source: src/main/java/weka/gui/visualize/MatrixPanel.java @ 22

Last change on this file since 22 was 4, checked in by gnappo, 14 years ago

Import di weka.

File size: 36.2 KB
Line 
1/*
2 *    This program is free software; you can redistribute it and/or modify
3 *    it under the terms of the GNU General Public License as published by
4 *    the Free Software Foundation; either version 2 of the License, or
5 *    (at your option) any later version.
6 *
7 *    This program is distributed in the hope that it will be useful,
8 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
9 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10 *    GNU General Public License for more details.
11 *
12 *    You should have received a copy of the GNU General Public License
13 *    along with this program; if not, write to the Free Software
14 *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
15 */
16
17/*
18 *    MatrixPanel.java
19 *    Copyright (C) 2002 University of Waikato, Hamilton, New Zealand
20 *
21 */
22
23package weka.gui.visualize;
24
25import weka.core.Attribute;
26import weka.core.FastVector;
27import weka.core.Instances;
28import weka.gui.ExtensionFileFilter;
29
30import java.awt.BorderLayout;
31import java.awt.Color;
32import java.awt.Dimension;
33import java.awt.Graphics;
34import java.awt.GridBagConstraints;
35import java.awt.GridBagLayout;
36import java.awt.Insets;
37import java.awt.event.ActionEvent;
38import java.awt.event.ActionListener;
39import java.awt.event.ComponentAdapter;
40import java.awt.event.ComponentEvent;
41import java.awt.event.MouseEvent;
42import java.awt.event.MouseListener;
43import java.awt.event.MouseMotionListener;
44import java.awt.event.WindowAdapter;
45import java.awt.event.WindowEvent;
46import java.io.BufferedReader;
47import java.io.FileReader;
48import java.io.IOException;
49import java.util.Random;
50
51import javax.swing.BorderFactory;
52import javax.swing.JButton;
53import javax.swing.JComboBox;
54import javax.swing.JDialog;
55import javax.swing.JFileChooser;
56import javax.swing.JFrame;
57import javax.swing.JLabel;
58import javax.swing.JList;
59import javax.swing.JPanel;
60import javax.swing.JScrollPane;
61import javax.swing.JSlider;
62import javax.swing.JSplitPane;
63import javax.swing.JTextField;
64import javax.swing.event.ChangeEvent;
65import javax.swing.event.ChangeListener;
66
67/**
68 * This panel displays a plot matrix of the user selected attributes
69 * of a given data set.
70 *
71 * The datapoints are coloured using a discrete colouring set if the
72 * user has selected a nominal attribute for colouring. If the user
73 * has selected a numeric attribute then the datapoints are coloured
74 * using a colour spectrum ranging from blue to red (low values to
75 * high). Datapoints missing a class value are displayed in black.
76 *
77 * @author Ashraf M. Kibriya (amk14@cs.waikato.ac.nz)
78 * @version $Revision: 1.18 $
79 */
80public class MatrixPanel
81  extends JPanel{
82
83  /** for serialization */
84  private static final long serialVersionUID = -1232642719869188740L;
85
86  /** The that panel contains the actual matrix */
87  private final Plot m_plotsPanel;
88
89  /** The panel that displays the legend of the colouring attribute */
90  protected final ClassPanel m_cp = new ClassPanel();
91
92  /** The panel that contains all the buttons and tools, i.e. resize, jitter bars and sub-sampling buttons etc
93      on the bottom of the panel */
94  protected JPanel optionsPanel;
95
96  /** Split pane for splitting the matrix and the buttons and bars */
97  protected JSplitPane jp;
98  /** The button that updates the display to reflect the changes made by the user.
99      E.g. changed attribute set for the matrix    */
100  protected JButton m_updateBt = new JButton("Update");
101
102  /** The button to display a window to select attributes */
103  protected JButton m_selAttrib = new JButton("Select Attributes");
104
105  /** The dataset for which this panel will display the plot matrix for  */
106  protected Instances m_data=null;
107
108  /** The list for selecting the attributes to display the plot matrix */
109  protected JList m_attribList = new JList();
110
111  /** The scroll pane to scrolling the matrix */
112  protected final JScrollPane m_js = new JScrollPane();
113
114  /** The combo box to allow user to select the colouring attribute */
115  protected JComboBox m_classAttrib = new JComboBox();
116
117  /** The slider to adjust the size of the cells in the matrix  */ 
118  protected JSlider m_plotSize = new JSlider(50, 500, 100);
119
120  /** The slider to adjust the size of the datapoints  */ 
121  protected JSlider m_pointSize = new JSlider(1, 10, 1);
122
123  /** The slider to add jitter to the plots */ 
124  protected JSlider m_jitter = new JSlider(0, 20, 0); 
125
126  /** For adding random jitter */
127  private Random rnd = new Random();
128   
129  /** Array containing precalculated jitter values */
130  private int jitterVals[][];
131 
132  /** This stores the size of the datapoint */
133  private int datapointSize=1;
134
135  /** The text area for percentage to resample data */
136  protected JTextField m_resamplePercent = new JTextField(5);
137
138  /** The label for resample percentage */
139  protected JButton m_resampleBt =  new JButton("SubSample % :");
140
141  /** Random seed for random subsample */
142  protected JTextField m_rseed = new JTextField(5);
143 
144  /** Displays the current size beside the slider bar for cell size */
145  private final JLabel m_plotSizeLb = new JLabel("PlotSize: [100]");
146
147  /** Displays the current size beside the slider bar for point size */
148  private final JLabel m_pointSizeLb = new JLabel("PointSize: [10]");
149
150  /** This array contains the indices of the attributes currently selected  */
151  private int [] m_selectedAttribs;
152
153  /** This contains the index of the currently selected colouring attribute  */
154  private int m_classIndex;
155
156  /** This is a local array cache for all the instance values for faster rendering */
157  private int [][] m_points;
158
159  /** This is an array cache for the colour of each of the instances depending on the
160      colouring attribute. If the colouring attribute is nominal then it contains the
161      index of the colour in our colour list. Otherwise, for numeric colouring attribute,
162      it contains the precalculated red component for each instance's colour */
163  private int [] m_pointColors;
164
165  /** Contains true for each attribute value (only the selected attributes+class attribute)
166      that is  missing, for each instance.
167      m_missing[i][j] == true if m_selectedAttribs[j] is missing in instance i.
168      m_missing[i][m_missing[].length-1] == true  if class value is missing in instance i. */ 
169  private boolean [][] m_missing;
170
171  /** This array contains for the classAttribute: <br>
172      m_type[0] = [type of attribute, nominal, string or numeric]<br>
173      m_type[1] = [number of discrete values of nominal or string attribute <br>
174      or same as m_type[0] for numeric attribute] */
175  private int [] m_type;
176
177  /** Stores the maximum size for PlotSize label to keep it's size constant */
178  private Dimension m_plotLBSizeD;
179
180  /** Stores the maximum size for PointSize label to keep it's size constant */
181  private Dimension m_pointLBSizeD;
182
183  /** Contains discrete colours for colouring for nominal attributes */
184  private FastVector m_colorList = new FastVector();
185
186  /** default colour list */
187  private static final Color [] m_defaultColors = {Color.blue,
188                                                   Color.red,
189                                                   Color.cyan,
190                                                   new Color(75, 123, 130),
191                                                   Color.pink,
192                                                   Color.green,
193                                                   Color.orange,
194                                                   new Color(255, 0, 255),
195                                                   new Color(255, 0, 0),
196                                                   new Color(0, 255, 0),
197                                                   Color.black};
198
199  /** color for the font used in column and row names */
200  private final Color fontColor = new Color(98, 101, 156);
201
202  /** font used in column and row names */
203  private final java.awt.Font f = new java.awt.Font("Dialog", java.awt.Font.BOLD, 11);
204
205
206
207  /**
208   * Constructor
209   */
210  public MatrixPanel() {
211    m_rseed.setText("1");
212
213    /** Setting up GUI **/
214    m_selAttrib.addActionListener( new ActionListener() {
215        public void actionPerformed(ActionEvent ae) {
216          final JDialog jd = new JDialog((JFrame) MatrixPanel.this.getTopLevelAncestor(), 
217                                         "Attribute Selection Panel",
218                                         true);
219
220          JPanel jp = new JPanel();
221          JScrollPane js = new JScrollPane(m_attribList);
222          JButton okBt = new JButton("OK");
223          JButton cancelBt = new JButton("Cancel");
224          final int [] savedSelection = m_attribList.getSelectedIndices();
225                                       
226          okBt.addActionListener( new ActionListener() {       
227              public void actionPerformed(ActionEvent e) {
228                jd.dispose(); }
229            } );
230
231          cancelBt.addActionListener( new ActionListener() {
232              public void actionPerformed(ActionEvent e) {
233                m_attribList.setSelectedIndices(savedSelection);
234                jd.dispose();}
235            });
236          jd.addWindowListener( new WindowAdapter() {
237              public void windowClosing(WindowEvent e) {
238                m_attribList.setSelectedIndices(savedSelection);
239                jd.dispose();}
240            });
241          jp.add(okBt);
242          jp.add(cancelBt);
243
244          jd.getContentPane().add(js, BorderLayout.CENTER); 
245          jd.getContentPane().add(jp, BorderLayout.SOUTH);
246
247          if(js.getPreferredSize().width < 200)
248            jd.setSize( 250, 250 );
249          else
250            jd.setSize( (int) js.getPreferredSize().width+10, 250);
251                                       
252          jd.setLocation( m_selAttrib.getLocationOnScreen().x,
253                          m_selAttrib.getLocationOnScreen().y-jd.getHeight() );
254          jd.setVisible(true);
255        }
256      });
257     
258    m_updateBt.addActionListener( new ActionListener() {
259        public void actionPerformed(ActionEvent e) {
260            //m_selectedAttribs = m_attribList.getSelectedIndices();
261          initInternalFields();
262                                       
263          Plot a = m_plotsPanel;
264          a.setCellSize( m_plotSize.getValue() );                                       
265          Dimension d = new Dimension((m_selectedAttribs.length)*(a.cellSize+a.extpad)+2, 
266                                      (m_selectedAttribs.length)*(a.cellSize+a.extpad)+2
267                                     );
268          //System.out.println("Size: "+a.cellSize+" Extpad: "+
269          //               a.extpad+" selected: "+
270          //               m_selectedAttribs.length+' '+d);
271          a.setPreferredSize(d);
272          a.setSize( a.getPreferredSize() );
273          a.setJitter( m_jitter.getValue() );
274                                       
275          m_js.revalidate();
276          m_cp.setColours(m_colorList);
277          m_cp.setCindex(m_classIndex);
278                                       
279          repaint();
280        }
281      });
282    m_updateBt.setPreferredSize( m_selAttrib.getPreferredSize() );
283     
284    m_plotSize.addChangeListener( new ChangeListener() {
285        public void stateChanged(ChangeEvent ce) {
286          m_plotSizeLb.setText("PlotSize: ["+m_plotSize.getValue()+"]");
287          m_plotSizeLb.setPreferredSize( m_plotLBSizeD );
288          m_jitter.setMaximum( m_plotSize.getValue()/5 ); //20% of cell Size
289        }
290      });
291 
292    m_pointSize.addChangeListener( new ChangeListener() {
293        public void stateChanged(ChangeEvent ce) {
294          m_pointSizeLb.setText("PointSize: ["+m_pointSize.getValue()+"]");
295          m_pointSizeLb.setPreferredSize( m_pointLBSizeD );
296          datapointSize = m_pointSize.getValue();
297        }
298      });
299 
300    m_resampleBt.addActionListener( new ActionListener() { 
301        public void actionPerformed(ActionEvent e) {
302          JLabel rseedLb = new JLabel("Random Seed: ");
303          JTextField rseedTxt = m_rseed;
304          JLabel percentLb = new JLabel("Subsample as");
305          JLabel percent2Lb = new JLabel("% of input: ");
306          final JTextField percentTxt = new JTextField(5);
307          percentTxt.setText( m_resamplePercent.getText() );
308          JButton doneBt = new JButton("Done");
309
310          final JDialog jd = new JDialog((JFrame) MatrixPanel.this.getTopLevelAncestor(), 
311                                         "Subsample % Panel",
312                                         true) {
313              private static final long serialVersionUID = -269823533147146296L;
314             
315              public void dispose() { 
316                m_resamplePercent.setText(percentTxt.getText());
317                super.dispose();
318              } 
319            };
320          jd.setDefaultCloseOperation( JDialog.DISPOSE_ON_CLOSE );
321                               
322          doneBt.addActionListener( new ActionListener(){ 
323              public void actionPerformed(ActionEvent ae) {
324                jd.dispose(); 
325              }
326            });
327          GridBagLayout gbl = new GridBagLayout();
328          GridBagConstraints gbc = new GridBagConstraints();
329          JPanel p1 = new JPanel( gbl );               
330          gbc.anchor = GridBagConstraints.WEST; gbc.fill = GridBagConstraints.HORIZONTAL;
331          gbc.insets = new Insets(0,2,2,2);
332          gbc.gridwidth = GridBagConstraints.RELATIVE;
333          p1.add(rseedLb, gbc); gbc.weightx = 0;
334          gbc.gridwidth = GridBagConstraints.REMAINDER; gbc.weightx=1;
335          p1.add(rseedTxt, gbc);
336          gbc.insets = new Insets(8,2,0,2); gbc.weightx=0;
337          p1.add(percentLb, gbc);
338          gbc.insets = new Insets(0,2,2,2); gbc.gridwidth = GridBagConstraints.RELATIVE;
339          p1.add(percent2Lb, gbc);
340          gbc.gridwidth = GridBagConstraints.REMAINDER; gbc.weightx=1;
341          p1.add(percentTxt, gbc);
342          gbc.insets = new Insets(8,2,2,2);
343
344          JPanel p3 = new JPanel( gbl );
345          gbc.fill = GridBagConstraints.HORIZONTAL; gbc.gridwidth = GridBagConstraints.REMAINDER;
346          gbc.weightx = 1;  gbc.weighty = 0;
347          p3.add(p1, gbc);
348          gbc.insets = new Insets(8,4,8,4);
349          p3.add(doneBt, gbc);
350                                           
351          jd.getContentPane().setLayout( new BorderLayout() );
352          jd.getContentPane().add(p3, BorderLayout.NORTH);
353          jd.pack();
354          jd.setLocation( m_resampleBt.getLocationOnScreen().x,
355                          m_resampleBt.getLocationOnScreen().y-jd.getHeight() );
356          jd.setVisible(true);
357        }
358      });
359
360    optionsPanel = new JPanel( new GridBagLayout() ); //all the rest of the panels are in here.
361    final JPanel p2 = new JPanel( new BorderLayout() );  //this has class colour panel
362    final JPanel p3 = new JPanel( new GridBagLayout() ); //this has update and select buttons
363    final JPanel p4 = new JPanel( new GridBagLayout() ); //this has the slider bars and combobox
364    GridBagConstraints gbc = new GridBagConstraints();
365     
366    m_plotLBSizeD = m_plotSizeLb.getPreferredSize();
367    m_pointLBSizeD = m_pointSizeLb.getPreferredSize();
368    m_pointSizeLb.setText("PointSize: [1]");
369    m_pointSizeLb.setPreferredSize( m_pointLBSizeD );
370    m_resampleBt.setPreferredSize( m_selAttrib.getPreferredSize() );
371
372    gbc.fill = GridBagConstraints.HORIZONTAL;
373    gbc.anchor = GridBagConstraints.NORTHWEST;
374    gbc.insets = new Insets(2,2,2,2);
375    p4.add(m_plotSizeLb, gbc);
376    gbc.weightx=1; gbc.gridwidth = GridBagConstraints.REMAINDER;
377    p4.add(m_plotSize, gbc);
378    gbc.weightx=0; gbc.gridwidth = GridBagConstraints.RELATIVE;
379    p4.add(m_pointSizeLb, gbc);
380    gbc.weightx=1; gbc.gridwidth = GridBagConstraints.REMAINDER;
381    p4.add(m_pointSize, gbc);
382    gbc.weightx=0; gbc.gridwidth = GridBagConstraints.RELATIVE;
383    p4.add( new JLabel("Jitter: "), gbc);
384    gbc.weightx=1; gbc.gridwidth = GridBagConstraints.REMAINDER;
385    p4.add(m_jitter, gbc);
386    p4.add(m_classAttrib, gbc);
387     
388    gbc.gridwidth = GridBagConstraints.REMAINDER;
389    gbc.weightx=1;
390    gbc.fill = GridBagConstraints.NONE;
391    p3.add(m_updateBt, gbc);
392    p3.add(m_selAttrib, gbc);
393    gbc.gridwidth = GridBagConstraints.RELATIVE;
394    gbc.weightx = 0;
395    gbc.fill = GridBagConstraints.VERTICAL;
396    gbc.anchor = GridBagConstraints.WEST;
397    p3.add(m_resampleBt, gbc);
398    gbc.gridwidth = GridBagConstraints.REMAINDER;
399    p3.add(m_resamplePercent, gbc);
400   
401    p2.setBorder(BorderFactory.createTitledBorder("Class Colour"));
402    p2.add(m_cp, BorderLayout.SOUTH);
403
404    gbc.insets = new Insets(8,5,2,5);
405    gbc.anchor = GridBagConstraints.SOUTHWEST; gbc.fill = GridBagConstraints.HORIZONTAL; gbc.weightx=1;
406    gbc.gridwidth = GridBagConstraints.RELATIVE;
407    optionsPanel.add(p4, gbc);
408    gbc.gridwidth = GridBagConstraints.REMAINDER;
409    optionsPanel.add(p3, gbc);
410    optionsPanel.add(p2, gbc);
411
412    this.addComponentListener( new ComponentAdapter() {
413        public void componentResized(ComponentEvent cv) {
414          m_js.setMinimumSize( new Dimension(MatrixPanel.this.getWidth(),
415                                             MatrixPanel.this.getHeight()
416                                             -optionsPanel.getPreferredSize().height-10));
417          jp.setDividerLocation( MatrixPanel.this.getHeight()-optionsPanel.getPreferredSize().height-10 );
418        }
419      });
420
421    optionsPanel.setMinimumSize( new Dimension(0,0) );
422    jp = new JSplitPane(JSplitPane.VERTICAL_SPLIT, m_js, optionsPanel);
423    jp.setOneTouchExpandable(true);
424    jp.setResizeWeight(1);
425    this.setLayout( new BorderLayout() );
426    this.add(jp, BorderLayout.CENTER);
427
428    /** Setting up the initial color list **/
429    for(int i=0; i<m_defaultColors.length-1; i++)
430      m_colorList.addElement(m_defaultColors[i]);
431     
432    /** Initializing internal fields and components **/
433    m_selectedAttribs = m_attribList.getSelectedIndices();
434    m_plotsPanel = new Plot();
435    m_plotsPanel.setLayout(null);
436    m_js.getHorizontalScrollBar().setUnitIncrement( 10 );
437    m_js.getVerticalScrollBar().setUnitIncrement( 10 ); 
438    m_js.setViewportView( m_plotsPanel );
439    m_js.setColumnHeaderView( m_plotsPanel.getColHeader() );
440    m_js.setRowHeaderView( m_plotsPanel.getRowHeader() );
441    final JLabel lb = new JLabel(" Plot Matrix");
442    lb.setFont(f); lb.setForeground(fontColor);
443    lb.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
444    m_js.setCorner(JScrollPane.UPPER_LEFT_CORNER, lb);
445    m_cp.setInstances(m_data);
446    m_cp.setBorder(BorderFactory.createEmptyBorder(15,10,10,10));
447    m_cp.addRepaintNotify(m_plotsPanel);
448    //m_updateBt.doClick(); //not until setting up the instances
449  }
450
451
452
453  /** Initializes internal data fields, i.e. data values, type, missing and color cache arrays
454   */
455  public void initInternalFields() {
456    Instances inst = m_data;
457    m_classIndex = m_classAttrib.getSelectedIndex();
458    m_selectedAttribs = m_attribList.getSelectedIndices();
459    double minC=0, maxC=0;
460
461    /** Resampling  **/
462    if(Double.parseDouble(m_resamplePercent.getText())<100) {
463        inst = new Instances(m_data, 0, m_data.numInstances());
464        inst.randomize( new Random(Integer.parseInt(m_rseed.getText())) );
465       
466        //System.err.println("gettingPercent: " +
467        //                   Math.round(
468        //                     Double.parseDouble(m_resamplePercent.getText())
469        //                     / 100D * m_data.numInstances()
470        //                             )
471        //                  );
472       
473        inst = new Instances(inst, 
474                 0,
475                 (int)Math.round(Double.parseDouble(m_resamplePercent.getText())
476                 / 100D*inst.numInstances())
477                            );
478    }
479   
480    m_points = new int[inst.numInstances()][m_selectedAttribs.length]; //changed
481    m_pointColors = new int[inst.numInstances()];
482    m_missing = new boolean[inst.numInstances()][m_selectedAttribs.length+1]; //changed
483    m_type = new int[2]; //[m_selectedAttribs.length]; //changed
484    jitterVals = new int[inst.numInstances()][2];
485     
486    /** Setting up the color list for non-numeric attribute as well as jittervals**/
487    if(!(inst.attribute(m_classIndex).isNumeric())) {
488         
489      for(int i=m_colorList.size(); i<inst.attribute(m_classIndex).numValues()+1; i++) {
490        Color pc = m_defaultColors[i % 10];
491        int ija =  i / 10;
492        ija *= 2; 
493        for (int j=0;j<ija;j++) {
494            pc = pc.darker();
495        }
496        m_colorList.addElement(pc);
497      }
498         
499      for(int i=0; i<inst.numInstances(); i++) {
500        //set to black for missing class value which is last colour is default list
501        if(inst.instance(i).isMissing(m_classIndex))
502          m_pointColors[i] =  m_defaultColors.length-1;
503        else
504          m_pointColors[i] = (int) inst.instance(i).value(m_classIndex);
505
506        jitterVals[i][0] = rnd.nextInt(m_jitter.getValue()+1)
507          - m_jitter.getValue()/2;
508        jitterVals[i][1] = rnd.nextInt(m_jitter.getValue()+1)
509          - m_jitter.getValue()/2;
510             
511      }
512    }
513    /** Setting up color variations for numeric attribute as well as jittervals **/
514    else {
515      for(int i=0; i<inst.numInstances(); i++) {
516        if(!(inst.instance(i).isMissing(m_classIndex))) {
517          minC = maxC = inst.instance(i).value(m_classIndex);
518          break;
519        }
520      }
521         
522      for(int i=1; i<inst.numInstances(); i++) {
523        if(!(inst.instance(i).isMissing(m_classIndex))) {
524          if(minC > inst.instance(i).value(m_classIndex))
525            minC = inst.instance(i).value(m_classIndex);
526          if(maxC < inst.instance(i).value(m_classIndex))
527            maxC = inst.instance(i).value(m_classIndex);
528        }
529      }
530         
531      for(int i=0; i<inst.numInstances(); i++) {
532        double r = (inst.instance(i).value(m_classIndex) - minC) / (maxC - minC);
533        r = (r * 240) + 15;
534        m_pointColors[i] = (int)r;
535
536        jitterVals[i][0] = rnd.nextInt(m_jitter.getValue()+1)
537          - m_jitter.getValue()/2;
538        jitterVals[i][1] = rnd.nextInt(m_jitter.getValue()+1)
539          - m_jitter.getValue()/2;
540      }
541    }
542
543    /** Creating local cache of the data values **/
544    double min[]=new double[m_selectedAttribs.length], max=0;  //changed
545    double ratio[] = new double[m_selectedAttribs.length];     //changed
546    double cellSize = m_plotSize.getValue(), temp1=0, temp2=0;
547
548    for(int j=0; j<m_selectedAttribs.length; j++) {
549      int i;
550      for(i=0; i<inst.numInstances(); i++) {
551        min[j] = max = 0;
552        if(!(inst.instance(i).isMissing(m_selectedAttribs[j]))) {
553          min[j] = max = inst.instance(i).value(m_selectedAttribs[j]);
554          break;
555        }
556      }
557      for( i=i; i<inst.numInstances(); i++ ) {
558        if(!(inst.instance(i).isMissing(m_selectedAttribs[j]))) {
559          if(inst.instance(i).value(m_selectedAttribs[j]) < min[j])
560            min[j] = inst.instance(i).value(m_selectedAttribs[j]);
561          if(inst.instance(i).value(m_selectedAttribs[j]) > max)
562            max = inst.instance(i).value(m_selectedAttribs[j]);
563        }
564      }
565      ratio[j] =  cellSize / (max - min[j]);
566    }
567
568    boolean classIndexProcessed=false;
569    for(int j=0; j<m_selectedAttribs.length; j++) {
570      if(inst.attribute(m_selectedAttribs[j]).isNominal() || inst.attribute(m_selectedAttribs[j]).isString()) {
571          //m_type[0][j] = 1;  m_type[1][j] = inst.attribute(m_selectedAttribs[j]).numValues();
572
573        temp1 = cellSize/(double)inst.attribute(m_selectedAttribs[j]).numValues(); //m_type[1][j];
574        temp2 = temp1/2;
575        for(int i=0; i<inst.numInstances(); i++) {
576          m_points[i][j] = (int) Math.round(temp2+temp1*inst.instance(i).value(m_selectedAttribs[j]));
577          if(inst.instance(i).isMissing(m_selectedAttribs[j])) {
578            m_missing[i][j] = true;    //represents missing value
579            if(m_selectedAttribs[j]==m_classIndex) {
580                m_missing[i][m_missing[0].length-1] = true;
581                classIndexProcessed = true;
582            }
583          }
584        }
585      }
586      else {
587          //m_type[0][j] = m_type[1][j] = 0;
588        for(int i=0; i<inst.numInstances(); i++) {
589          m_points[i][j] = (int) Math.round((inst.instance(i).value(m_selectedAttribs[j])
590                                             -min[j])*ratio[j]);       
591          if(inst.instance(i).isMissing(m_selectedAttribs[j])) {
592            m_missing[i][j] = true;    //represents missing value
593            if(m_selectedAttribs[j]==m_classIndex) {
594                m_missing[i][m_missing[0].length-1] = true;
595                classIndexProcessed = true;
596            }
597          }
598        }
599      }
600    }
601
602    if(inst.attribute(m_classIndex).isNominal() || inst.attribute(m_classIndex).isString()) {
603        m_type[0] = 1; m_type[1] = inst.attribute(m_classIndex).numValues();
604    }
605    else
606        m_type[0] = m_type[1] = 0;
607
608    if(classIndexProcessed==false) {  //class Index has not been processed as class index is not among the selected attribs
609        for(int i=0; i<inst.numInstances(); i++) {
610            if(inst.instance(i).isMissing(m_classIndex))
611                m_missing[i][m_missing[0].length-1] = true;
612        }
613    }
614
615    m_cp.setColours(m_colorList);
616  }
617
618  /** Sets up the UI's attributes lists
619   */ 
620  public void setupAttribLists() {
621    String [] tempAttribNames = new String[m_data.numAttributes()];
622    String type;
623
624    m_classAttrib.removeAllItems();
625    for(int i=0; i<tempAttribNames.length; i++) {
626      switch (m_data.attribute(i).type()) {
627      case Attribute.NOMINAL:
628        type = " (Nom)";
629        break;
630      case Attribute.NUMERIC:
631        type = " (Num)";
632        break;
633      case Attribute.STRING:
634        type = " (Str)";
635        break;
636      case Attribute.DATE:
637        type = " (Dat)";
638        break;
639      case Attribute.RELATIONAL:
640        type = " (Rel)";
641        break;
642      default:
643        type = " (???)";
644      }
645      tempAttribNames[i] = new String("Colour: "+m_data.attribute(i).name()+" "+type);
646      m_classAttrib.addItem(tempAttribNames[i]);
647    }
648    if (m_data.classIndex() == -1)
649      m_classAttrib.setSelectedIndex(tempAttribNames.length - 1);
650    else
651      m_classAttrib.setSelectedIndex(m_data.classIndex());
652    m_attribList.setListData(tempAttribNames);
653    m_attribList.setSelectionInterval(0, tempAttribNames.length-1);
654  }
655
656  /** Calculates the percentage to resample
657   */
658  public void setPercent() {
659    if(m_data.numInstances() > 700) {
660      double percnt = 500D/m_data.numInstances()*100;     
661      percnt *= 100;
662      percnt = Math.round(percnt);
663      percnt /= 100;
664
665      m_resamplePercent.setText(""+percnt);
666    }
667    else
668      m_resamplePercent.setText("100");
669  }
670
671
672  /** This method changes the Instances object of this class to a new one. It also does all the necessary
673      initializations for displaying the panel. This must be called before trying to display the panel.
674      @param newInst The new set of Instances
675  */
676  public void setInstances(Instances newInst) {
677
678    m_data = newInst;
679    setPercent();
680    setupAttribLists();
681    m_rseed.setText("1");
682    initInternalFields();
683    m_cp.setInstances(m_data);
684    m_cp.setCindex(m_classIndex);
685    m_updateBt.doClick();
686  }
687
688
689  /**
690     Main method for testing this class
691  */
692  public static void main(String [] args)  {
693    final JFrame jf = new JFrame("Weka Explorer: MatrixPanel");
694    final JButton setBt = new JButton("Set Instances");
695    Instances data = null;
696    try {
697      if(args.length==1)
698        data = new Instances( new BufferedReader( new FileReader(args[0])) ); 
699      else {
700        System.out.println("Usage: MatrixPanel <arff file>"); 
701        System.exit(-1);
702      }
703    } catch(IOException ex) { ex.printStackTrace(); System.exit(-1); }
704     
705    final MatrixPanel mp = new MatrixPanel();
706    mp.setInstances(data);
707    setBt.addActionListener( new ActionListener() {
708        public void actionPerformed(ActionEvent e) {
709          JFileChooser chooser = new JFileChooser(new java.io.File(System.getProperty("user.dir")));
710          ExtensionFileFilter myfilter = new ExtensionFileFilter("arff", "Arff data files");
711          chooser.setFileFilter(myfilter);
712          int returnVal = chooser.showOpenDialog(jf);
713                 
714          if(returnVal == JFileChooser.APPROVE_OPTION)
715            {
716              try{
717                System.out.println("You chose to open this file: " +chooser.getSelectedFile().getName());
718                Instances in = new Instances ( new FileReader(chooser.getSelectedFile().getAbsolutePath()) );
719                mp.setInstances(in);
720              }
721              catch(Exception ex) { ex.printStackTrace(); }
722            }
723        }
724      });
725    //System.out.println("Loaded: "+args[0]+"\nRelation: "+data.relationName()+"\nAttributes: "+data.numAttributes());
726    //System.out.println("The attributes are: ");
727    //for(int i=0; i<data.numAttributes(); i++)
728    //  System.out.println(data.attribute(i).name());
729
730    //RepaintManager.currentManager(jf.getRootPane()).setDoubleBufferingEnabled(false);
731    jf.getContentPane().setLayout( new BorderLayout() );
732    jf.getContentPane().add(mp, BorderLayout.CENTER);
733    jf.getContentPane().add(setBt, BorderLayout.SOUTH);
734    jf.getContentPane().setFont( new java.awt.Font( "SansSerif", java.awt.Font.PLAIN, 11) );
735    jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
736    jf.setSize(800, 600);
737    jf.setVisible(true);
738    jf.repaint();
739  }
740
741 
742  /**
743     Internal class responsible for displaying the actual matrix
744     Requires the internal data fields of the parent class to be properly initialized
745     before being created
746  */
747  private class Plot
748    extends JPanel
749    implements MouseMotionListener, MouseListener {
750
751    /** for serialization */
752    private static final long serialVersionUID = -1721245738439420882L;   
753
754    int extpad=3, intpad=4, cellSize=100, cellRange=100, lastx=0, lasty=0, jitter=0;
755    java.awt.Rectangle r;
756    java.awt.FontMetrics fm;
757    int lastxpos, lastypos;
758    JPanel jPlColHeader, jPlRowHeader;
759
760
761    /** Constructor
762     */
763    public Plot() {
764      super();
765      this.setToolTipText("blah");
766      this.addMouseMotionListener( this );
767      this.addMouseListener( this );
768      initialize();
769    }
770
771    /** Initializes the internal fields */
772    public void initialize() {
773      lastxpos = lastypos = 0;   
774      cellRange = cellSize; cellSize = cellRange + 2*intpad;
775
776      jPlColHeader = new JPanel() {
777        private static final long serialVersionUID = -9098547751937467506L;
778        java.awt.Rectangle r;
779        public void paint(Graphics g) {
780          r = g.getClipBounds();
781          g.setColor(this.getBackground());
782          g.fillRect(r.x, r.y, r.width, r.height);
783          g.setFont( f );
784          fm = g.getFontMetrics();
785          int xpos = 0, ypos = 0, attribWidth=0;
786         
787          g.setColor(fontColor);
788          xpos = extpad;
789          ypos=extpad+fm.getHeight();
790         
791          for(int i=0; i<m_selectedAttribs.length; i++) {
792            if( xpos+cellSize < r.x)
793            { xpos += cellSize+extpad; continue; }
794            else if(xpos > r.x+r.width)
795            { break; }
796            else {
797              attribWidth = fm.stringWidth(m_data.attribute(m_selectedAttribs[i]).name());
798              g.drawString(m_data.attribute(m_selectedAttribs[i]).name(),
799              (attribWidth<cellSize) ? (xpos + (cellSize/2 - attribWidth/2)):xpos,
800              ypos);
801            }
802            xpos += cellSize+extpad;
803          }
804          fm = null; r=null;
805        }
806       
807        public Dimension getPreferredSize() {
808          fm = this.getFontMetrics(this.getFont());
809          return new Dimension( m_selectedAttribs.length*(cellSize+extpad),
810          2*extpad + fm.getHeight() );
811        }
812      };
813
814      jPlRowHeader = new JPanel() {
815        private static final long serialVersionUID = 8474957069309552844L;
816       
817        java.awt.Rectangle r;
818        public void paint(Graphics g) {
819          r = g.getClipBounds();
820          g.setColor(this.getBackground());
821          g.fillRect(r.x, r.y, r.width, r.height);
822          g.setFont( f );
823          fm = g.getFontMetrics();
824          int xpos = 0, ypos = 0;
825         
826          g.setColor(fontColor);
827          xpos = extpad;
828          ypos=extpad;
829         
830          for(int j=m_selectedAttribs.length-1; j>=0; j--) {
831            if( ypos+cellSize < r.y )
832            { ypos += cellSize+extpad;  continue; }
833            else if( ypos > r.y+r.height )
834              break;
835            else {
836              g.drawString(m_data.attribute(m_selectedAttribs[j]).name(), xpos+extpad, ypos+cellSize/2);
837            }
838            xpos = extpad;
839            ypos += cellSize+extpad;
840          }
841          r=null;
842        }
843       
844        public Dimension getPreferredSize() {
845          return new Dimension( 100+extpad,
846          m_selectedAttribs.length*(cellSize+extpad)
847          );
848        }
849      };
850      jPlColHeader.setFont(f);
851      jPlRowHeader.setFont(f);
852      this.setFont(f);
853    }     
854
855    public JPanel getRowHeader() {
856          return jPlRowHeader;
857    }
858
859    public JPanel getColHeader() {
860        return jPlColHeader;
861    }
862
863    public void mouseMoved(MouseEvent e) {
864      Graphics g = this.getGraphics();
865      int xpos=extpad, ypos=extpad;
866
867      for(int j=m_selectedAttribs.length-1; j>=0; j--) {
868        for(int i=0; i<m_selectedAttribs.length; i++) {
869          if(e.getX()>=xpos && e.getX()<=xpos+cellSize+extpad)
870            if(e.getY()>=ypos && e.getY()<=ypos+cellSize+extpad) {
871              if(xpos!=lastxpos || ypos!=lastypos) {
872                g.setColor( Color.red );
873                g.drawRect(xpos-1, ypos-1, cellSize+1, cellSize+1);
874                if(lastxpos!=0 && lastypos!=0) {
875                  g.setColor( this.getBackground().darker() );
876                  g.drawRect(lastxpos-1, lastypos-1, cellSize+1, cellSize+1); }
877                lastxpos = xpos; lastypos = ypos;
878              }
879              return;
880            }
881          xpos+=cellSize+extpad;
882        }
883        xpos=extpad;
884        ypos+=cellSize+extpad;
885      }
886      if(lastxpos!=0 && lastypos!=0) {
887        g.setColor( this.getBackground().darker() );
888        g.drawRect(lastxpos-1, lastypos-1, cellSize+1, cellSize+1); }
889      lastxpos=lastypos=0;
890    }
891
892    public void mouseDragged(MouseEvent e){ }
893
894    public void mouseClicked(MouseEvent e) {
895      int i=0, j=0, found=0;
896         
897      int xpos=extpad, ypos=extpad;
898      for(j=m_selectedAttribs.length-1; j>=0; j--) {
899        for(i=0; i<m_selectedAttribs.length; i++) {
900          if(e.getX()>=xpos && e.getX()<=xpos+cellSize+extpad)
901            if(e.getY()>=ypos && e.getY()<=ypos+cellSize+extpad) {
902              found=1; break;
903            }
904          xpos+=cellSize+extpad;
905        }
906        if(found==1)
907          break;
908        xpos=extpad;
909        ypos+=cellSize+extpad;
910      }
911      if(found==0)
912        return;
913
914      JFrame jf = new JFrame("Weka Explorer: Visualizing "+m_data.relationName() );
915      VisualizePanel vp = new VisualizePanel();
916      try {
917        PlotData2D pd = new PlotData2D(m_data);
918        pd.setPlotName("Master Plot");
919        vp.setMasterPlot(pd);
920        //System.out.println("x: "+i+" y: "+j);
921        vp.setXIndex(m_selectedAttribs[i]);
922        vp.setYIndex(m_selectedAttribs[j]);
923        vp.m_ColourCombo.setSelectedIndex( m_classIndex );
924      }
925      catch(Exception ex) { ex.printStackTrace(); }
926      jf.getContentPane().add(vp);
927      jf.setSize(800,600);
928      jf.setVisible(true);
929    } 
930
931    public void mouseEntered(MouseEvent e){ }
932    public void mouseExited(MouseEvent e){ }
933    public void mousePressed(MouseEvent e){ }
934    public void mouseReleased(MouseEvent e){ }
935
936    /** sets the new jitter value for the plots
937     */
938    public void setJitter(int newjitter) {
939      jitter = newjitter;
940    }
941     
942    /** sets the new size for the plots
943     */
944    public void setCellSize(int newCellSize) {
945      cellSize = newCellSize;
946      initialize();
947    }
948
949    /** Returns the X and Y attributes of the plot the mouse is currently
950        on
951    */
952    public String getToolTipText(MouseEvent event) {
953      int xpos=extpad, ypos=extpad;
954         
955      for(int j=m_selectedAttribs.length-1; j>=0; j--) {
956        for(int i=0; i<m_selectedAttribs.length; i++) {
957          if(event.getX()>=xpos && event.getX()<=xpos+cellSize+extpad)
958            if(event.getY()>=ypos && event.getY()<=ypos+cellSize+extpad)
959              return("X: "+m_data.attribute(m_selectedAttribs[i]).name()+
960                     " Y: "+m_data.attribute(m_selectedAttribs[j]).name()+
961                     " (click to enlarge)");
962          xpos+=cellSize+extpad;
963        }
964        xpos=extpad;
965        ypos+=cellSize+extpad;
966      }
967      return ("Matrix Panel");
968    }
969
970    /**  Paints a single Plot at xpos, ypos. and xattrib and yattrib on X and
971         Y axes
972    */
973    public void paintGraph(Graphics g, int xattrib, int yattrib, int xpos, int ypos) {
974      int x, y;
975      g.setColor( this.getBackground().darker().darker() );
976      g.drawRect(xpos-1, ypos-1, cellSize+1, cellSize+1);
977      g.setColor(Color.white);
978      g.fillRect(xpos, ypos, cellSize, cellSize);
979      for(int i=0; i<m_points.length; i++) {
980       
981        if( !(m_missing[i][yattrib] || m_missing[i][xattrib]) ) {
982         
983          if(m_type[0]==0)
984            if(m_missing[i][m_missing[0].length-1])
985              g.setColor(m_defaultColors[m_defaultColors.length-1]);
986            else
987              g.setColor( new Color(m_pointColors[i],150,(255-m_pointColors[i])) );
988          else
989            g.setColor((Color)m_colorList.elementAt(m_pointColors[i]));
990         
991          if(m_points[i][xattrib]+jitterVals[i][0]<0 || m_points[i][xattrib]+jitterVals[i][0]>cellRange)
992            if(cellRange-m_points[i][yattrib]+jitterVals[i][1]<0 || cellRange-m_points[i][yattrib]+jitterVals[i][1]>cellRange) {
993              //both x and y out of range don't add jitter
994              x=intpad+m_points[i][xattrib];
995              y=intpad+(cellRange - m_points[i][yattrib]);
996            }
997            else {
998              //only x out of range
999              x=intpad+m_points[i][xattrib];
1000              y=intpad+(cellRange - m_points[i][yattrib])+jitterVals[i][1];
1001            }
1002          else if(cellRange-m_points[i][yattrib]+jitterVals[i][1]<0 || cellRange-m_points[i][yattrib]+jitterVals[i][1]>cellRange) {
1003            //only y out of range
1004            x=intpad+m_points[i][xattrib]+jitterVals[i][0];
1005            y=intpad+(cellRange - m_points[i][yattrib]);
1006          }
1007          else {
1008            //none out of range
1009            x=intpad+m_points[i][xattrib]+jitterVals[i][0];
1010            y=intpad+(cellRange - m_points[i][yattrib])+jitterVals[i][1];
1011          }
1012          if(datapointSize==1)
1013            g.drawLine(x+xpos, y+ypos, x+xpos, y+ypos);
1014          else
1015            g.drawOval(x+xpos-datapointSize/2, y+ypos-datapointSize/2, datapointSize, datapointSize);
1016        }
1017      }
1018      g.setColor( fontColor );
1019    }
1020   
1021
1022    /**
1023       Paints the matrix of plots in the current visible region
1024    */
1025    public void paintME(Graphics g) {
1026      r = g.getClipBounds();
1027     
1028      g.setColor( this.getBackground() );
1029      g.fillRect(r.x, r.y, r.width, r.height);
1030      g.setColor( fontColor );
1031     
1032      int xpos = 0, ypos = 0;
1033     
1034      xpos = extpad;
1035      ypos=extpad;
1036     
1037     
1038      for(int j=m_selectedAttribs.length-1; j>=0; j--) {
1039        if( ypos+cellSize < r.y )
1040        { ypos += cellSize+extpad;  continue; }
1041        else if( ypos > r.y+r.height )
1042          break;
1043        else {
1044          for(int i=0; i<m_selectedAttribs.length; i++) {
1045            if( xpos+cellSize < r.x) {
1046              xpos += cellSize+extpad; continue; }
1047            else if(xpos > r.x+r.width)
1048              break;
1049            else
1050              paintGraph(g, i, j, xpos, ypos); //m_selectedAttribs[i], m_selectedAttribs[j], xpos, ypos);
1051            xpos += cellSize+extpad;
1052          }
1053        }
1054        xpos = extpad;
1055        ypos += cellSize+extpad;
1056      }
1057    }
1058     
1059    /** paints this JPanel (PlotsPanel)
1060     */
1061    public void paintComponent(Graphics g) {
1062      paintME(g);
1063    }
1064  }
1065}
Note: See TracBrowser for help on using the repository browser.