Java tutorial
/* * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ /* * MatrixPanel.java * Copyright (C) 2002-2012 University of Waikato, Hamilton, New Zealand * */ package weka.gui.visualize; import weka.core.Attribute; import weka.core.Environment; import weka.core.Instances; import weka.core.Settings; import weka.core.Utils; import weka.gui.ExtensionFileFilter; import weka.gui.WekaFileChooser; import javax.swing.BorderFactory; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JDialog; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JSlider; import javax.swing.JSplitPane; import javax.swing.JTextField; import javax.swing.SwingUtilities; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dialog.ModalityType; import java.awt.Dimension; import java.awt.Graphics; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Image; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ComponentAdapter; import java.awt.event.ComponentEvent; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; import java.util.ArrayList; import java.util.Random; /** * This panel displays a plot matrix of the user selected attributes of a given * data set. * * The datapoints are coloured using a discrete colouring set if the user has * selected a nominal attribute for colouring. If the user has selected a * numeric attribute then the datapoints are coloured using a colour spectrum * ranging from blue to red (low values to high). Datapoints missing a class * value are displayed in black. * * @author Ashraf M. Kibriya (amk14@cs.waikato.ac.nz) * @version $Revision$ */ public class MatrixPanel extends JPanel { /** for serialization */ private static final long serialVersionUID = -1232642719869188740L; /** The that panel contains the actual matrix */ private final Plot m_plotsPanel; /** The panel that displays the legend of the colouring attribute */ protected final ClassPanel m_cp = new ClassPanel(); /** * The panel that contains all the buttons and tools, i.e. resize, jitter bars * and sub-sampling buttons etc on the bottom of the panel */ protected JPanel optionsPanel; /** Split pane for splitting the matrix and the buttons and bars */ protected JSplitPane jp; /** * The button that updates the display to reflect the changes made by the * user. E.g. changed attribute set for the matrix */ protected JButton m_updateBt = new JButton("Update"); /** The button to display a window to select attributes */ protected JButton m_selAttrib = new JButton("Select Attributes"); /** The dataset for which this panel will display the plot matrix for */ protected Instances m_data = null; /** The list for selecting the attributes to display the plot matrix */ protected JList m_attribList = new JList(); /** The scroll pane to scrolling the matrix */ protected final JScrollPane m_js = new JScrollPane(); /** The combo box to allow user to select the colouring attribute */ protected JComboBox m_classAttrib = new JComboBox(); /** The slider to adjust the size of the cells in the matrix */ protected JSlider m_plotSize = new JSlider(50, 200, 100); /** The slider to adjust the size of the datapoints */ protected JSlider m_pointSize = new JSlider(1, 10, 1); /** The slider to add jitter to the plots */ protected JSlider m_jitter = new JSlider(0, 20, 0); /** For adding random jitter */ private final Random rnd = new Random(); /** Array containing precalculated jitter values */ private int jitterVals[][]; /** This stores the size of the datapoint */ private int datapointSize = 1; /** The text area for percentage to resample data */ protected JTextField m_resamplePercent = new JTextField(5); /** The label for resample percentage */ protected JButton m_resampleBt = new JButton("SubSample % :"); /** Random seed for random subsample */ protected JTextField m_rseed = new JTextField(5); /** Displays the current size beside the slider bar for cell size */ private final JLabel m_plotSizeLb = new JLabel("PlotSize: [100]"); /** Displays the current size beside the slider bar for point size */ private final JLabel m_pointSizeLb = new JLabel("PointSize: [10]"); /** This array contains the indices of the attributes currently selected */ private int[] m_selectedAttribs; /** This contains the index of the currently selected colouring attribute */ private int m_classIndex; /** * This is a local array cache for all the instance values for faster * rendering */ private int[][] m_points; /** * This is an array cache for the colour of each of the instances depending on * the colouring attribute. If the colouring attribute is nominal then it * contains the index of the colour in our colour list. Otherwise, for numeric * colouring attribute, it contains the precalculated red component for each * instance's colour */ private int[] m_pointColors; /** * Contains true for each attribute value (only the selected attributes+class * attribute) that is missing, for each instance. m_missing[i][j] == true if * m_selectedAttribs[j] is missing in instance i. * m_missing[i][m_missing[].length-1] == true if class value is missing in * instance i. */ private boolean[][] m_missing; /** * This array contains for the classAttribute: <br> * m_type[0] = [type of attribute, nominal, string or numeric]<br> * m_type[1] = [number of discrete values of nominal or string attribute <br> * or same as m_type[0] for numeric attribute] */ private int[] m_type; /** Stores the maximum size for PlotSize label to keep it's size constant */ private final Dimension m_plotLBSizeD; /** Stores the maximum size for PointSize label to keep it's size constant */ private final Dimension m_pointLBSizeD; /** Contains discrete colours for colouring for nominal attributes */ private final ArrayList<Color> m_colorList = new ArrayList<Color>(); /** default colour list */ private static final Color[] m_defaultColors = { Color.blue, Color.red, Color.cyan, new Color(75, 123, 130), Color.pink, Color.green, Color.orange, new Color(255, 0, 255), new Color(255, 0, 0), new Color(0, 255, 0), Color.black }; /** color for the font used in column and row names */ private final Color fontColor = new Color(98, 101, 156); /** font used in column and row names */ private final java.awt.Font f = new java.awt.Font("Dialog", java.awt.Font.BOLD, 11); /** Settings (if available) to pass through to the VisualizePanels */ protected Settings m_settings; /** For the background of the little plots */ protected Color m_backgroundColor = Color.white; /** * ID of the owner (perspective, panel etc.) under which to lookup our * settings */ protected String m_settingsOwnerID; protected transient Image m_osi = null; protected boolean[][] m_plottedCells; protected boolean m_regenerateOSI = true; protected boolean m_clearOSIPlottedCells; protected double m_previousPercent = -1; protected JCheckBox m_fastScroll = new JCheckBox("Fast scrolling (uses more memory)"); /** * Constructor */ public MatrixPanel() { m_rseed.setText("1"); /** Setting up GUI **/ m_selAttrib.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent ae) { final JDialog jd = new JDialog((JFrame) MatrixPanel.this.getTopLevelAncestor(), "Attribute Selection Panel", ModalityType.DOCUMENT_MODAL); JPanel jp = new JPanel(); JScrollPane js = new JScrollPane(m_attribList); JButton okBt = new JButton("OK"); JButton cancelBt = new JButton("Cancel"); final int[] savedSelection = m_attribList.getSelectedIndices(); okBt.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { jd.dispose(); } }); cancelBt.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { m_attribList.setSelectedIndices(savedSelection); jd.dispose(); } }); jd.addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { m_attribList.setSelectedIndices(savedSelection); jd.dispose(); } }); jp.add(okBt); jp.add(cancelBt); jd.getContentPane().add(js, BorderLayout.CENTER); jd.getContentPane().add(jp, BorderLayout.SOUTH); if (js.getPreferredSize().width < 200) { jd.setSize(250, 250); } else { jd.setSize(js.getPreferredSize().width + 10, 250); } jd.setLocation(m_selAttrib.getLocationOnScreen().x, m_selAttrib.getLocationOnScreen().y - jd.getHeight()); jd.setVisible(true); } }); m_updateBt.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { updatePanel(); } }); m_updateBt.setPreferredSize(m_selAttrib.getPreferredSize()); m_jitter.addChangeListener(new ChangeListener() { @Override public void stateChanged(ChangeEvent ce) { if (m_fastScroll.isSelected()) { m_clearOSIPlottedCells = true; } } }); m_plotSize.addChangeListener(new ChangeListener() { @Override public void stateChanged(ChangeEvent ce) { m_plotSizeLb.setText("PlotSize: [" + m_plotSize.getValue() + "]"); m_plotSizeLb.setPreferredSize(m_plotLBSizeD); m_jitter.setMaximum(m_plotSize.getValue() / 5); // 20% of cell Size m_regenerateOSI = true; } }); m_pointSize.addChangeListener(new ChangeListener() { @Override public void stateChanged(ChangeEvent ce) { m_pointSizeLb.setText("PointSize: [" + m_pointSize.getValue() + "]"); m_pointSizeLb.setPreferredSize(m_pointLBSizeD); datapointSize = m_pointSize.getValue(); if (m_fastScroll.isSelected()) { m_clearOSIPlottedCells = true; } } }); m_resampleBt.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { JLabel rseedLb = new JLabel("Random Seed: "); JTextField rseedTxt = m_rseed; JLabel percentLb = new JLabel("Subsample as"); JLabel percent2Lb = new JLabel("% of input: "); final JTextField percentTxt = new JTextField(5); percentTxt.setText(m_resamplePercent.getText()); JButton doneBt = new JButton("Done"); final JDialog jd = new JDialog((JFrame) MatrixPanel.this.getTopLevelAncestor(), "Subsample % Panel", ModalityType.DOCUMENT_MODAL) { private static final long serialVersionUID = -269823533147146296L; @Override public void dispose() { m_resamplePercent.setText(percentTxt.getText()); super.dispose(); } }; jd.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); doneBt.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent ae) { jd.dispose(); } }); GridBagLayout gbl = new GridBagLayout(); GridBagConstraints gbc = new GridBagConstraints(); JPanel p1 = new JPanel(gbl); gbc.anchor = GridBagConstraints.WEST; gbc.fill = GridBagConstraints.HORIZONTAL; gbc.insets = new Insets(0, 2, 2, 2); gbc.gridwidth = GridBagConstraints.RELATIVE; p1.add(rseedLb, gbc); gbc.weightx = 0; gbc.gridwidth = GridBagConstraints.REMAINDER; gbc.weightx = 1; p1.add(rseedTxt, gbc); gbc.insets = new Insets(8, 2, 0, 2); gbc.weightx = 0; p1.add(percentLb, gbc); gbc.insets = new Insets(0, 2, 2, 2); gbc.gridwidth = GridBagConstraints.RELATIVE; p1.add(percent2Lb, gbc); gbc.gridwidth = GridBagConstraints.REMAINDER; gbc.weightx = 1; p1.add(percentTxt, gbc); gbc.insets = new Insets(8, 2, 2, 2); JPanel p3 = new JPanel(gbl); gbc.fill = GridBagConstraints.HORIZONTAL; gbc.gridwidth = GridBagConstraints.REMAINDER; gbc.weightx = 1; gbc.weighty = 0; p3.add(p1, gbc); gbc.insets = new Insets(8, 4, 8, 4); p3.add(doneBt, gbc); jd.getContentPane().setLayout(new BorderLayout()); jd.getContentPane().add(p3, BorderLayout.NORTH); jd.pack(); jd.setLocation(m_resampleBt.getLocationOnScreen().x, m_resampleBt.getLocationOnScreen().y - jd.getHeight()); jd.setVisible(true); } }); optionsPanel = new JPanel(new GridBagLayout()); // all the rest of the // panels are in here. final JPanel p2 = new JPanel(new BorderLayout()); // this has class colour // panel final JPanel p3 = new JPanel(new GridBagLayout()); // this has update and // select buttons final JPanel p4 = new JPanel(new GridBagLayout()); // this has the slider // bars and combobox GridBagConstraints gbc = new GridBagConstraints(); m_plotLBSizeD = m_plotSizeLb.getPreferredSize(); m_pointLBSizeD = m_pointSizeLb.getPreferredSize(); m_pointSizeLb.setText("PointSize: [1]"); m_pointSizeLb.setPreferredSize(m_pointLBSizeD); m_resampleBt.setPreferredSize(m_selAttrib.getPreferredSize()); gbc.fill = GridBagConstraints.HORIZONTAL; gbc.anchor = GridBagConstraints.NORTHWEST; gbc.insets = new Insets(2, 2, 2, 2); p4.add(m_plotSizeLb, gbc); gbc.weightx = 1; gbc.gridwidth = GridBagConstraints.REMAINDER; p4.add(m_plotSize, gbc); gbc.weightx = 0; gbc.gridwidth = GridBagConstraints.RELATIVE; p4.add(m_pointSizeLb, gbc); gbc.weightx = 1; gbc.gridwidth = GridBagConstraints.REMAINDER; p4.add(m_pointSize, gbc); gbc.weightx = 0; gbc.gridwidth = GridBagConstraints.RELATIVE; p4.add(new JLabel("Jitter: "), gbc); gbc.weightx = 1; gbc.gridwidth = GridBagConstraints.REMAINDER; p4.add(m_jitter, gbc); p4.add(m_classAttrib, gbc); gbc.gridwidth = GridBagConstraints.REMAINDER; gbc.weightx = 1; gbc.fill = GridBagConstraints.NONE; p3.add(m_fastScroll, gbc); p3.add(m_updateBt, gbc); p3.add(m_selAttrib, gbc); gbc.gridwidth = GridBagConstraints.RELATIVE; gbc.weightx = 0; gbc.fill = GridBagConstraints.VERTICAL; gbc.anchor = GridBagConstraints.WEST; p3.add(m_resampleBt, gbc); gbc.gridwidth = GridBagConstraints.REMAINDER; p3.add(m_resamplePercent, gbc); p2.setBorder(BorderFactory.createTitledBorder("Class Colour")); p2.add(m_cp, BorderLayout.SOUTH); gbc.insets = new Insets(8, 5, 2, 5); gbc.anchor = GridBagConstraints.SOUTHWEST; gbc.fill = GridBagConstraints.HORIZONTAL; gbc.weightx = 1; gbc.gridwidth = GridBagConstraints.RELATIVE; optionsPanel.add(p4, gbc); gbc.gridwidth = GridBagConstraints.REMAINDER; optionsPanel.add(p3, gbc); optionsPanel.add(p2, gbc); m_fastScroll.setSelected(false); m_fastScroll.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { if (!m_fastScroll.isSelected()) { m_osi = null; } else { m_plottedCells = new boolean[m_selectedAttribs.length][m_selectedAttribs.length]; } MatrixPanel.this.invalidate(); MatrixPanel.this.repaint(); } }); this.addComponentListener(new ComponentAdapter() { @Override public void componentResized(ComponentEvent cv) { m_js.setMinimumSize(new Dimension(MatrixPanel.this.getWidth(), MatrixPanel.this.getHeight() - optionsPanel.getPreferredSize().height - 10)); jp.setDividerLocation(MatrixPanel.this.getHeight() - optionsPanel.getPreferredSize().height - 10); } }); optionsPanel.setMinimumSize(new Dimension(0, 0)); jp = new JSplitPane(JSplitPane.VERTICAL_SPLIT, m_js, optionsPanel); jp.setOneTouchExpandable(true); jp.setResizeWeight(1); this.setLayout(new BorderLayout()); this.add(jp, BorderLayout.CENTER); /** Setting up the initial color list **/ for (int i = 0; i < m_defaultColors.length; i++) { m_colorList.add(m_defaultColors[i]); } /** Initializing internal fields and components **/ m_selectedAttribs = m_attribList.getSelectedIndices(); m_plotsPanel = new Plot(); m_plotsPanel.setLayout(null); m_js.getHorizontalScrollBar().setUnitIncrement(10); m_js.getVerticalScrollBar().setUnitIncrement(10); m_js.setViewportView(m_plotsPanel); m_js.setColumnHeaderView(m_plotsPanel.getColHeader()); m_js.setRowHeaderView(m_plotsPanel.getRowHeader()); final JLabel lb = new JLabel(" Plot Matrix"); lb.setFont(f); lb.setForeground(fontColor); lb.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); m_js.setCorner(JScrollPane.UPPER_LEFT_CORNER, lb); m_cp.setInstances(m_data); m_cp.setBorder(BorderFactory.createEmptyBorder(15, 10, 10, 10)); m_cp.addRepaintNotify(m_plotsPanel); // m_updateBt.doClick(); //not until setting up the instances } /** * Initializes internal data fields, i.e. data values, type, missing and color * cache arrays */ public void initInternalFields() { Instances inst = m_data; m_classIndex = m_classAttrib.getSelectedIndex(); m_selectedAttribs = m_attribList.getSelectedIndices(); double minC = 0, maxC = 0; /** Resampling **/ double currentPercent = Double.parseDouble(m_resamplePercent.getText()); if (currentPercent <= 100) { if (currentPercent != m_previousPercent) { m_clearOSIPlottedCells = true; } inst = new Instances(m_data, 0, m_data.numInstances()); inst.randomize(new Random(Integer.parseInt(m_rseed.getText()))); // System.err.println("gettingPercent: " + // Math.round( // Double.parseDouble(m_resamplePercent.getText()) // / 100D * m_data.numInstances() // ) // ); inst = new Instances(inst, 0, (int) Math.round(currentPercent / 100D * inst.numInstances())); m_previousPercent = currentPercent; } m_points = new int[inst.numInstances()][m_selectedAttribs.length]; // changed m_pointColors = new int[inst.numInstances()]; m_missing = new boolean[inst.numInstances()][m_selectedAttribs.length + 1]; // changed m_type = new int[2]; // [m_selectedAttribs.length]; //changed jitterVals = new int[inst.numInstances()][2]; /** * Setting up the color list for non-numeric attribute as well as jittervals **/ if (!(inst.attribute(m_classIndex).isNumeric())) { for (int i = m_colorList.size(); i < inst.attribute(m_classIndex).numValues() + 1; i++) { Color pc = m_defaultColors[i % 10]; int ija = i / 10; ija *= 2; for (int j = 0; j < ija; j++) { pc = pc.darker(); } m_colorList.add(pc); } for (int i = 0; i < inst.numInstances(); i++) { // set to black for missing class value which is last colour is default // list if (inst.instance(i).isMissing(m_classIndex)) { m_pointColors[i] = m_defaultColors.length - 1; } else { m_pointColors[i] = (int) inst.instance(i).value(m_classIndex); } jitterVals[i][0] = rnd.nextInt(m_jitter.getValue() + 1) - m_jitter.getValue() / 2; jitterVals[i][1] = rnd.nextInt(m_jitter.getValue() + 1) - m_jitter.getValue() / 2; } } /** Setting up color variations for numeric attribute as well as jittervals **/ else { for (int i = 0; i < inst.numInstances(); i++) { if (!(inst.instance(i).isMissing(m_classIndex))) { minC = maxC = inst.instance(i).value(m_classIndex); break; } } for (int i = 1; i < inst.numInstances(); i++) { if (!(inst.instance(i).isMissing(m_classIndex))) { if (minC > inst.instance(i).value(m_classIndex)) { minC = inst.instance(i).value(m_classIndex); } if (maxC < inst.instance(i).value(m_classIndex)) { maxC = inst.instance(i).value(m_classIndex); } } } for (int i = 0; i < inst.numInstances(); i++) { double r = (inst.instance(i).value(m_classIndex) - minC) / (maxC - minC); r = (r * 240) + 15; m_pointColors[i] = (int) r; jitterVals[i][0] = rnd.nextInt(m_jitter.getValue() + 1) - m_jitter.getValue() / 2; jitterVals[i][1] = rnd.nextInt(m_jitter.getValue() + 1) - m_jitter.getValue() / 2; } } /** Creating local cache of the data values **/ double min[] = new double[m_selectedAttribs.length], max = 0; // changed double ratio[] = new double[m_selectedAttribs.length]; // changed double cellSize = m_plotSize.getValue(), temp1 = 0, temp2 = 0; for (int j = 0; j < m_selectedAttribs.length; j++) { int i; for (i = 0; i < inst.numInstances(); i++) { min[j] = max = 0; if (!(inst.instance(i).isMissing(m_selectedAttribs[j]))) { min[j] = max = inst.instance(i).value(m_selectedAttribs[j]); break; } } for (; i < inst.numInstances(); i++) { if (!(inst.instance(i).isMissing(m_selectedAttribs[j]))) { if (inst.instance(i).value(m_selectedAttribs[j]) < min[j]) { min[j] = inst.instance(i).value(m_selectedAttribs[j]); } if (inst.instance(i).value(m_selectedAttribs[j]) > max) { max = inst.instance(i).value(m_selectedAttribs[j]); } } } ratio[j] = cellSize / (max - min[j]); } boolean classIndexProcessed = false; for (int j = 0; j < m_selectedAttribs.length; j++) { if (inst.attribute(m_selectedAttribs[j]).isNominal() || inst.attribute(m_selectedAttribs[j]).isString()) { // m_type[0][j] = 1; m_type[1][j] = // inst.attribute(m_selectedAttribs[j]).numValues(); temp1 = cellSize / inst.attribute(m_selectedAttribs[j]).numValues(); // m_type[1][j]; temp2 = temp1 / 2; for (int i = 0; i < inst.numInstances(); i++) { m_points[i][j] = (int) Math.round(temp2 + temp1 * inst.instance(i).value(m_selectedAttribs[j])); if (inst.instance(i).isMissing(m_selectedAttribs[j])) { m_missing[i][j] = true; // represents missing value if (m_selectedAttribs[j] == m_classIndex) { m_missing[i][m_missing[0].length - 1] = true; classIndexProcessed = true; } } } } else { // m_type[0][j] = m_type[1][j] = 0; for (int i = 0; i < inst.numInstances(); i++) { m_points[i][j] = (int) Math .round((inst.instance(i).value(m_selectedAttribs[j]) - min[j]) * ratio[j]); if (inst.instance(i).isMissing(m_selectedAttribs[j])) { m_missing[i][j] = true; // represents missing value if (m_selectedAttribs[j] == m_classIndex) { m_missing[i][m_missing[0].length - 1] = true; classIndexProcessed = true; } } } } } if (inst.attribute(m_classIndex).isNominal() || inst.attribute(m_classIndex).isString()) { m_type[0] = 1; m_type[1] = inst.attribute(m_classIndex).numValues(); } else { m_type[0] = m_type[1] = 0; } if (classIndexProcessed == false) { // class Index has not been processed as // class index is not among the selected // attribs for (int i = 0; i < inst.numInstances(); i++) { if (inst.instance(i).isMissing(m_classIndex)) { m_missing[i][m_missing[0].length - 1] = true; } } } m_cp.setColours(m_colorList); } /** * Sets up the UI's attributes lists */ public void setupAttribLists() { String[] tempAttribNames = new String[m_data.numAttributes()]; String type; m_classAttrib.removeAllItems(); for (int i = 0; i < tempAttribNames.length; i++) { type = " (" + Attribute.typeToStringShort(m_data.attribute(i)) + ")"; tempAttribNames[i] = new String("Colour: " + m_data.attribute(i).name() + " " + type); m_classAttrib.addItem(tempAttribNames[i]); } if (m_data.classIndex() == -1) { m_classAttrib.setSelectedIndex(tempAttribNames.length - 1); } else { m_classAttrib.setSelectedIndex(m_data.classIndex()); } m_attribList.setListData(tempAttribNames); m_attribList.setSelectionInterval(0, tempAttribNames.length - 1); } /** * Calculates the percentage to resample */ public void setPercent() { if (m_data.numInstances() > 700) { double percnt = 500D / m_data.numInstances() * 100; percnt *= 100; percnt = Math.round(percnt); percnt /= 100; m_resamplePercent.setText("" + percnt); } else { m_resamplePercent.setText("100"); } } /** * This method changes the Instances object of this class to a new one. It * also does all the necessary initializations for displaying the panel. This * must be called before trying to display the panel. * * @param newInst The new set of Instances */ public void setInstances(Instances newInst) { m_osi = null; m_fastScroll.setSelected(false); m_data = newInst; setPercent(); setupAttribLists(); m_rseed.setText("1"); initInternalFields(); m_cp.setInstances(m_data); m_cp.setCindex(m_classIndex); m_updateBt.doClick(); } /** * Main method for testing this class */ public static void main(String[] args) { final JFrame jf = new JFrame("Weka Explorer: MatrixPanel"); final JButton setBt = new JButton("Set Instances"); Instances data = null; try { if (args.length == 1) { data = new Instances(new BufferedReader(new FileReader(args[0]))); } else { System.out.println("Usage: MatrixPanel <arff file>"); System.exit(-1); } } catch (IOException ex) { ex.printStackTrace(); System.exit(-1); } final MatrixPanel mp = new MatrixPanel(); mp.setInstances(data); setBt.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { WekaFileChooser chooser = new WekaFileChooser(new java.io.File(System.getProperty("user.dir"))); ExtensionFileFilter myfilter = new ExtensionFileFilter("arff", "Arff data files"); chooser.setFileFilter(myfilter); int returnVal = chooser.showOpenDialog(jf); if (returnVal == JFileChooser.APPROVE_OPTION) { try { System.out.println("You chose to open this file: " + chooser.getSelectedFile().getName()); Instances in = new Instances(new FileReader(chooser.getSelectedFile().getAbsolutePath())); mp.setInstances(in); } catch (Exception ex) { ex.printStackTrace(); } } } }); // System.out.println("Loaded: "+args[0]+"\nRelation: "+data.relationName()+"\nAttributes: "+data.numAttributes()); // System.out.println("The attributes are: "); // for(int i=0; i<data.numAttributes(); i++) // System.out.println(data.attribute(i).name()); // RepaintManager.currentManager(jf.getRootPane()).setDoubleBufferingEnabled(false); jf.getContentPane().setLayout(new BorderLayout()); jf.getContentPane().add(mp, BorderLayout.CENTER); jf.getContentPane().add(setBt, BorderLayout.SOUTH); jf.getContentPane().setFont(new java.awt.Font("SansSerif", java.awt.Font.PLAIN, 11)); jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); jf.setSize(800, 600); jf.setVisible(true); jf.repaint(); } /** * Internal class responsible for displaying the actual matrix Requires the * internal data fields of the parent class to be properly initialized before * being created */ private class Plot extends JPanel implements MouseMotionListener, MouseListener { /** for serialization */ private static final long serialVersionUID = -1721245738439420882L; int extpad = 3, intpad = 4, cellSize = 100, cellRange = 100; java.awt.Rectangle r; java.awt.FontMetrics fm; int lastxpos, lastypos; JPanel jPlColHeader, jPlRowHeader; /** * Constructor */ public Plot() { super(); this.setToolTipText("blah"); this.addMouseMotionListener(this); this.addMouseListener(this); initialize(); } /** Initializes the internal fields */ public void initialize() { lastxpos = lastypos = 0; cellRange = cellSize; cellSize = cellRange + 2 * intpad; jPlColHeader = new JPanel() { private static final long serialVersionUID = -9098547751937467506L; java.awt.Rectangle r; @Override public void paint(Graphics g) { r = g.getClipBounds(); g.setColor(this.getBackground()); g.fillRect(r.x, r.y, r.width, r.height); g.setFont(f); fm = g.getFontMetrics(); int xpos = 0, ypos = 0, attribWidth = 0; g.setColor(fontColor); xpos = extpad; ypos = extpad + fm.getHeight(); for (int m_selectedAttrib : m_selectedAttribs) { if (xpos + cellSize < r.x) { xpos += cellSize + extpad; continue; } else if (xpos > r.x + r.width) { break; } else { attribWidth = fm.stringWidth(m_data.attribute(m_selectedAttrib).name()); g.drawString(m_data.attribute(m_selectedAttrib).name(), (attribWidth < cellSize) ? (xpos + (cellSize / 2 - attribWidth / 2)) : xpos, ypos); } xpos += cellSize + extpad; } fm = null; r = null; } @Override public Dimension getPreferredSize() { fm = this.getFontMetrics(this.getFont()); return new Dimension(m_selectedAttribs.length * (cellSize + extpad), 2 * extpad + fm.getHeight()); } }; jPlRowHeader = new JPanel() { private static final long serialVersionUID = 8474957069309552844L; java.awt.Rectangle r; @Override public void paint(Graphics g) { r = g.getClipBounds(); g.setColor(this.getBackground()); g.fillRect(r.x, r.y, r.width, r.height); g.setFont(f); fm = g.getFontMetrics(); int xpos = 0, ypos = 0; g.setColor(fontColor); xpos = extpad; ypos = extpad; for (int j = m_selectedAttribs.length - 1; j >= 0; j--) { if (ypos + cellSize < r.y) { ypos += cellSize + extpad; continue; } else if (ypos > r.y + r.height) { break; } else { g.drawString(m_data.attribute(m_selectedAttribs[j]).name(), xpos + extpad, ypos + cellSize / 2); } xpos = extpad; ypos += cellSize + extpad; } r = null; } @Override public Dimension getPreferredSize() { return new Dimension(100 + extpad, m_selectedAttribs.length * (cellSize + extpad)); } }; jPlColHeader.setFont(f); jPlRowHeader.setFont(f); this.setFont(f); } public JPanel getRowHeader() { return jPlRowHeader; } public JPanel getColHeader() { return jPlColHeader; } @Override public void mouseMoved(MouseEvent e) { Graphics g = this.getGraphics(); int xpos = extpad, ypos = extpad; for (int j = m_selectedAttribs.length - 1; j >= 0; j--) { for (@SuppressWarnings("unused") int m_selectedAttrib : m_selectedAttribs) { if (e.getX() >= xpos && e.getX() <= xpos + cellSize + extpad) { if (e.getY() >= ypos && e.getY() <= ypos + cellSize + extpad) { if (xpos != lastxpos || ypos != lastypos) { g.setColor(Color.red); g.drawRect(xpos - 1, ypos - 1, cellSize + 1, cellSize + 1); if (lastxpos != 0 && lastypos != 0) { g.setColor(this.getBackground().darker()); g.drawRect(lastxpos - 1, lastypos - 1, cellSize + 1, cellSize + 1); } lastxpos = xpos; lastypos = ypos; } return; } } xpos += cellSize + extpad; } xpos = extpad; ypos += cellSize + extpad; } if (lastxpos != 0 && lastypos != 0) { g.setColor(this.getBackground().darker()); g.drawRect(lastxpos - 1, lastypos - 1, cellSize + 1, cellSize + 1); } lastxpos = lastypos = 0; } @Override public void mouseDragged(MouseEvent e) { } @Override public void mouseClicked(MouseEvent e) { int i = 0, j = 0, found = 0; int xpos = extpad, ypos = extpad; for (j = m_selectedAttribs.length - 1; j >= 0; j--) { for (i = 0; i < m_selectedAttribs.length; i++) { if (e.getX() >= xpos && e.getX() <= xpos + cellSize + extpad) { if (e.getY() >= ypos && e.getY() <= ypos + cellSize + extpad) { found = 1; break; } } xpos += cellSize + extpad; } if (found == 1) { break; } xpos = extpad; ypos += cellSize + extpad; } if (found == 0) { return; } JFrame jf = Utils.getWekaJFrame("Weka Explorer: Visualizing " + m_data.relationName(), this); VisualizePanel vp = new VisualizePanel(); try { PlotData2D pd = new PlotData2D(m_data); pd.setPlotName("Master Plot"); vp.setMasterPlot(pd); // System.out.println("x: "+i+" y: "+j); vp.setXIndex(m_selectedAttribs[i]); vp.setYIndex(m_selectedAttribs[j]); vp.m_ColourCombo.setSelectedIndex(m_classIndex); if (m_settings != null) { vp.applySettings(m_settings, m_settingsOwnerID); } } catch (Exception ex) { ex.printStackTrace(); } jf.getContentPane().add(vp); jf.addWindowListener(new java.awt.event.WindowAdapter() { @Override public void windowClosing(java.awt.event.WindowEvent e) { jf.dispose(); } }); jf.pack(); jf.setSize(800, 600); jf.setLocationRelativeTo(SwingUtilities.getWindowAncestor(this)); jf.setVisible(true); } @Override public void mouseEntered(MouseEvent e) { } @Override public void mouseExited(MouseEvent e) { } @Override public void mousePressed(MouseEvent e) { } @Override public void mouseReleased(MouseEvent e) { } /** * sets the new jitter value for the plots */ public void setJitter(int newjitter) { } /** * sets the new size for the plots */ public void setCellSize(int newCellSize) { cellSize = newCellSize; initialize(); } /** * Returns the X and Y attributes of the plot the mouse is currently on */ @Override public String getToolTipText(MouseEvent event) { int xpos = extpad, ypos = extpad; for (int j = m_selectedAttribs.length - 1; j >= 0; j--) { for (int m_selectedAttrib : m_selectedAttribs) { if (event.getX() >= xpos && event.getX() <= xpos + cellSize + extpad) { if (event.getY() >= ypos && event.getY() <= ypos + cellSize + extpad) { return ("X: " + m_data.attribute(m_selectedAttrib).name() + " Y: " + m_data.attribute(m_selectedAttribs[j]).name() + " (click to enlarge)"); } } xpos += cellSize + extpad; } xpos = extpad; ypos += cellSize + extpad; } return ("Matrix Panel"); } /** * Paints a single Plot at xpos, ypos. and xattrib and yattrib on X and Y * axes */ public void paintGraph(Graphics g, int xattrib, int yattrib, int xpos, int ypos) { int x, y; g.setColor(m_backgroundColor.equals(Color.BLACK) ? m_backgroundColor.brighter().brighter() : m_backgroundColor.darker().darker()); g.drawRect(xpos - 1, ypos - 1, cellSize + 1, cellSize + 1); g.setColor(m_backgroundColor); g.fillRect(xpos, ypos, cellSize, cellSize); for (int i = 0; i < m_points.length; i++) { if (!(m_missing[i][yattrib] || m_missing[i][xattrib])) { if (m_type[0] == 0) { if (m_missing[i][m_missing[0].length - 1]) { g.setColor(m_defaultColors[m_defaultColors.length - 1]); } else { g.setColor(new Color(m_pointColors[i], 150, (255 - m_pointColors[i]))); } } else { g.setColor(m_colorList.get(m_pointColors[i])); } if (m_points[i][xattrib] + jitterVals[i][0] < 0 || m_points[i][xattrib] + jitterVals[i][0] > cellRange) { if (cellRange - m_points[i][yattrib] + jitterVals[i][1] < 0 || cellRange - m_points[i][yattrib] + jitterVals[i][1] > cellRange) { // both x and y out of range don't add jitter x = intpad + m_points[i][xattrib]; y = intpad + (cellRange - m_points[i][yattrib]); } else { // only x out of range x = intpad + m_points[i][xattrib]; y = intpad + (cellRange - m_points[i][yattrib]) + jitterVals[i][1]; } } else if (cellRange - m_points[i][yattrib] + jitterVals[i][1] < 0 || cellRange - m_points[i][yattrib] + jitterVals[i][1] > cellRange) { // only y out of range x = intpad + m_points[i][xattrib] + jitterVals[i][0]; y = intpad + (cellRange - m_points[i][yattrib]); } else { // none out of range x = intpad + m_points[i][xattrib] + jitterVals[i][0]; y = intpad + (cellRange - m_points[i][yattrib]) + jitterVals[i][1]; } if (datapointSize == 1) { g.drawLine(x + xpos, y + ypos, x + xpos, y + ypos); } else { g.drawOval(x + xpos - datapointSize / 2, y + ypos - datapointSize / 2, datapointSize, datapointSize); } } } g.setColor(fontColor); } private void createOSI() { int iwidth = this.getWidth(); int iheight = this.getHeight(); m_osi = this.createImage(iwidth, iheight); clearOSI(); } private void clearOSI() { if (m_osi == null) { return; } int iwidth = this.getWidth(); int iheight = this.getHeight(); Graphics m = m_osi.getGraphics(); m.setColor(this.getBackground().darker().darker()); m.fillRect(0, 0, iwidth, iheight); } /** * Paints the matrix of plots in the current visible region */ public void paintME(Graphics g) { Graphics g2 = g; if (m_osi == null && m_fastScroll.isSelected()) { createOSI(); } if (m_osi != null && m_fastScroll.isSelected()) { g2 = m_osi.getGraphics(); } r = g.getClipBounds(); g.setColor(this.getBackground()); g.fillRect(r.x, r.y, r.width, r.height); g.setColor(fontColor); int xpos = 0, ypos = 0; xpos = extpad; ypos = extpad; for (int j = m_selectedAttribs.length - 1; j >= 0; j--) { if (ypos + cellSize < r.y) { ypos += cellSize + extpad; continue; } else if (ypos > r.y + r.height) { break; } else { for (int i = 0; i < m_selectedAttribs.length; i++) { if (xpos + cellSize < r.x) { xpos += cellSize + extpad; continue; } else if (xpos > r.x + r.width) { break; } else if (m_fastScroll.isSelected()) { if (!m_plottedCells[i][j]) { paintGraph(g2, i, j, xpos, ypos); // m_selectedAttribs[i], // m_selectedAttribs[j], xpos, // ypos); m_plottedCells[i][j] = true; } } else { paintGraph(g2, i, j, xpos, ypos); } xpos += cellSize + extpad; } } xpos = extpad; ypos += cellSize + extpad; } } /** * paints this JPanel (PlotsPanel) */ @Override public void paintComponent(Graphics g) { paintME(g); if (m_osi != null && m_fastScroll.isSelected()) { g.drawImage(m_osi, 0, 0, this); } } } /** * Set the point size for the plots * * @param pointSize the point size to use */ public void setPointSize(int pointSize) { if (pointSize <= m_pointSize.getMaximum() && pointSize > m_pointSize.getMinimum()) { m_pointSize.setValue(pointSize); } } /** * Set the plot size * * @param plotSize the plot size to use */ public void setPlotSize(int plotSize) { if (plotSize >= m_plotSize.getMinimum() && plotSize <= m_plotSize.getMaximum()) { m_plotSize.setValue(plotSize); } } /** * Set the background colour for the cells in the matrix * * @param c the background colour */ public void setPlotBackgroundColour(Color c) { m_backgroundColor = c; } /** * @param settings * @param ownerID */ public void applySettings(Settings settings, String ownerID) { m_settings = settings; m_settingsOwnerID = ownerID; setPointSize(settings.getSetting(ownerID, weka.gui.explorer.VisualizePanel.ScatterDefaults.POINT_SIZE_KEY, weka.gui.explorer.VisualizePanel.ScatterDefaults.POINT_SIZE, Environment.getSystemWide())); setPlotSize(settings.getSetting(ownerID, weka.gui.explorer.VisualizePanel.ScatterDefaults.PLOT_SIZE_KEY, weka.gui.explorer.VisualizePanel.ScatterDefaults.PLOT_SIZE, Environment.getSystemWide())); setPlotBackgroundColour(settings.getSetting(ownerID, VisualizeUtils.VisualizeDefaults.BACKGROUND_COLOUR_KEY, VisualizeUtils.VisualizeDefaults.BACKGROUND_COLOR, Environment.getSystemWide())); } /** * Update the display. Typically called after changing plot size, point size * etc. */ public void updatePanel() { // m_selectedAttribs = m_attribList.getSelectedIndices(); initInternalFields(); Plot a = m_plotsPanel; a.setCellSize(m_plotSize.getValue()); Dimension d = new Dimension((m_selectedAttribs.length) * (a.cellSize + a.extpad) + 2, (m_selectedAttribs.length) * (a.cellSize + a.extpad) + 2); // System.out.println("Size: "+a.cellSize+" Extpad: "+ // a.extpad+" selected: "+ // m_selectedAttribs.length+' '+d); a.setPreferredSize(d); a.setSize(a.getPreferredSize()); a.setJitter(m_jitter.getValue()); if (m_fastScroll.isSelected() && m_clearOSIPlottedCells) { m_plottedCells = new boolean[m_selectedAttribs.length][m_selectedAttribs.length]; m_clearOSIPlottedCells = false; } if (m_regenerateOSI) { m_osi = null; } m_js.revalidate(); m_cp.setColours(m_colorList); m_cp.setCindex(m_classIndex); m_regenerateOSI = false; repaint(); } }