~ubuntu-branches/ubuntu/precise/weka/precise

« back to all changes in this revision

Viewing changes to weka/gui/visualize/VisualizePanel.java

  • Committer: Bazaar Package Importer
  • Author(s): Soeren Sonnenburg
  • Date: 2008-02-24 09:18:45 UTC
  • Revision ID: james.westby@ubuntu.com-20080224091845-1l8zy6fm6xipbzsr
Tags: upstream-3.5.7+tut1
ImportĀ upstreamĀ versionĀ 3.5.7+tut1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 *    VisualizePanel.java
 
19
 *    Copyright (C) 1999 University of Waikato, Hamilton, New Zealand
 
20
 *
 
21
 */
 
22
 
 
23
package weka.gui.visualize;
 
24
 
 
25
import weka.core.Attribute;
 
26
import weka.core.FastVector;
 
27
import weka.core.Instance;
 
28
import weka.core.Instances;
 
29
import weka.gui.ExtensionFileFilter;
 
30
import weka.gui.Logger;
 
31
 
 
32
import java.awt.BorderLayout;
 
33
import java.awt.Color;
 
34
import java.awt.Component;
 
35
import java.awt.Dimension;
 
36
import java.awt.Graphics;
 
37
import java.awt.GridBagConstraints;
 
38
import java.awt.GridBagLayout;
 
39
import java.awt.GridLayout;
 
40
import java.awt.Insets;
 
41
import java.awt.event.ActionEvent;
 
42
import java.awt.event.ActionListener;
 
43
import java.awt.event.InputEvent;
 
44
import java.awt.event.MouseAdapter;
 
45
import java.awt.event.MouseEvent;
 
46
import java.awt.event.MouseMotionAdapter;
 
47
import java.io.BufferedReader;
 
48
import java.io.BufferedWriter;
 
49
import java.io.File;
 
50
import java.io.FileReader;
 
51
import java.io.FileWriter;
 
52
import java.io.Writer;
 
53
import java.util.Random;
 
54
 
 
55
import javax.swing.BorderFactory;
 
56
import javax.swing.DefaultComboBoxModel;
 
57
import javax.swing.JButton;
 
58
import javax.swing.JComboBox;
 
59
import javax.swing.JFileChooser;
 
60
import javax.swing.JFrame;
 
61
import javax.swing.JLabel;
 
62
import javax.swing.JOptionPane;
 
63
import javax.swing.JPanel;
 
64
import javax.swing.JSlider;
 
65
import javax.swing.SwingConstants;
 
66
import javax.swing.event.ChangeEvent;
 
67
import javax.swing.event.ChangeListener;
 
68
import javax.swing.filechooser.FileFilter;
 
69
 
 
70
/** 
 
71
 * This panel allows the user to visualize a dataset (and if provided) a
 
72
 * classifier's/clusterer's predictions in two dimensions.
 
73
 *
 
74
 * If the user selects a nominal attribute as the colouring attribute then
 
75
 * each point is drawn in a colour that corresponds to the discrete value
 
76
 * of that attribute for the instance. If the user selects a numeric
 
77
 * attribute to colour on, then the points are coloured using a spectrum
 
78
 * ranging from blue to red (low values to high).
 
79
 *
 
80
 * When a classifier's predictions are supplied they are plotted in one
 
81
 * of two ways (depending on whether the class is nominal or numeric).<br>
 
82
 * For nominal class: an error made by a classifier is plotted as a square
 
83
 * in the colour corresponding to the class it predicted.<br>
 
84
 * For numeric class: predictions are plotted as varying sized x's, where
 
85
 * the size of the x is related to the magnitude of the error.
 
86
 *
 
87
 * @author Mark Hall (mhall@cs.waikato.ac.nz)
 
88
 * @author Malcolm Ware (mfw4@cs.waikato.ac.nz)
 
89
 * @version $Revision: 1.28 $
 
90
 */
 
91
public class VisualizePanel
 
92
  extends PrintablePanel {
 
93
 
 
94
  /** for serialization */
 
95
  private static final long serialVersionUID = 240108358588153943L;
 
96
 
 
97
  /** Inner class to handle plotting */
 
98
  protected class PlotPanel
 
99
    extends PrintablePanel
 
100
    implements Plot2DCompanion {
 
101
 
 
102
    /** for serialization */
 
103
    private static final long serialVersionUID = -4823674171136494204L;
 
104
 
 
105
    /** The actual generic plotting panel */
 
106
    protected Plot2D m_plot2D = new Plot2D();
 
107
 
 
108
    /** The instances from the master plot */
 
109
    protected Instances m_plotInstances=null;
 
110
 
 
111
    /** The master plot */
 
112
    protected PlotData2D m_originalPlot=null;
 
113
    
 
114
    /** Indexes of the attributes to go on the x and y axis and the attribute
 
115
        to use for colouring and the current shape for drawing */
 
116
    protected int m_xIndex=0;
 
117
    protected int m_yIndex=0;
 
118
    protected int m_cIndex=0;
 
119
    protected int m_sIndex=0;
 
120
 
 
121
    /**the offsets of the axes once label metrics are calculated */
 
122
    private int m_XaxisStart=0;
 
123
    private int m_YaxisStart=0;
 
124
    private int m_XaxisEnd=0;
 
125
    private int m_YaxisEnd=0;
 
126
 
 
127
    /** True if the user is currently dragging a box. */
 
128
    private boolean m_createShape;
 
129
    
 
130
    /** contains all the shapes that have been drawn for these attribs */
 
131
    private FastVector m_shapes;
 
132
 
 
133
    /** contains the points of the shape currently being drawn. */
 
134
    private FastVector m_shapePoints;
 
135
 
 
136
    /** contains the position of the mouse (used for rubberbanding). */
 
137
    private Dimension m_newMousePos;
 
138
 
 
139
    /** Constructor */
 
140
    public PlotPanel() {
 
141
      this.setBackground(m_plot2D.getBackground());
 
142
      this.setLayout(new BorderLayout());
 
143
      this.add(m_plot2D, BorderLayout.CENTER);
 
144
      m_plot2D.setPlotCompanion(this);
 
145
 
 
146
      m_createShape = false;        
 
147
      m_shapes = null;////
 
148
      m_shapePoints = null;
 
149
      m_newMousePos = new Dimension();
 
150
 
 
151
      this.addMouseListener(new MouseAdapter() {
 
152
          ///////      
 
153
          public void mousePressed(MouseEvent e) {
 
154
            if ((e.getModifiers() & MouseEvent.BUTTON1_MASK) == MouseEvent.BUTTON1_MASK) {
 
155
              //
 
156
              if (m_sIndex == 0) {
 
157
                //do nothing it will get dealt to in the clicked method
 
158
              }
 
159
              else if (m_sIndex == 1) {
 
160
                m_createShape = true;
 
161
                m_shapePoints = new FastVector(5);
 
162
                m_shapePoints.addElement(new Double(m_sIndex));
 
163
                m_shapePoints.addElement(new Double(e.getX()));
 
164
                m_shapePoints.addElement(new Double(e.getY()));
 
165
                m_shapePoints.addElement(new Double(e.getX()));
 
166
                m_shapePoints.addElement(new Double(e.getY()));
 
167
                //              Graphics g = PlotPanel.this.getGraphics();
 
168
                Graphics g = m_plot2D.getGraphics();
 
169
                g.setColor(Color.black);
 
170
                g.setXORMode(Color.white);
 
171
                g.drawRect(((Double)m_shapePoints.elementAt(1)).intValue(),
 
172
                           ((Double)m_shapePoints.elementAt(2)).intValue(),
 
173
                           ((Double)m_shapePoints.elementAt(3)).intValue() -
 
174
                           ((Double)m_shapePoints.elementAt(1)).intValue(), 
 
175
                           ((Double)m_shapePoints.elementAt(4)).intValue() -
 
176
                           ((Double)m_shapePoints.elementAt(2)).intValue());
 
177
                g.dispose();
 
178
              }
 
179
              //System.out.println("clicked");
 
180
            }
 
181
            //System.out.println("clicked");
 
182
          }
 
183
          //////
 
184
          public void mouseClicked(MouseEvent e) {
 
185
            
 
186
            if ((m_sIndex == 2 || m_sIndex == 3) && 
 
187
                (m_createShape || 
 
188
                 (e.getModifiers() & MouseEvent.BUTTON1_MASK) == MouseEvent.BUTTON1_MASK)) {
 
189
              if (m_createShape) {
 
190
                //then it has been started already.
 
191
 
 
192
                Graphics g = m_plot2D.getGraphics();
 
193
                g.setColor(Color.black);
 
194
                g.setXORMode(Color.white);
 
195
                if ((e.getModifiers() & MouseEvent.BUTTON1_MASK) == MouseEvent.BUTTON1_MASK &&
 
196
                    !e.isAltDown()) {
 
197
                  m_shapePoints.addElement(new 
 
198
                    Double(m_plot2D.convertToAttribX(e.getX())));
 
199
                  
 
200
                  m_shapePoints.addElement(new 
 
201
                    Double(m_plot2D.convertToAttribY(e.getY())));
 
202
                  
 
203
                  m_newMousePos.width = e.getX();
 
204
                  m_newMousePos.height = e.getY();
 
205
                  g.drawLine((int)Math.ceil
 
206
                             (m_plot2D.convertToPanelX
 
207
                              (((Double)m_shapePoints.
 
208
                                elementAt(m_shapePoints.size() - 2)).
 
209
                               doubleValue())),
 
210
                             
 
211
                             (int)Math.ceil
 
212
                             (m_plot2D.convertToPanelY
 
213
                              (((Double)m_shapePoints.
 
214
                                elementAt(m_shapePoints.size() - 1)).
 
215
                               doubleValue())),
 
216
                             m_newMousePos.width, m_newMousePos.height);
 
217
                  
 
218
                }
 
219
                else if (m_sIndex == 3) {
 
220
                  //then extend the lines to infinity 
 
221
                  //(100000 or so should be enough).
 
222
                  //the area is selected by where the user right clicks 
 
223
                  //the mouse button
 
224
                  
 
225
                  m_createShape = false;
 
226
                  if (m_shapePoints.size() >= 5) {
 
227
                    double cx = Math.ceil
 
228
                      (m_plot2D.convertToPanelX
 
229
                       (((Double)m_shapePoints.elementAt
 
230
                         (m_shapePoints.size() - 4)).doubleValue()));
 
231
                    
 
232
                    double cx2 = Math.ceil
 
233
                      (m_plot2D.convertToPanelX
 
234
                       (((Double)m_shapePoints.elementAt
 
235
                         (m_shapePoints.size() - 2)).doubleValue())) - 
 
236
                      cx;
 
237
                    
 
238
                    cx2 *= 50000;
 
239
                    
 
240
                    double cy = Math.ceil
 
241
                      (m_plot2D.
 
242
                       convertToPanelY(((Double)m_shapePoints.
 
243
                                        elementAt(m_shapePoints.size() - 3)).
 
244
                                       doubleValue()));
 
245
                    double cy2 = Math.ceil
 
246
                      (m_plot2D.convertToPanelY(((Double)m_shapePoints.
 
247
                                          elementAt(m_shapePoints.size() - 1)).
 
248
                                          doubleValue())) - cy;
 
249
                    cy2 *= 50000;
 
250
                            
 
251
                    
 
252
                    double cxa = Math.ceil(m_plot2D.convertToPanelX
 
253
                                           (((Double)m_shapePoints.
 
254
                                             elementAt(3)).
 
255
                                            doubleValue()));
 
256
                    double cxa2 = Math.ceil(m_plot2D.convertToPanelX
 
257
                                            (((Double)m_shapePoints.
 
258
                                              elementAt(1)).
 
259
                                             doubleValue())) - cxa;
 
260
                    cxa2 *= 50000;
 
261
                    
 
262
                    
 
263
                    double cya = Math.ceil
 
264
                      (m_plot2D.convertToPanelY
 
265
                       (((Double)m_shapePoints.elementAt(4)).
 
266
                        doubleValue()));
 
267
                    double cya2 = Math.ceil
 
268
                      (m_plot2D.convertToPanelY
 
269
                       (((Double)m_shapePoints.elementAt(2)).
 
270
                        doubleValue())) - cya;
 
271
                    
 
272
                    cya2 *= 50000;
 
273
                    
 
274
                    m_shapePoints.setElementAt
 
275
                      (new Double(m_plot2D.convertToAttribX(cxa2 + cxa)), 1);
 
276
                    
 
277
                    m_shapePoints.setElementAt
 
278
                      (new Double(m_plot2D.convertToAttribY(cy2 + cy)), 
 
279
                       m_shapePoints.size() - 1);
 
280
                    
 
281
                    m_shapePoints.setElementAt
 
282
                      (new Double(m_plot2D.convertToAttribX(cx2 + cx)), 
 
283
                       m_shapePoints.size() - 2);
 
284
                    
 
285
                    m_shapePoints.setElementAt
 
286
                      (new Double(m_plot2D.convertToAttribY(cya2 + cya)), 2);
 
287
                    
 
288
                    
 
289
                    //determine how infinity line should be built
 
290
                    
 
291
                    cy = Double.POSITIVE_INFINITY;
 
292
                    cy2 = Double.NEGATIVE_INFINITY;
 
293
                    if (((Double)m_shapePoints.elementAt(1)).
 
294
                        doubleValue() > 
 
295
                        ((Double)m_shapePoints.elementAt(3)).
 
296
                        doubleValue()) {
 
297
                      if (((Double)m_shapePoints.elementAt(2)).
 
298
                          doubleValue() == 
 
299
                          ((Double)m_shapePoints.elementAt(4)).
 
300
                          doubleValue()) {
 
301
                        cy = ((Double)m_shapePoints.elementAt(2)).
 
302
                          doubleValue();
 
303
                      }
 
304
                    }
 
305
                    if (((Double)m_shapePoints.elementAt
 
306
                         (m_shapePoints.size() - 2)).doubleValue() > 
 
307
                        ((Double)m_shapePoints.elementAt
 
308
                         (m_shapePoints.size() - 4)).doubleValue()) {
 
309
                      if (((Double)m_shapePoints.elementAt
 
310
                           (m_shapePoints.size() - 3)).
 
311
                          doubleValue() == 
 
312
                          ((Double)m_shapePoints.elementAt
 
313
                           (m_shapePoints.size() - 1)).doubleValue()) {
 
314
                        cy2 = ((Double)m_shapePoints.lastElement()).
 
315
                          doubleValue();
 
316
                      }
 
317
                    }
 
318
                    m_shapePoints.addElement(new Double(cy));
 
319
                    m_shapePoints.addElement(new Double(cy2));
 
320
                    
 
321
                    if (!inPolyline(m_shapePoints, m_plot2D.convertToAttribX
 
322
                                    (e.getX()), 
 
323
                                    m_plot2D.convertToAttribY(e.getY()))) {
 
324
                      Double tmp = (Double)m_shapePoints.
 
325
                        elementAt(m_shapePoints.size() - 2);
 
326
                      m_shapePoints.setElementAt
 
327
                        (m_shapePoints.lastElement(), 
 
328
                         m_shapePoints.size() - 2);
 
329
                      m_shapePoints.setElementAt
 
330
                        (tmp, m_shapePoints.size() - 1);
 
331
                    }
 
332
                    
 
333
                    if (m_shapes == null) {
 
334
                      m_shapes = new FastVector(4);
 
335
                    }
 
336
                    m_shapes.addElement(m_shapePoints);
 
337
 
 
338
                    m_submit.setText("Submit");
 
339
                    m_submit.setActionCommand("Submit");
 
340
                    
 
341
                    m_submit.setEnabled(true);
 
342
                  }
 
343
                  
 
344
                  m_shapePoints = null;
 
345
                  PlotPanel.this.repaint();
 
346
                  
 
347
                }
 
348
                else {
 
349
                  //then close the shape
 
350
                  m_createShape = false;
 
351
                  if (m_shapePoints.size() >= 7) {
 
352
                    m_shapePoints.addElement(m_shapePoints.elementAt(1));
 
353
                    m_shapePoints.addElement(m_shapePoints.elementAt(2));
 
354
                    if (m_shapes == null) {
 
355
                      m_shapes = new FastVector(4);
 
356
                    }
 
357
                    m_shapes.addElement(m_shapePoints);
 
358
                           
 
359
                    m_submit.setText("Submit");
 
360
                    m_submit.setActionCommand("Submit");
 
361
                    
 
362
                    m_submit.setEnabled(true);
 
363
                  }
 
364
                  m_shapePoints = null;
 
365
                  PlotPanel.this.repaint();
 
366
                }
 
367
                g.dispose();
 
368
                //repaint();
 
369
              }
 
370
              else if ((e.getModifiers() & MouseEvent.BUTTON1_MASK) == MouseEvent.BUTTON1_MASK) {
 
371
                //then this is the first point
 
372
                m_createShape = true;
 
373
                m_shapePoints = new FastVector(17);
 
374
                m_shapePoints.addElement(new Double(m_sIndex));
 
375
                m_shapePoints.addElement(new 
 
376
                  Double(m_plot2D.convertToAttribX(e.getX()))); //the new point
 
377
                m_shapePoints.addElement(new 
 
378
                  Double(m_plot2D.convertToAttribY(e.getY())));
 
379
                m_newMousePos.width = e.getX();      //the temp mouse point
 
380
                m_newMousePos.height = e.getY();
 
381
 
 
382
                Graphics g = m_plot2D.getGraphics();
 
383
                g.setColor(Color.black);
 
384
                g.setXORMode(Color.white);
 
385
                g.drawLine((int)Math.ceil
 
386
                           (m_plot2D.convertToPanelX(((Double)m_shapePoints.
 
387
                                             elementAt(1)).doubleValue())),
 
388
                           (int)Math.ceil
 
389
                           (m_plot2D.convertToPanelY(((Double)m_shapePoints.
 
390
                                             elementAt(2)).doubleValue())),
 
391
                           m_newMousePos.width, m_newMousePos.height);
 
392
                g.dispose();
 
393
              }
 
394
            }
 
395
            else {
 
396
              if ((e.getModifiers() & InputEvent.BUTTON1_MASK) == 
 
397
                  InputEvent.BUTTON1_MASK) {
 
398
                
 
399
                m_plot2D.searchPoints(e.getX(),e.getY(), false);
 
400
              } else {
 
401
                m_plot2D.searchPoints(e.getX(), e.getY(), true);
 
402
              }
 
403
            }
 
404
          }
 
405
          
 
406
          /////////             
 
407
          public void mouseReleased(MouseEvent e) {
 
408
 
 
409
            if (m_createShape) {
 
410
              if (((Double)m_shapePoints.elementAt(0)).intValue() == 1) {
 
411
                m_createShape = false;
 
412
                Graphics g = m_plot2D.getGraphics();
 
413
                g.setColor(Color.black);
 
414
                g.setXORMode(Color.white);
 
415
                g.drawRect(((Double)m_shapePoints.elementAt(1)).
 
416
                           intValue(), 
 
417
                           ((Double)m_shapePoints.elementAt(2)).intValue(),
 
418
                           ((Double)m_shapePoints.elementAt(3)).intValue() -
 
419
                           ((Double)m_shapePoints.elementAt(1)).intValue(), 
 
420
                           ((Double)m_shapePoints.elementAt(4)).intValue() -
 
421
                           ((Double)m_shapePoints.elementAt(2)).intValue());
 
422
                
 
423
                g.dispose();
 
424
                if (checkPoints(((Double)m_shapePoints.elementAt(1)).
 
425
                                doubleValue(), 
 
426
                                ((Double)m_shapePoints.elementAt(2)).
 
427
                                doubleValue()) &&
 
428
                    checkPoints(((Double)m_shapePoints.elementAt(3)).
 
429
                                doubleValue(), 
 
430
                                ((Double)m_shapePoints.elementAt(4)).
 
431
                                doubleValue())) {
 
432
                  //then the points all land on the screen
 
433
                  //now do special check for the rectangle
 
434
                  if (((Double)m_shapePoints.elementAt(1)).doubleValue() <
 
435
                      ((Double)m_shapePoints.elementAt(3)).doubleValue() 
 
436
                      &&
 
437
                      ((Double)m_shapePoints.elementAt(2)).doubleValue() <
 
438
                      ((Double)m_shapePoints.elementAt(4)).doubleValue()) {
 
439
                    //then the rectangle is valid
 
440
                    if (m_shapes == null) {
 
441
                      m_shapes = new FastVector(2);
 
442
                    }
 
443
                    m_shapePoints.setElementAt(new 
 
444
                      Double(m_plot2D.convertToAttribX(((Double)m_shapePoints.
 
445
                                               elementAt(1)).
 
446
                                              doubleValue())), 1);
 
447
                    m_shapePoints.setElementAt(new 
 
448
                      Double(m_plot2D.convertToAttribY(((Double)m_shapePoints.
 
449
                                               elementAt(2)).
 
450
                                              doubleValue())), 2);
 
451
                    m_shapePoints.setElementAt(new 
 
452
                      Double(m_plot2D.convertToAttribX(((Double)m_shapePoints.
 
453
                                               elementAt(3)).
 
454
                                              doubleValue())), 3);
 
455
                    m_shapePoints.setElementAt(new 
 
456
                      Double(m_plot2D.convertToAttribY(((Double)m_shapePoints.
 
457
                                               elementAt(4)).
 
458
                                              doubleValue())), 4);
 
459
                    
 
460
                    m_shapes.addElement(m_shapePoints);
 
461
                    
 
462
                    m_submit.setText("Submit");
 
463
                    m_submit.setActionCommand("Submit");
 
464
                    
 
465
                    m_submit.setEnabled(true);
 
466
 
 
467
                    PlotPanel.this.repaint();
 
468
                  }
 
469
                }
 
470
                m_shapePoints = null;
 
471
              }
 
472
            }
 
473
          }
 
474
        });
 
475
      
 
476
      this.addMouseMotionListener(new MouseMotionAdapter() {
 
477
          public void mouseDragged(MouseEvent e) {
 
478
            //check if the user is dragging a box
 
479
            if (m_createShape) {
 
480
              if (((Double)m_shapePoints.elementAt(0)).intValue() == 1) {
 
481
                Graphics g = m_plot2D.getGraphics();
 
482
                g.setColor(Color.black);
 
483
                g.setXORMode(Color.white);
 
484
                g.drawRect(((Double)m_shapePoints.elementAt(1)).intValue(), 
 
485
                           ((Double)m_shapePoints.elementAt(2)).intValue(),
 
486
                           ((Double)m_shapePoints.elementAt(3)).intValue() -
 
487
                           ((Double)m_shapePoints.elementAt(1)).intValue(), 
 
488
                           ((Double)m_shapePoints.elementAt(4)).intValue() -
 
489
                           ((Double)m_shapePoints.elementAt(2)).intValue());
 
490
                
 
491
                m_shapePoints.setElementAt(new Double(e.getX()), 3);
 
492
                m_shapePoints.setElementAt(new Double(e.getY()), 4);
 
493
                
 
494
                g.drawRect(((Double)m_shapePoints.elementAt(1)).intValue(), 
 
495
                           ((Double)m_shapePoints.elementAt(2)).intValue(),
 
496
                           ((Double)m_shapePoints.elementAt(3)).intValue() -
 
497
                           ((Double)m_shapePoints.elementAt(1)).intValue(), 
 
498
                           ((Double)m_shapePoints.elementAt(4)).intValue() -
 
499
                           ((Double)m_shapePoints.elementAt(2)).intValue());
 
500
                g.dispose();
 
501
              }
 
502
            }
 
503
          }
 
504
          
 
505
          public void mouseMoved(MouseEvent e) {
 
506
            if (m_createShape) {
 
507
              if (((Double)m_shapePoints.elementAt(0)).intValue() == 2 || 
 
508
                  ((Double)m_shapePoints.elementAt(0)).intValue() == 3) {
 
509
                Graphics g = m_plot2D.getGraphics();
 
510
                g.setColor(Color.black);
 
511
                g.setXORMode(Color.white);
 
512
                g.drawLine((int)Math.ceil(m_plot2D.convertToPanelX
 
513
                                          (((Double)m_shapePoints.elementAt
 
514
                                            (m_shapePoints.size() - 2)).
 
515
                                           doubleValue())),
 
516
                           (int)Math.ceil(m_plot2D.convertToPanelY
 
517
                                          (((Double)m_shapePoints.elementAt
 
518
                                            (m_shapePoints.size() - 1)).
 
519
                                           doubleValue())),
 
520
                           m_newMousePos.width, m_newMousePos.height);
 
521
                
 
522
                m_newMousePos.width = e.getX();
 
523
                m_newMousePos.height = e.getY();
 
524
                
 
525
                g.drawLine((int)Math.ceil(m_plot2D.convertToPanelX
 
526
                                          (((Double)m_shapePoints.elementAt
 
527
                                            (m_shapePoints.size() - 2)).
 
528
                                           doubleValue())),
 
529
                           (int)Math.ceil(m_plot2D.convertToPanelY
 
530
                                          (((Double)m_shapePoints.elementAt
 
531
                                            (m_shapePoints.size() - 1)).
 
532
                                           doubleValue())),
 
533
                           m_newMousePos.width, m_newMousePos.height);
 
534
                g.dispose();
 
535
              }
 
536
            }
 
537
          }
 
538
        });
 
539
      
 
540
      m_submit.addActionListener(new ActionListener() {
 
541
          public void actionPerformed(ActionEvent e) {
 
542
         
 
543
            if (e.getActionCommand().equals("Submit")) {
 
544
              if (m_splitListener != null && m_shapes != null) {
 
545
                //then send the split to the listener
 
546
                Instances sub_set1 = new Instances(m_plot2D.getMasterPlot().
 
547
                                                   m_plotInstances, 500);
 
548
                Instances sub_set2 = new Instances(m_plot2D.getMasterPlot().
 
549
                                                   m_plotInstances, 500);
 
550
                
 
551
                if (m_plot2D.getMasterPlot().
 
552
                    m_plotInstances != null) {
 
553
                  
 
554
                  for (int noa = 0 ; noa < m_plot2D.getMasterPlot().
 
555
                         m_plotInstances.numInstances(); noa++) {
 
556
                    if (!m_plot2D.getMasterPlot().
 
557
                        m_plotInstances.instance(noa).isMissing(m_xIndex) &&
 
558
                        !m_plot2D.getMasterPlot().
 
559
                        m_plotInstances.instance(noa).isMissing(m_yIndex)){
 
560
                      
 
561
                      if (inSplit(m_plot2D.getMasterPlot().
 
562
                                  m_plotInstances.instance(noa))) {
 
563
                        sub_set1.add(m_plot2D.getMasterPlot().
 
564
                                     m_plotInstances.instance(noa));
 
565
                      }
 
566
                      else {
 
567
                        sub_set2.add(m_plot2D.getMasterPlot().
 
568
                                     m_plotInstances.instance(noa));
 
569
                      }
 
570
                    }
 
571
                  }
 
572
                  FastVector tmp = m_shapes;
 
573
                  cancelShapes();
 
574
                  m_splitListener.userDataEvent(new 
 
575
                    VisualizePanelEvent(tmp, sub_set1, sub_set2, m_xIndex, 
 
576
                                        m_yIndex));
 
577
                }
 
578
              }
 
579
              else if (m_shapes != null && 
 
580
                       m_plot2D.getMasterPlot().m_plotInstances != null) { 
 
581
                Instances sub_set1 = new Instances(m_plot2D.getMasterPlot().
 
582
                                                   m_plotInstances, 500);
 
583
                int count = 0;
 
584
                for (int noa = 0 ; noa < m_plot2D.getMasterPlot().
 
585
                       m_plotInstances.numInstances(); noa++) {
 
586
                  if (inSplit(m_plot2D.getMasterPlot().
 
587
                              m_plotInstances.instance(noa))) {
 
588
                    sub_set1.add(m_plot2D.getMasterPlot().
 
589
                                 m_plotInstances.instance(noa));
 
590
                    count++;
 
591
                  }
 
592
                  
 
593
                }
 
594
 
 
595
                int [] nSizes = null;
 
596
                int [] nTypes = null;
 
597
                int x = m_xIndex;
 
598
                int y = m_yIndex;
 
599
 
 
600
                if (m_originalPlot == null) {
 
601
                  //this sets these instances as the instances 
 
602
                  //to go back to.
 
603
                  m_originalPlot = m_plot2D.getMasterPlot();
 
604
                }
 
605
 
 
606
                if (count > 0) {
 
607
                  nTypes = new int[count];
 
608
                  nSizes = new int[count];
 
609
                  count = 0;
 
610
                  for (int noa = 0; noa < m_plot2D.getMasterPlot().
 
611
                         m_plotInstances.numInstances(); 
 
612
                       noa++) {
 
613
                    if (inSplit(m_plot2D.getMasterPlot().
 
614
                                m_plotInstances.instance(noa))) {
 
615
 
 
616
                      nTypes[count] = m_plot2D.getMasterPlot().
 
617
                        m_shapeType[noa];
 
618
                      nSizes[count] = m_plot2D.getMasterPlot().
 
619
                        m_shapeSize[noa];
 
620
                      count++;
 
621
                    }
 
622
                  }
 
623
                }
 
624
                cancelShapes();
 
625
 
 
626
                PlotData2D newPlot = new PlotData2D(sub_set1);
 
627
 
 
628
                try {
 
629
                  newPlot.setShapeSize(nSizes);
 
630
                  newPlot.setShapeType(nTypes);
 
631
                
 
632
                  m_plot2D.removeAllPlots();
 
633
                  
 
634
                  VisualizePanel.this.addPlot(newPlot);
 
635
                } catch (Exception ex) {
 
636
                  System.err.println(ex);
 
637
                  ex.printStackTrace();
 
638
                }
 
639
 
 
640
                try {
 
641
                  VisualizePanel.this.setXIndex(x);
 
642
                  VisualizePanel.this.setYIndex(y);
 
643
                } catch(Exception er) {
 
644
                  System.out.println("Error : " + er);
 
645
                  //  System.out.println("Part of user input so had to" +
 
646
                  //             " catch here");
 
647
                }
 
648
              }
 
649
            }
 
650
            else if (e.getActionCommand().equals("Reset")) {
 
651
              int x = m_xIndex;
 
652
              int y = m_yIndex;
 
653
 
 
654
              m_plot2D.removeAllPlots();
 
655
              try {
 
656
                VisualizePanel.this.addPlot(m_originalPlot);
 
657
              } catch (Exception ex) {
 
658
                System.err.println(ex);
 
659
                ex.printStackTrace();
 
660
              }
 
661
 
 
662
              try {
 
663
                VisualizePanel.this.setXIndex(x);
 
664
                VisualizePanel.this.setYIndex(y);
 
665
              } catch(Exception er) {
 
666
                System.out.println("Error : " + er);
 
667
              }
 
668
            }
 
669
          }  
 
670
        });
 
671
 
 
672
      m_cancel.addActionListener(new ActionListener() {
 
673
          public void actionPerformed(ActionEvent e) {
 
674
            cancelShapes();
 
675
            PlotPanel.this.repaint();
 
676
          }
 
677
        });
 
678
      ////////////
 
679
    }
 
680
    
 
681
    /**
 
682
     * @return The FastVector containing all the shapes.
 
683
     */
 
684
    public FastVector getShapes() {
 
685
      
 
686
      return m_shapes;
 
687
    }
 
688
    
 
689
    /**
 
690
     * Sets the list of shapes to empty and also cancels
 
691
     * the current shape being drawn (if applicable).
 
692
     */
 
693
    public void cancelShapes() {
 
694
       
 
695
      if (m_splitListener == null) {
 
696
        m_submit.setText("Reset");
 
697
        m_submit.setActionCommand("Reset");
 
698
 
 
699
        if (m_originalPlot == null || 
 
700
            m_originalPlot.m_plotInstances == m_plotInstances) {
 
701
          m_submit.setEnabled(false);
 
702
        }
 
703
        else {
 
704
          m_submit.setEnabled(true);
 
705
        }
 
706
      }
 
707
      else {
 
708
        m_submit.setEnabled(false);
 
709
      }
 
710
      
 
711
      m_createShape = false;
 
712
      m_shapePoints = null;
 
713
      m_shapes = null;
 
714
      this.repaint();
 
715
    }
 
716
 
 
717
    /**
 
718
     * This can be used to set the shapes that should appear.
 
719
     * @param v The list of shapes.
 
720
     */
 
721
    public void setShapes(FastVector v) {
 
722
      //note that this method should be fine for doubles,
 
723
      //but anything else that uses something other than doubles 
 
724
      //(or uneditable objects) could have unsafe copies.
 
725
      if (v != null) {
 
726
        FastVector temp;
 
727
        m_shapes = new FastVector(v.size());
 
728
        for (int noa = 0; noa < v.size(); noa++) {
 
729
          temp = new FastVector(((FastVector)v.elementAt(noa)).size());
 
730
          m_shapes.addElement(temp);
 
731
          for (int nob = 0; nob < ((FastVector)v.elementAt(noa)).size()
 
732
                 ; nob++) {
 
733
            
 
734
            temp.addElement(((FastVector)v.elementAt(noa)).elementAt(nob));
 
735
            
 
736
          }
 
737
        }
 
738
      }
 
739
      else {
 
740
        m_shapes = null;
 
741
      }
 
742
      this.repaint();
 
743
    }
 
744
    
 
745
    /** 
 
746
     * This will check the values of the screen points passed and make sure 
 
747
     * that they land on the screen
 
748
     * @param x1 The x coord.
 
749
     * @param y1 The y coord.
 
750
     * @return true if the point would land on the screen
 
751
     */
 
752
    private boolean checkPoints(double x1, double y1) {
 
753
      if (x1 < 0 || x1 > this.getSize().width || y1 < 0 
 
754
          || y1 > this.getSize().height) {
 
755
        return false;
 
756
      }
 
757
      return true;
 
758
    }
 
759
    
 
760
    /**
 
761
     * This will check if an instance is inside or outside of the current
 
762
     * shapes.
 
763
     * @param i The instance to check.
 
764
     * @return True if 'i' falls inside the shapes, false otherwise.
 
765
     */
 
766
    public boolean inSplit(Instance i) {
 
767
      //this will check if the instance lies inside the shapes or not
 
768
      
 
769
      if (m_shapes != null) {
 
770
        FastVector stmp;
 
771
        double x1, y1, x2, y2;
 
772
        for (int noa = 0; noa < m_shapes.size(); noa++) {
 
773
          stmp = (FastVector)m_shapes.elementAt(noa);
 
774
          if (((Double)stmp.elementAt(0)).intValue() == 1) {
 
775
            //then rectangle
 
776
            x1 = ((Double)stmp.elementAt(1)).doubleValue();
 
777
            y1 = ((Double)stmp.elementAt(2)).doubleValue();
 
778
            x2 = ((Double)stmp.elementAt(3)).doubleValue();
 
779
            y2 = ((Double)stmp.elementAt(4)).doubleValue();
 
780
            if (i.value(m_xIndex) >= x1 && i.value(m_xIndex) <= x2 &&
 
781
                i.value(m_yIndex) <= y1 && i.value(m_yIndex) >= y2) {
 
782
              //then is inside split so return true;
 
783
              return true;
 
784
            }
 
785
          }
 
786
          else if (((Double)stmp.elementAt(0)).intValue() == 2) {
 
787
            //then polygon
 
788
            if (inPoly(stmp, i.value(m_xIndex), i.value(m_yIndex))) {
 
789
              return true;
 
790
            }
 
791
          }
 
792
          else if (((Double)stmp.elementAt(0)).intValue() == 3) {
 
793
            //then polyline
 
794
            if (inPolyline(stmp, i.value(m_xIndex), i.value(m_yIndex))) {
 
795
              return true;
 
796
            }
 
797
          }
 
798
        }
 
799
      }
 
800
      return false;
 
801
    }
 
802
    
 
803
    /**
 
804
     * Checks to see if the coordinate passed is inside the ployline
 
805
     * passed, Note that this is done using attribute values and not there
 
806
     * respective screen values.
 
807
     * @param ob The polyline.
 
808
     * @param x The x coord.
 
809
     * @param y The y coord.
 
810
     * @return True if it falls inside the polyline, false otherwise.
 
811
     */
 
812
    private boolean inPolyline(FastVector ob, double x, double y) {
 
813
      //this works similar to the inPoly below except that
 
814
      //the first and last lines are treated as extending infinite in one 
 
815
      //direction and 
 
816
      //then infinitly in the x dirction their is a line that will 
 
817
      //normaly be infinite but
 
818
      //can be finite in one or both directions
 
819
      
 
820
      int countx = 0;
 
821
      double vecx, vecy;
 
822
      double change;
 
823
      double x1, y1, x2, y2;
 
824
      
 
825
      for (int noa = 1; noa < ob.size() - 4; noa+= 2) {
 
826
        y1 = ((Double)ob.elementAt(noa+1)).doubleValue();
 
827
        y2 = ((Double)ob.elementAt(noa+3)).doubleValue();
 
828
        x1 = ((Double)ob.elementAt(noa)).doubleValue();
 
829
        x2 = ((Double)ob.elementAt(noa+2)).doubleValue();
 
830
        
 
831
        //System.err.println(y1 + " " + y2 + " " + x1 + " " + x2);
 
832
        vecy = y2 - y1;
 
833
        vecx = x2 - x1;
 
834
        if (noa == 1 && noa == ob.size() - 6) {
 
835
          //then do special test first and last edge
 
836
          if (vecy != 0) {
 
837
            change = (y - y1) / vecy;
 
838
            if (vecx * change + x1 >= x) {
 
839
              //then intersection
 
840
              countx++;
 
841
            }
 
842
          }
 
843
        }
 
844
        else if (noa == 1) {
 
845
          if ((y < y2 && vecy > 0) || (y > y2 && vecy < 0)) {
 
846
            //now just determine intersection or not
 
847
            change = (y - y1) / vecy;
 
848
            if (vecx * change + x1 >= x) {
 
849
              //then intersection on horiz
 
850
              countx++;
 
851
            }
 
852
          }
 
853
        }
 
854
        else if (noa == ob.size() - 6) {
 
855
          //then do special test on last edge
 
856
          if ((y <= y1 && vecy < 0) || (y >= y1 && vecy > 0)) {
 
857
            change = (y - y1) / vecy;
 
858
            if (vecx * change + x1 >= x) {
 
859
              countx++;
 
860
            }
 
861
          }
 
862
        }
 
863
        else if ((y1 <= y && y < y2) || (y2 < y && y <= y1)) {
 
864
          //then continue tests.
 
865
          if (vecy == 0) {
 
866
            //then lines are parallel stop tests in 
 
867
            //ofcourse it should never make it this far
 
868
          }
 
869
          else {
 
870
            change = (y - y1) / vecy;
 
871
            if (vecx * change + x1 >= x) {
 
872
              //then intersects on horiz
 
873
              countx++;
 
874
            }
 
875
          }
 
876
        }
 
877
      }
 
878
      
 
879
      //now check for intersection with the infinity line
 
880
      y1 = ((Double)ob.elementAt(ob.size() - 2)).doubleValue();
 
881
      y2 = ((Double)ob.elementAt(ob.size() - 1)).doubleValue();
 
882
      
 
883
      if (y1 > y2) {
 
884
        //then normal line
 
885
        if (y1 >= y && y > y2) {
 
886
          countx++;
 
887
        }
 
888
      }
 
889
      else {
 
890
        //then the line segment is inverted
 
891
        if (y1 >= y || y > y2) {
 
892
          countx++;
 
893
        }
 
894
      }
 
895
      
 
896
      if ((countx % 2) == 1) {
 
897
        return true;
 
898
      }
 
899
      else {
 
900
        return false;
 
901
      }
 
902
    }
 
903
 
 
904
 
 
905
    /**
 
906
     * This checks to see if The coordinate passed is inside
 
907
     * the polygon that was passed.
 
908
     * @param ob The polygon.
 
909
     * @param x The x coord.
 
910
     * @param y The y coord.
 
911
     * @return True if the coordinate is in the polygon, false otherwise.
 
912
     */
 
913
    private boolean inPoly(FastVector ob, double x, double y) {
 
914
      //brief on how this works
 
915
      //it draws a line horizontally from the point to the right (infinitly)
 
916
      //it then sees how many lines of the polygon intersect this, 
 
917
      //if it is even then the point is
 
918
      // outside the polygon if it's odd then it's inside the polygon
 
919
      int count = 0;
 
920
      double vecx, vecy;
 
921
      double change;
 
922
      double x1, y1, x2, y2;
 
923
      for (int noa = 1; noa < ob.size() - 2; noa += 2) {
 
924
        y1 = ((Double)ob.elementAt(noa+1)).doubleValue();
 
925
        y2 = ((Double)ob.elementAt(noa+3)).doubleValue();
 
926
        if ((y1 <= y && y < y2) || (y2 < y && y <= y1)) {
 
927
          //then continue tests.
 
928
          vecy = y2 - y1;
 
929
          if (vecy == 0) {
 
930
            //then lines are parallel stop tests for this line
 
931
          }
 
932
          else {
 
933
            x1 = ((Double)ob.elementAt(noa)).doubleValue();
 
934
            x2 = ((Double)ob.elementAt(noa+2)).doubleValue();
 
935
            vecx = x2 - x1;
 
936
            change = (y - y1) / vecy;
 
937
            if (vecx * change + x1 >= x) {
 
938
              //then add to count as an intersected line
 
939
              count++;
 
940
            }
 
941
          }
 
942
        }
 
943
      }
 
944
      if ((count % 2) == 1) {
 
945
        //then lies inside polygon
 
946
        //System.out.println("in");
 
947
        return true;
 
948
      }
 
949
      else {
 
950
        //System.out.println("out");
 
951
        return false;
 
952
      }
 
953
      //System.out.println("WHAT?!?!?!?!!?!??!?!");
 
954
      //return false;
 
955
    }
 
956
 
 
957
    /**
 
958
     * Set level of jitter and repaint the plot using the new jitter value
 
959
     * @param j the level of jitter
 
960
     */
 
961
    public void setJitter(int j) {
 
962
      m_plot2D.setJitter(j);
 
963
    }
 
964
 
 
965
    /**
 
966
     * Set the index of the attribute to go on the x axis
 
967
     * @param x the index of the attribute to use on the x axis
 
968
     */
 
969
    public void setXindex(int x) {
 
970
 
 
971
      // this just ensures that the shapes get disposed of 
 
972
      //if the attribs change
 
973
      if (x != m_xIndex) {
 
974
        cancelShapes();
 
975
      }
 
976
      m_xIndex = x;
 
977
      m_plot2D.setXindex(x);
 
978
      if (m_showAttBars) {
 
979
        m_attrib.setX(x);
 
980
      }
 
981
      //      this.repaint();
 
982
    }
 
983
    
 
984
    /**
 
985
     * Set the index of the attribute to go on the y axis
 
986
     * @param y the index of the attribute to use on the y axis
 
987
     */
 
988
    public void setYindex(int y) {
 
989
    
 
990
      // this just ensures that the shapes get disposed of 
 
991
      //if the attribs change
 
992
      if (y != m_yIndex) {
 
993
        cancelShapes();
 
994
      }
 
995
      m_yIndex = y;
 
996
      m_plot2D.setYindex(y);
 
997
      if (m_showAttBars) {
 
998
        m_attrib.setY(y);
 
999
      }
 
1000
      //      this.repaint();
 
1001
    }
 
1002
 
 
1003
    /**
 
1004
     * Set the index of the attribute to use for colouring
 
1005
     * @param c the index of the attribute to use for colouring
 
1006
     */
 
1007
    public void setCindex(int c) {
 
1008
      m_cIndex = c;
 
1009
      m_plot2D.setCindex(c);
 
1010
      if (m_showAttBars) {
 
1011
        m_attrib.setCindex(c, m_plot2D.getMaxC(), m_plot2D.getMinC());
 
1012
      }
 
1013
      m_classPanel.setCindex(c);
 
1014
      this.repaint();
 
1015
    }
 
1016
 
 
1017
    /**
 
1018
     * Set the index of the attribute to use for the shape.
 
1019
     * @param s the index of the attribute to use for the shape
 
1020
     */
 
1021
    public void setSindex(int s) {
 
1022
      if (s != m_sIndex) {
 
1023
        m_shapePoints = null;
 
1024
        m_createShape = false;
 
1025
      }
 
1026
      m_sIndex = s;
 
1027
      this.repaint();
 
1028
    }
 
1029
 
 
1030
    /**
 
1031
     * Clears all existing plots and sets a new master plot
 
1032
     * @param newPlot the new master plot
 
1033
     * @exception Exception if plot could not be added
 
1034
     */
 
1035
    public void setMasterPlot(PlotData2D newPlot) throws Exception {
 
1036
      m_plot2D.removeAllPlots();
 
1037
      this.addPlot(newPlot);
 
1038
    }
 
1039
 
 
1040
    /**
 
1041
     * Adds a plot. If there are no plots so far this plot becomes
 
1042
     * the master plot and, if it has a custom colour defined then
 
1043
     * the class panel is removed.
 
1044
     * @param newPlot the plot to add.
 
1045
     * @exception Exception if plot could not be added
 
1046
     */
 
1047
    public void addPlot(PlotData2D newPlot) throws Exception {
 
1048
      if (m_plot2D.getPlots().size() == 0) {
 
1049
        m_plot2D.addPlot(newPlot);
 
1050
        if (m_plotSurround.getComponentCount() > 1 && 
 
1051
            m_plotSurround.getComponent(1) == m_attrib &&
 
1052
            m_showAttBars) {
 
1053
          try {
 
1054
            m_attrib.setInstances(newPlot.m_plotInstances);
 
1055
            m_attrib.setCindex(0);m_attrib.setX(0); m_attrib.setY(0);
 
1056
          } catch (Exception ex) {
 
1057
            // more attributes than the panel can handle?
 
1058
            // Due to hard coded constraints in GridBagLayout
 
1059
            m_plotSurround.remove(m_attrib);
 
1060
            System.err.println("Warning : data contains more attributes "
 
1061
                               +"than can be displayed as attribute bars.");
 
1062
            if (m_Log != null) {
 
1063
              m_Log.logMessage("Warning : data contains more attributes "
 
1064
                               +"than can be displayed as attribute bars.");
 
1065
            }
 
1066
          }
 
1067
        } else if (m_showAttBars) {
 
1068
          try {
 
1069
            m_attrib.setInstances(newPlot.m_plotInstances);
 
1070
            m_attrib.setCindex(0);m_attrib.setX(0); m_attrib.setY(0);
 
1071
            GridBagConstraints constraints = new GridBagConstraints();
 
1072
            constraints.fill = GridBagConstraints.BOTH;
 
1073
            constraints.insets = new Insets(0, 0, 0, 0);
 
1074
            constraints.gridx=4;constraints.gridy=0;constraints.weightx=1;
 
1075
            constraints.gridwidth=1;constraints.gridheight=1;
 
1076
            constraints.weighty=5;
 
1077
            m_plotSurround.add(m_attrib, constraints);
 
1078
          } catch (Exception ex) {
 
1079
            System.err.println("Warning : data contains more attributes "
 
1080
                               +"than can be displayed as attribute bars.");
 
1081
            if (m_Log != null) {
 
1082
              m_Log.logMessage("Warning : data contains more attributes "
 
1083
                               +"than can be displayed as attribute bars.");
 
1084
            }
 
1085
          }
 
1086
        }
 
1087
        m_classPanel.setInstances(newPlot.m_plotInstances);
 
1088
 
 
1089
        plotReset(newPlot.m_plotInstances, newPlot.getCindex());
 
1090
        if (newPlot.m_useCustomColour) {
 
1091
          VisualizePanel.this.remove(m_classSurround);
 
1092
          switchToLegend();
 
1093
          m_legendPanel.setPlotList(m_plot2D.getPlots());
 
1094
          m_ColourCombo.setEnabled(false);
 
1095
        }
 
1096
      } else  {
 
1097
        if (!newPlot.m_useCustomColour) {
 
1098
          VisualizePanel.this.add(m_classSurround, BorderLayout.SOUTH);
 
1099
          m_ColourCombo.setEnabled(true);
 
1100
        }
 
1101
        if (m_plot2D.getPlots().size() == 1) {
 
1102
          switchToLegend();
 
1103
        }
 
1104
        m_plot2D.addPlot(newPlot);
 
1105
        m_legendPanel.setPlotList(m_plot2D.getPlots());
 
1106
      }
 
1107
    }
 
1108
 
 
1109
    /**
 
1110
     * Remove the attibute panel and replace it with the legend panel
 
1111
     */
 
1112
    protected void switchToLegend() {
 
1113
 
 
1114
      if (m_plotSurround.getComponentCount() > 1 && 
 
1115
          m_plotSurround.getComponent(1) == m_attrib) {
 
1116
        m_plotSurround.remove(m_attrib);
 
1117
      }
 
1118
        
 
1119
      if (m_plotSurround.getComponentCount() > 1 &&
 
1120
          m_plotSurround.getComponent(1) == m_legendPanel) {
 
1121
        return;
 
1122
      }
 
1123
 
 
1124
      GridBagConstraints constraints = new GridBagConstraints();
 
1125
      constraints.fill = GridBagConstraints.BOTH;
 
1126
      constraints.insets = new Insets(0, 0, 0, 0);
 
1127
      constraints.gridx=4;constraints.gridy=0;constraints.weightx=1;
 
1128
      constraints.gridwidth=1;constraints.gridheight=1;
 
1129
      constraints.weighty=5;
 
1130
      m_plotSurround.add(m_legendPanel, constraints);
 
1131
      setSindex(0);
 
1132
      m_ShapeCombo.setEnabled(false);
 
1133
    }
 
1134
 
 
1135
    /**
 
1136
     * Reset the visualize panel's buttons and the plot panels instances
 
1137
     * 
 
1138
     * @param inst      the data
 
1139
     * @param cIndex    the color index
 
1140
     */
 
1141
    private void plotReset(Instances inst, int cIndex) {
 
1142
      if (m_splitListener == null) {
 
1143
        m_submit.setText("Reset");
 
1144
        m_submit.setActionCommand("Reset");
 
1145
        //if (m_origInstances == null || m_origInstances == inst) {
 
1146
        if (m_originalPlot == null || m_originalPlot.m_plotInstances == inst) {
 
1147
          m_submit.setEnabled(false);
 
1148
        }
 
1149
        else {
 
1150
          m_submit.setEnabled(true);
 
1151
        }
 
1152
      } 
 
1153
      else {
 
1154
        m_submit.setEnabled(false);
 
1155
      }
 
1156
 
 
1157
      m_plotInstances = inst;
 
1158
      if (m_splitListener != null) {
 
1159
        m_plotInstances.randomize(new Random());
 
1160
      }
 
1161
      m_xIndex=0;
 
1162
      m_yIndex=0;
 
1163
      m_cIndex=cIndex;
 
1164
      cancelShapes();
 
1165
    }
 
1166
 
 
1167
    /**
 
1168
     * Set a list of colours to use for plotting points
 
1169
     * @param cols a list of java.awt.Colors
 
1170
     */
 
1171
    public void setColours(FastVector cols) {
 
1172
      m_plot2D.setColours(cols);
 
1173
      m_colorList = cols;
 
1174
    }
 
1175
    
 
1176
    /**
 
1177
     * This will draw the shapes created onto the panel.
 
1178
     * For best visual, this should be the first thing to be drawn
 
1179
     * (and it currently is).
 
1180
     * @param gx The graphics context.
 
1181
     */
 
1182
    private void drawShapes(Graphics gx) {
 
1183
      //FastVector tmp = m_plot.getShapes();
 
1184
      
 
1185
      if (m_shapes != null) {
 
1186
        FastVector stmp;
 
1187
        int x1, y1, x2, y2;
 
1188
        for (int noa = 0; noa < m_shapes.size(); noa++) {
 
1189
          stmp = (FastVector)m_shapes.elementAt(noa);
 
1190
          if (((Double)stmp.elementAt(0)).intValue() == 1) {
 
1191
            //then rectangle
 
1192
            x1 = (int)m_plot2D.convertToPanelX(((Double)stmp.elementAt(1)).
 
1193
                                      doubleValue());
 
1194
            y1 = (int)m_plot2D.convertToPanelY(((Double)stmp.elementAt(2)).
 
1195
                                      doubleValue());
 
1196
            x2 = (int)m_plot2D.convertToPanelX(((Double)stmp.elementAt(3)).
 
1197
                                      doubleValue());
 
1198
            y2 = (int)m_plot2D.convertToPanelY(((Double)stmp.elementAt(4)).
 
1199
                                      doubleValue());
 
1200
            
 
1201
            gx.setColor(Color.gray);
 
1202
            gx.fillRect(x1, y1, x2 - x1, y2 - y1);
 
1203
            gx.setColor(Color.black);
 
1204
            gx.drawRect(x1, y1, x2 - x1, y2 - y1);
 
1205
            
 
1206
          }
 
1207
          else if (((Double)stmp.elementAt(0)).intValue() == 2) {
 
1208
            //then polygon
 
1209
            int[] ar1, ar2;
 
1210
            ar1 = getXCoords(stmp);
 
1211
            ar2 = getYCoords(stmp);
 
1212
            gx.setColor(Color.gray);
 
1213
            gx.fillPolygon(ar1, ar2, (stmp.size() - 1) / 2); 
 
1214
            gx.setColor(Color.black);
 
1215
            gx.drawPolyline(ar1, ar2, (stmp.size() - 1) / 2);
 
1216
          }
 
1217
          else if (((Double)stmp.elementAt(0)).intValue() == 3) {
 
1218
            //then polyline
 
1219
            int[] ar1, ar2;
 
1220
            FastVector tmp = makePolygon(stmp);
 
1221
            ar1 = getXCoords(tmp);
 
1222
            ar2 = getYCoords(tmp);
 
1223
            
 
1224
            gx.setColor(Color.gray);
 
1225
            gx.fillPolygon(ar1, ar2, (tmp.size() - 1) / 2);
 
1226
            gx.setColor(Color.black);
 
1227
            gx.drawPolyline(ar1, ar2, (tmp.size() - 1) / 2);
 
1228
          }
 
1229
        }
 
1230
      }
 
1231
      
 
1232
      if (m_shapePoints != null) {
 
1233
        //then the current image needs to be refreshed
 
1234
        if (((Double)m_shapePoints.elementAt(0)).intValue() == 2 ||
 
1235
            ((Double)m_shapePoints.elementAt(0)).intValue() == 3) {
 
1236
          gx.setColor(Color.black);
 
1237
          gx.setXORMode(Color.white);
 
1238
          int[] ar1, ar2;
 
1239
          ar1 = getXCoords(m_shapePoints);
 
1240
          ar2 = getYCoords(m_shapePoints);
 
1241
          gx.drawPolyline(ar1, ar2, (m_shapePoints.size() - 1) / 2);
 
1242
          m_newMousePos.width = (int)Math.ceil
 
1243
            (m_plot2D.convertToPanelX(((Double)m_shapePoints.elementAt
 
1244
                              (m_shapePoints.size() - 2)).doubleValue()));
 
1245
          
 
1246
          m_newMousePos.height = (int)Math.ceil
 
1247
            (m_plot2D.convertToPanelY(((Double)m_shapePoints.elementAt
 
1248
                              (m_shapePoints.size() - 1)).doubleValue()));
 
1249
          
 
1250
          gx.drawLine((int)Math.ceil
 
1251
                     (m_plot2D.convertToPanelX(((Double)m_shapePoints.elementAt
 
1252
                                                (m_shapePoints.size() - 2)).
 
1253
                                               doubleValue())),
 
1254
                      (int)Math.ceil(m_plot2D.convertToPanelY
 
1255
                                     (((Double)m_shapePoints.elementAt
 
1256
                                       (m_shapePoints.size() - 1)).
 
1257
                                      doubleValue())),
 
1258
                      m_newMousePos.width, m_newMousePos.height);
 
1259
          gx.setPaintMode();
 
1260
        }
 
1261
      }
 
1262
    }
 
1263
    
 
1264
    /**
 
1265
     * This is called for polylines to see where there two lines that
 
1266
     * extend to infinity cut the border of the view.
 
1267
     * @param x1 an x point along the line
 
1268
     * @param y1 the accompanying y point.
 
1269
     * @param x2 The x coord of the end point of the line.
 
1270
     * @param y2 The y coord of the end point of the line.
 
1271
     * @param x 0 or the width of the border line if it has one.
 
1272
     * @param y 0 or the height of the border line if it has one.
 
1273
     * @param offset The offset for the border line (either for x or y
 
1274
     * dependant on which one doesn't change).
 
1275
     * @return double array that contains the coordinate for the point 
 
1276
     * that the polyline cuts the border (which ever side that may be).
 
1277
     */
 
1278
    private double[] lineIntersect(double x1, double y1, double x2, double y2, 
 
1279
                                   double x, double y, double offset) {
 
1280
      //the first 4 params are thestart and end points of a line
 
1281
      //the next param is either 0 for no change in x or change in x, 
 
1282
      //the next param is the same for y
 
1283
      //the final 1 is the offset for either x or y (which ever has no change)
 
1284
      double xval;
 
1285
      double yval;
 
1286
      double xn = -100, yn = -100;
 
1287
      double change;
 
1288
      if (x == 0) {
 
1289
        if ((x1 <= offset && offset < x2) || (x1 >= offset && offset > x2)) {
 
1290
          //then continue
 
1291
          xval = x1 - x2;
 
1292
          change = (offset - x2) / xval;
 
1293
          yn = (y1 - y2) * change + y2;
 
1294
          if (0 <= yn && yn <= y) {
 
1295
            //then good
 
1296
            xn = offset;
 
1297
          }
 
1298
          else {
 
1299
            //no intersect
 
1300
            xn = -100;
 
1301
          }
 
1302
        }
 
1303
      }
 
1304
      else if (y == 0) {
 
1305
        if ((y1 <= offset && offset < y2) || (y1 >= offset && offset > y2)) {
 
1306
          //the continue
 
1307
          yval = (y1 - y2);
 
1308
          change = (offset - y2) / yval;
 
1309
          xn = (x1 - x2) * change + x2;
 
1310
          if (0 <= xn && xn <= x) {
 
1311
            //then good
 
1312
            yn = offset;
 
1313
          }
 
1314
          else {
 
1315
            xn = -100;
 
1316
          }
 
1317
        }
 
1318
      }
 
1319
      double[] ret = new double[2];
 
1320
      ret[0] = xn;
 
1321
      ret[1] = yn;
 
1322
      return ret;
 
1323
    }
 
1324
 
 
1325
 
 
1326
    /**
 
1327
     * This will convert a polyline to a polygon for drawing purposes
 
1328
     * So that I can simply use the polygon drawing function.
 
1329
     * @param v The polyline to convert.
 
1330
     * @return A FastVector containing the polygon.
 
1331
     */
 
1332
    private FastVector makePolygon(FastVector v) {
 
1333
      FastVector building = new FastVector(v.size() + 10);
 
1334
      double x1, y1, x2, y2;
 
1335
      int edge1 = 0, edge2 = 0;
 
1336
      for (int noa = 0; noa < v.size() - 2; noa++) {
 
1337
        building.addElement(new Double(((Double)v.elementAt(noa)).
 
1338
                                       doubleValue()));
 
1339
      }
 
1340
      
 
1341
      //now clip the lines
 
1342
      double[] new_coords;
 
1343
      //note lineIntersect , expects the values to have been converted to 
 
1344
      //screen coords
 
1345
      //note the first point passed is the one that gets shifted.
 
1346
      x1 = m_plot2D.convertToPanelX(((Double)v.elementAt(1)).doubleValue());
 
1347
      y1 = m_plot2D.convertToPanelY(((Double)v.elementAt(2)).doubleValue());
 
1348
      x2 = m_plot2D.convertToPanelX(((Double)v.elementAt(3)).doubleValue());
 
1349
      y2 = m_plot2D.convertToPanelY(((Double)v.elementAt(4)).doubleValue());
 
1350
 
 
1351
      if (x1 < 0) {
 
1352
        //test left
 
1353
        new_coords = lineIntersect(x1, y1, x2, y2, 0, this.getHeight(), 0);
 
1354
        edge1 = 0;
 
1355
        if (new_coords[0] < 0) {
 
1356
          //then not left
 
1357
          if (y1 < 0) {
 
1358
            //test top
 
1359
            new_coords = lineIntersect(x1, y1, x2, y2, this.getWidth(), 0, 0);
 
1360
            edge1 = 1;
 
1361
          }
 
1362
          else {
 
1363
            //test bottom
 
1364
            new_coords = lineIntersect(x1, y1, x2, y2, this.getWidth(), 0, 
 
1365
                                       this.getHeight());
 
1366
            edge1 = 3;
 
1367
          }
 
1368
        }
 
1369
      }
 
1370
      else if (x1 > this.getWidth()) {
 
1371
        //test right
 
1372
        new_coords = lineIntersect(x1, y1, x2, y2, 0, this.getHeight(), 
 
1373
                                   this.getWidth());
 
1374
        edge1 = 2;
 
1375
        if (new_coords[0] < 0) {
 
1376
          //then not right
 
1377
          if (y1 < 0) {
 
1378
            //test top
 
1379
            new_coords = lineIntersect(x1, y1, x2, y2, this.getWidth(), 0, 0);
 
1380
            edge1 = 1;
 
1381
          }
 
1382
          else {
 
1383
            //test bottom
 
1384
            new_coords = lineIntersect(x1, y1, x2, y2, this.getWidth(), 0, 
 
1385
                                       this.getHeight());
 
1386
            edge1 = 3;
 
1387
          }
 
1388
        }
 
1389
      }
 
1390
      else if (y1 < 0) {
 
1391
        //test top
 
1392
        new_coords = lineIntersect(x1, y1, x2, y2, this.getWidth(), 0, 0);
 
1393
        edge1 = 1;
 
1394
      }
 
1395
      else {
 
1396
        //test bottom
 
1397
        new_coords = lineIntersect(x1, y1, x2, y2, this.getWidth(), 0, 
 
1398
                                   this.getHeight());
 
1399
        edge1 = 3;
 
1400
      }
 
1401
      
 
1402
      building.setElementAt(new 
 
1403
        Double(m_plot2D.convertToAttribX(new_coords[0])), 1);
 
1404
      building.setElementAt(new 
 
1405
        Double(m_plot2D.convertToAttribY(new_coords[1])), 2);
 
1406
 
 
1407
      x1 = m_plot2D.convertToPanelX(((Double)v.elementAt(v.size() - 4)).
 
1408
                                    doubleValue());
 
1409
      y1 = m_plot2D.convertToPanelY(((Double)v.elementAt(v.size() - 3)).
 
1410
                                    doubleValue());
 
1411
      x2 = m_plot2D.convertToPanelX(((Double)v.elementAt(v.size() - 6)).
 
1412
                                    doubleValue());
 
1413
      y2 = m_plot2D.convertToPanelY(((Double)v.elementAt(v.size() - 5)).
 
1414
                                    doubleValue());
 
1415
      
 
1416
      if (x1 < 0) {
 
1417
        //test left
 
1418
        new_coords = lineIntersect(x1, y1, x2, y2, 0, this.getHeight(), 0);
 
1419
        edge2 = 0;
 
1420
        if (new_coords[0] < 0) {
 
1421
          //then not left
 
1422
          if (y1 < 0) {
 
1423
            //test top
 
1424
            new_coords = lineIntersect(x1, y1, x2, y2, this.getWidth(), 0, 0);
 
1425
            edge2 = 1;
 
1426
          }
 
1427
          else {
 
1428
            //test bottom
 
1429
            new_coords = lineIntersect(x1, y1, x2, y2, this.getWidth(), 0, 
 
1430
                                       this.getHeight());
 
1431
            edge2 = 3;
 
1432
          }
 
1433
        }
 
1434
      }
 
1435
      else if (x1 > this.getWidth()) {
 
1436
        //test right
 
1437
        new_coords = lineIntersect(x1, y1, x2, y2, 0, this.getHeight(), 
 
1438
                                   this.getWidth());
 
1439
        edge2 = 2;
 
1440
        if (new_coords[0] < 0) {
 
1441
          //then not right
 
1442
          if (y1 < 0) {
 
1443
            //test top
 
1444
            new_coords = lineIntersect(x1, y1, x2, y2, this.getWidth(), 0, 0);
 
1445
            edge2 = 1;
 
1446
          }
 
1447
          else {
 
1448
            //test bottom
 
1449
            new_coords = lineIntersect(x1, y1, x2, y2, this.getWidth(), 0, 
 
1450
                                       this.getHeight());
 
1451
            edge2 = 3;
 
1452
          }
 
1453
        }
 
1454
      }
 
1455
      else if (y1 < 0) {
 
1456
        //test top
 
1457
        new_coords = lineIntersect(x1, y1, x2, y2, this.getWidth(), 0, 0);
 
1458
        edge2 = 1;
 
1459
      }
 
1460
      else {
 
1461
        //test bottom
 
1462
        new_coords = lineIntersect(x1, y1, x2, y2, this.getWidth(), 0, 
 
1463
                                   this.getHeight());
 
1464
        edge2 = 3;
 
1465
      }
 
1466
      
 
1467
      building.setElementAt(new 
 
1468
        Double(m_plot2D.convertToAttribX(new_coords[0])), building.size() - 2);
 
1469
      building.setElementAt(new 
 
1470
        Double(m_plot2D.convertToAttribY(new_coords[1])), building.size() - 1);
 
1471
      
 
1472
 
 
1473
      //trust me this complicated piece of code will
 
1474
      //determine what points on the boundary of the view to add to the polygon
 
1475
      int xp, yp;
 
1476
 
 
1477
      xp = this.getWidth() * ((edge2 & 1) ^ ((edge2 & 2) / 2));
 
1478
      yp = this.getHeight() * ((edge2 & 2) / 2);
 
1479
      //System.out.println(((-1 + 4) % 4) + " hoi");
 
1480
      
 
1481
      if (inPolyline(v, m_plot2D.convertToAttribX(xp), 
 
1482
                     m_plot2D.convertToAttribY(yp))) {
 
1483
        //then add points in a clockwise direction
 
1484
        building.addElement(new Double(m_plot2D.convertToAttribX(xp)));
 
1485
        building.addElement(new Double(m_plot2D.convertToAttribY(yp)));
 
1486
        for (int noa = (edge2 + 1) % 4; noa != edge1; noa = (noa + 1) % 4) {
 
1487
          xp = this.getWidth() * ((noa & 1) ^ ((noa & 2) / 2));
 
1488
          yp = this.getHeight() * ((noa & 2) / 2);
 
1489
          building.addElement(new Double(m_plot2D.convertToAttribX(xp)));
 
1490
          building.addElement(new Double(m_plot2D.convertToAttribY(yp)));
 
1491
        }
 
1492
      }
 
1493
      else {
 
1494
        xp = this.getWidth() * ((edge2 & 2) / 2);
 
1495
        yp = this.getHeight() * (1 & ~((edge2 & 1) ^ ((edge2 & 2) / 2)));
 
1496
        if (inPolyline(v, m_plot2D.convertToAttribX(xp), 
 
1497
                       m_plot2D.convertToAttribY(yp))) {
 
1498
          //then add points in anticlockwise direction
 
1499
          building.addElement(new Double(m_plot2D.convertToAttribX(xp)));
 
1500
          building.addElement(new Double(m_plot2D.convertToAttribY(yp)));
 
1501
          for (int noa = (edge2 + 3) % 4; noa != edge1; noa = (noa + 3) % 4) {
 
1502
            xp = this.getWidth() * ((noa & 2) / 2);
 
1503
            yp = this.getHeight() * (1 & ~((noa & 1) ^ ((noa & 2) / 2)));
 
1504
            building.addElement(new Double(m_plot2D.convertToAttribX(xp)));
 
1505
            building.addElement(new Double(m_plot2D.convertToAttribY(yp)));
 
1506
          }
 
1507
        }
 
1508
      }
 
1509
      return building;
 
1510
    }
 
1511
 
 
1512
    /**
 
1513
     * This will extract from a polygon shape its x coodrdinates
 
1514
     * so that an awt.Polygon can be created.
 
1515
     * @param v The polygon shape.
 
1516
     * @return an int array containing the screen x coords for the polygon.
 
1517
     */
 
1518
    private int[] getXCoords(FastVector v) {
 
1519
      int cach = (v.size() - 1) / 2;
 
1520
      int[] ar = new int[cach];
 
1521
      for (int noa = 0; noa < cach; noa ++) {
 
1522
        ar[noa] = (int)m_plot2D.convertToPanelX(((Double)v.elementAt(noa * 2 +
 
1523
                                                1)).doubleValue());
 
1524
      }
 
1525
      return ar;
 
1526
    }
 
1527
 
 
1528
    /**
 
1529
     * This will extract from a polygon shape its y coordinates
 
1530
     * so that an awt.Polygon can be created.
 
1531
     * @param v The polygon shape.
 
1532
     * @return an int array containing the screen y coords for the polygon.
 
1533
     */
 
1534
    private int[] getYCoords(FastVector v) {
 
1535
      int cach = (v.size() - 1) / 2;
 
1536
      int[] ar = new int[cach];
 
1537
      for (int noa = 0; noa < cach; noa ++) {
 
1538
        ar[noa] = (int)m_plot2D.
 
1539
          convertToPanelY(((Double)v.elementAt(noa * 2 + 2)).
 
1540
                          doubleValue());
 
1541
      }
 
1542
      return ar;
 
1543
    }
 
1544
    
 
1545
    /**
 
1546
     * Renders the polygons if necessary
 
1547
     * @param gx the graphics context
 
1548
     */
 
1549
    public void prePlot(Graphics gx) {
 
1550
      super.paintComponent(gx);
 
1551
      if (m_plotInstances != null) {
 
1552
        drawShapes(gx); // will be in paintComponent of ShapePlot2D
 
1553
      }
 
1554
    }
 
1555
  }
 
1556
 
 
1557
 
 
1558
 
 
1559
  /** default colours for colouring discrete class */
 
1560
  protected Color [] m_DefaultColors = {Color.blue,
 
1561
                                        Color.red,
 
1562
                                        Color.green,
 
1563
                                        Color.cyan,
 
1564
                                        Color.pink,
 
1565
                                        new Color(255, 0, 255),
 
1566
                                        Color.orange,
 
1567
                                        new Color(255, 0, 0),
 
1568
                                        new Color(0, 255, 0),
 
1569
                                        Color.white};
 
1570
  
 
1571
  /** Lets the user select the attribute for the x axis */
 
1572
  protected JComboBox m_XCombo = new JComboBox();
 
1573
 
 
1574
  /** Lets the user select the attribute for the y axis */
 
1575
  protected JComboBox m_YCombo = new JComboBox();
 
1576
 
 
1577
  /** Lets the user select the attribute to use for colouring */
 
1578
  protected JComboBox m_ColourCombo = new JComboBox();
 
1579
  
 
1580
  /** Lets the user select the shape they want to create for instance 
 
1581
   * selection. */
 
1582
  protected JComboBox m_ShapeCombo = new JComboBox();
 
1583
 
 
1584
  /** Button for the user to enter the splits. */
 
1585
  protected JButton m_submit = new JButton("Submit");
 
1586
  
 
1587
  /** Button for the user to remove all splits. */
 
1588
  protected JButton m_cancel = new JButton("Clear");
 
1589
 
 
1590
  /** Button for the user to open the visualized set of instances */
 
1591
  protected JButton m_openBut = new JButton("Open");
 
1592
 
 
1593
  /** Button for the user to save the visualized set of instances */
 
1594
  protected JButton m_saveBut = new JButton("Save");
 
1595
 
 
1596
  /** Stop the combos from growing out of control */
 
1597
  private Dimension COMBO_SIZE = new Dimension(250, m_saveBut
 
1598
                                               .getPreferredSize().height);
 
1599
 
 
1600
  /** file chooser for saving instances */
 
1601
  protected JFileChooser m_FileChooser 
 
1602
    = new JFileChooser(new File(System.getProperty("user.dir")));
 
1603
 
 
1604
  /** Filter to ensure only arff files are selected */  
 
1605
  protected FileFilter m_ArffFilter =
 
1606
    new ExtensionFileFilter(Instances.FILE_EXTENSION, "Arff data files");
 
1607
 
 
1608
  /** Label for the jitter slider */
 
1609
  protected JLabel m_JitterLab= new JLabel("Jitter",SwingConstants.RIGHT);
 
1610
 
 
1611
  /** The jitter slider */
 
1612
  protected JSlider m_Jitter = new JSlider(0,50,0);
 
1613
 
 
1614
  /** The panel that displays the plot */
 
1615
  protected PlotPanel m_plot = new PlotPanel();
 
1616
 
 
1617
  /** The panel that displays the attributes , using color to represent 
 
1618
   * another attribute. */
 
1619
  protected AttributePanel m_attrib = new AttributePanel();
 
1620
 
 
1621
  /** The panel that displays legend info if there is more than one plot */
 
1622
  protected LegendPanel m_legendPanel = new LegendPanel();
 
1623
 
 
1624
  /** Panel that surrounds the plot panel with a titled border */
 
1625
  protected JPanel m_plotSurround = new JPanel();
 
1626
 
 
1627
  /** Panel that surrounds the class panel with a titled border */
 
1628
  protected JPanel m_classSurround = new JPanel();
 
1629
 
 
1630
  /** An optional listener that we will inform when ComboBox selections
 
1631
      change */
 
1632
  protected ActionListener listener = null;
 
1633
 
 
1634
  /** An optional listener that we will inform when the user creates a 
 
1635
   * split to seperate instances. */
 
1636
  protected VisualizePanelListener m_splitListener = null;
 
1637
 
 
1638
  /** The name of the plot (not currently displayed, but can be used
 
1639
      in the containing Frame or Panel) */
 
1640
  protected String m_plotName = "";
 
1641
 
 
1642
  /** The panel that displays the legend for the colouring attribute */
 
1643
  protected ClassPanel m_classPanel = new ClassPanel();
 
1644
  
 
1645
  /** The list of the colors used */
 
1646
  protected FastVector m_colorList;
 
1647
 
 
1648
  /** These hold the names of preferred columns to visualize on---if the
 
1649
      user has defined them in the Visualize.props file */
 
1650
  protected String m_preferredXDimension = null;
 
1651
  protected String m_preferredYDimension = null;
 
1652
  protected String m_preferredColourDimension = null;
 
1653
 
 
1654
  /** Show the attribute bar panel */
 
1655
  protected boolean m_showAttBars = true;
 
1656
 
 
1657
  /** the logger */
 
1658
  protected Logger m_Log;
 
1659
  
 
1660
  /**
 
1661
   * Sets the Logger to receive informational messages
 
1662
   *
 
1663
   * @param newLog the Logger that will now get info messages
 
1664
   */
 
1665
  public void setLog(Logger newLog) {
 
1666
    m_Log = newLog;
 
1667
  }
 
1668
 
 
1669
  /** 
 
1670
   * This constructor allows a VisualizePanelListener to be set. 
 
1671
   * 
 
1672
   * @param ls          the listener to use
 
1673
   */
 
1674
  public VisualizePanel(VisualizePanelListener ls) {
 
1675
    this();
 
1676
    m_splitListener = ls;
 
1677
  }
 
1678
 
 
1679
  /**
 
1680
   * Set the properties for the VisualizePanel
 
1681
   * 
 
1682
   * @param relationName        the name of the relation, can be null
 
1683
   */
 
1684
  private void setProperties(String relationName) {
 
1685
    if (VisualizeUtils.VISUALIZE_PROPERTIES != null) {
 
1686
      String thisClass = this.getClass().getName();
 
1687
      if (relationName == null) {
 
1688
        
 
1689
        String showAttBars = thisClass+".displayAttributeBars";
 
1690
 
 
1691
        String val = VisualizeUtils.VISUALIZE_PROPERTIES.
 
1692
          getProperty(showAttBars);
 
1693
        if (val == null) {
 
1694
          //System.err.println("Displaying attribute bars ");
 
1695
          m_showAttBars = true;
 
1696
        } else {
 
1697
          if (val.compareTo("true") == 0 || val.compareTo("on") == 0) {
 
1698
            //System.err.println("Displaying attribute bars ");
 
1699
            m_showAttBars = true;
 
1700
          } else {
 
1701
            m_showAttBars = false;
 
1702
          }
 
1703
        }
 
1704
      } else {
 
1705
        /*
 
1706
        System.err.println("Looking for preferred visualization dimensions for "
 
1707
                           +relationName);
 
1708
        */
 
1709
        String xcolKey = thisClass+"."+relationName+".XDimension";
 
1710
        String ycolKey = thisClass+"."+relationName+".YDimension";
 
1711
        String ccolKey = thisClass+"."+relationName+".ColourDimension";
 
1712
      
 
1713
        m_preferredXDimension = VisualizeUtils.VISUALIZE_PROPERTIES.
 
1714
          getProperty(xcolKey);
 
1715
        /*
 
1716
        if (m_preferredXDimension == null) {
 
1717
          System.err.println("No preferred X dimension found in "
 
1718
                             +VisualizeUtils.PROPERTY_FILE
 
1719
                             +" for "+xcolKey);
 
1720
        } else {
 
1721
          System.err.println("Setting preferred X dimension to "
 
1722
                             +m_preferredXDimension);
 
1723
                             }*/
 
1724
        m_preferredYDimension = VisualizeUtils.VISUALIZE_PROPERTIES.
 
1725
          getProperty(ycolKey);
 
1726
        /*
 
1727
        if (m_preferredYDimension == null) {
 
1728
          System.err.println("No preferred Y dimension found in "
 
1729
                             +VisualizeUtils.PROPERTY_FILE
 
1730
                             +" for "+ycolKey);
 
1731
        } else {
 
1732
          System.err.println("Setting preferred dimension Y to "
 
1733
                             +m_preferredYDimension);
 
1734
                             }*/
 
1735
        m_preferredColourDimension = VisualizeUtils.VISUALIZE_PROPERTIES.
 
1736
          getProperty(ccolKey);
 
1737
        /*
 
1738
        if (m_preferredColourDimension == null) {
 
1739
          System.err.println("No preferred Colour dimension found in "
 
1740
                             +VisualizeUtils.PROPERTY_FILE
 
1741
                             +" for "+ycolKey);
 
1742
        } else {
 
1743
          System.err.println("Setting preferred Colour dimension to "
 
1744
                             +m_preferredColourDimension);
 
1745
                             }*/
 
1746
      }
 
1747
    }
 
1748
  }
 
1749
 
 
1750
  /**
 
1751
   * Constructor
 
1752
   */
 
1753
  public VisualizePanel() {
 
1754
    super();
 
1755
    setProperties(null);
 
1756
    m_FileChooser.setFileFilter(m_ArffFilter);
 
1757
    m_FileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
 
1758
 
 
1759
    m_XCombo.setToolTipText("Select the attribute for the x axis");
 
1760
    m_YCombo.setToolTipText("Select the attribute for the y axis");
 
1761
    m_ColourCombo.setToolTipText("Select the attribute to colour on");
 
1762
    m_ShapeCombo.setToolTipText("Select the shape to use for data selection"); 
 
1763
 
 
1764
    m_XCombo.setPreferredSize(COMBO_SIZE);
 
1765
    m_YCombo.setPreferredSize(COMBO_SIZE);
 
1766
    m_ColourCombo.setPreferredSize(COMBO_SIZE);
 
1767
    m_ShapeCombo.setPreferredSize(COMBO_SIZE);
 
1768
 
 
1769
    m_XCombo.setMaximumSize(COMBO_SIZE);
 
1770
    m_YCombo.setMaximumSize(COMBO_SIZE);
 
1771
    m_ColourCombo.setMaximumSize(COMBO_SIZE);
 
1772
    m_ShapeCombo.setMaximumSize(COMBO_SIZE);
 
1773
    
 
1774
    m_XCombo.setMinimumSize(COMBO_SIZE);
 
1775
    m_YCombo.setMinimumSize(COMBO_SIZE);
 
1776
    m_ColourCombo.setMinimumSize(COMBO_SIZE);
 
1777
    m_ShapeCombo.setMinimumSize(COMBO_SIZE);
 
1778
    //////////
 
1779
    m_XCombo.setEnabled(false);
 
1780
    m_YCombo.setEnabled(false);
 
1781
    m_ColourCombo.setEnabled(false);
 
1782
    m_ShapeCombo.setEnabled(false);
 
1783
 
 
1784
    // tell the class panel and the legend panel that we want to know when 
 
1785
    // colours change
 
1786
    m_classPanel.addRepaintNotify(this);
 
1787
    m_legendPanel.addRepaintNotify(this);
 
1788
 
 
1789
    m_colorList = new FastVector(10);
 
1790
    for (int noa = m_colorList.size(); noa < 10; noa++) {
 
1791
      Color pc = m_DefaultColors[noa % 10];
 
1792
      int ija =  noa / 10;
 
1793
      ija *= 2; 
 
1794
      for (int j=0;j<ija;j++) {
 
1795
        pc = pc.darker();
 
1796
      }
 
1797
      
 
1798
      m_colorList.addElement(pc);
 
1799
    }
 
1800
    m_plot.setColours(m_colorList);
 
1801
    m_classPanel.setColours(m_colorList);
 
1802
    m_attrib.setColours(m_colorList);
 
1803
    m_attrib.addAttributePanelListener(new AttributePanelListener() {
 
1804
        public void attributeSelectionChange(AttributePanelEvent e) {
 
1805
          if (e.m_xChange) {
 
1806
            m_XCombo.setSelectedIndex(e.m_indexVal);
 
1807
          } else {
 
1808
            m_YCombo.setSelectedIndex(e.m_indexVal);
 
1809
          }
 
1810
        }
 
1811
      });
 
1812
    
 
1813
    m_XCombo.addActionListener(new ActionListener() {
 
1814
        public void actionPerformed(ActionEvent e) {
 
1815
          int selected = m_XCombo.getSelectedIndex();
 
1816
          if (selected < 0) {
 
1817
            selected = 0;
 
1818
          }
 
1819
          m_plot.setXindex(selected);
 
1820
         
 
1821
          // try sending on the event if anyone is listening
 
1822
          if (listener != null) {
 
1823
            listener.actionPerformed(e);
 
1824
          }
 
1825
        }
 
1826
      });
 
1827
 
 
1828
    m_YCombo.addActionListener(new ActionListener() {
 
1829
        public void actionPerformed(ActionEvent e) {
 
1830
          int selected = m_YCombo.getSelectedIndex();
 
1831
          if (selected < 0) {
 
1832
            selected = 0;
 
1833
          }
 
1834
          m_plot.setYindex(selected);
 
1835
         
 
1836
          // try sending on the event if anyone is listening
 
1837
          if (listener != null) {
 
1838
            listener.actionPerformed(e);
 
1839
          }
 
1840
        }
 
1841
      });
 
1842
 
 
1843
    m_ColourCombo.addActionListener(new ActionListener() {
 
1844
        public void actionPerformed(ActionEvent e) {
 
1845
          int selected = m_ColourCombo.getSelectedIndex();
 
1846
          if (selected < 0) {
 
1847
            selected = 0;
 
1848
          }
 
1849
          m_plot.setCindex(selected);
 
1850
 
 
1851
          if (listener != null) {
 
1852
            listener.actionPerformed(e);
 
1853
          }
 
1854
        }
 
1855
      });
 
1856
    
 
1857
    ///////
 
1858
    m_ShapeCombo.addActionListener(new ActionListener() {
 
1859
        public void actionPerformed(ActionEvent e) {
 
1860
          int selected = m_ShapeCombo.getSelectedIndex();
 
1861
          if (selected < 0) {
 
1862
            selected = 0;
 
1863
          }
 
1864
          m_plot.setSindex(selected);
 
1865
          // try sending on the event if anyone is listening
 
1866
          if (listener != null) {
 
1867
            listener.actionPerformed(e);
 
1868
          }
 
1869
        }
 
1870
      });
 
1871
 
 
1872
 
 
1873
    ///////////////////////////////////////
 
1874
 
 
1875
    m_Jitter.addChangeListener(new ChangeListener() {
 
1876
        public void stateChanged(ChangeEvent e) {
 
1877
          m_plot.setJitter(m_Jitter.getValue());
 
1878
        }
 
1879
      });
 
1880
 
 
1881
    m_openBut.setToolTipText("Loads previously saved instances from a file");
 
1882
    m_openBut.addActionListener(new ActionListener() {
 
1883
        public void actionPerformed(ActionEvent e) {
 
1884
          openVisibleInstances();
 
1885
        }
 
1886
      });
 
1887
    
 
1888
    m_saveBut.setEnabled(false);
 
1889
    m_saveBut.setToolTipText("Save the visible instances to a file");
 
1890
    m_saveBut.addActionListener(new ActionListener() {
 
1891
        public void actionPerformed(ActionEvent e) {
 
1892
          saveVisibleInstances();
 
1893
        }
 
1894
      });
 
1895
    
 
1896
    JPanel combos = new JPanel();
 
1897
    GridBagLayout gb = new GridBagLayout();
 
1898
    GridBagConstraints constraints = new GridBagConstraints();
 
1899
 
 
1900
 
 
1901
    m_XCombo.setLightWeightPopupEnabled(false);
 
1902
    m_YCombo.setLightWeightPopupEnabled(false);
 
1903
    m_ColourCombo.setLightWeightPopupEnabled(false);
 
1904
    m_ShapeCombo.setLightWeightPopupEnabled(false);
 
1905
    combos.setBorder(BorderFactory.createEmptyBorder(10, 5, 10, 5));
 
1906
 
 
1907
    combos.setLayout(gb);
 
1908
    constraints.gridx=0;constraints.gridy=0;constraints.weightx=5;
 
1909
    constraints.fill = GridBagConstraints.HORIZONTAL;
 
1910
    constraints.gridwidth=2;constraints.gridheight=1;
 
1911
    constraints.insets = new Insets(0,2,0,2);
 
1912
    combos.add(m_XCombo,constraints);
 
1913
    constraints.gridx=2;constraints.gridy=0;constraints.weightx=5;
 
1914
    constraints.gridwidth=2;constraints.gridheight=1;
 
1915
    combos.add(m_YCombo,constraints);
 
1916
    constraints.gridx=0;constraints.gridy=1;constraints.weightx=5;
 
1917
    constraints.gridwidth=2;constraints.gridheight=1;
 
1918
    combos.add(m_ColourCombo,constraints);
 
1919
    //
 
1920
    constraints.gridx=2;constraints.gridy=1;constraints.weightx=5;
 
1921
    constraints.gridwidth=2;constraints.gridheight=1;
 
1922
    combos.add(m_ShapeCombo,constraints);
 
1923
 
 
1924
   
 
1925
    JPanel mbts = new JPanel();
 
1926
    mbts.setLayout(new GridLayout(1,4));
 
1927
    mbts.add(m_submit); mbts.add(m_cancel); mbts.add(m_openBut); mbts.add(m_saveBut);
 
1928
 
 
1929
    constraints.gridx=0;constraints.gridy=2;constraints.weightx=5;
 
1930
    constraints.gridwidth=2;constraints.gridheight=1;
 
1931
    combos.add(mbts, constraints);
 
1932
 
 
1933
    ////////////////////////////////
 
1934
    constraints.gridx=2;constraints.gridy=2;constraints.weightx=5;
 
1935
    constraints.gridwidth=1;constraints.gridheight=1;
 
1936
    constraints.insets = new Insets(10,0,0,5);
 
1937
    combos.add(m_JitterLab,constraints);
 
1938
    constraints.gridx=3;constraints.gridy=2;
 
1939
    constraints.weightx=5;
 
1940
    constraints.insets = new Insets(10,0,0,0);
 
1941
    combos.add(m_Jitter,constraints);
 
1942
 
 
1943
    m_classSurround = new JPanel();
 
1944
    m_classSurround.
 
1945
      setBorder(BorderFactory.createTitledBorder("Class colour")); 
 
1946
    m_classSurround.setLayout(new BorderLayout());
 
1947
 
 
1948
    m_classPanel.setBorder(BorderFactory.createEmptyBorder(15,10,10,10));
 
1949
    m_classSurround.add(m_classPanel, BorderLayout.CENTER);
 
1950
 
 
1951
    GridBagLayout gb2 = new GridBagLayout();
 
1952
    m_plotSurround.setBorder(BorderFactory.createTitledBorder("Plot"));
 
1953
    m_plotSurround.setLayout(gb2);
 
1954
 
 
1955
    constraints.fill = GridBagConstraints.BOTH;
 
1956
    constraints.insets = new Insets(0, 0, 0, 10);
 
1957
    constraints.gridx=0;constraints.gridy=0;constraints.weightx=3;
 
1958
    constraints.gridwidth=4;constraints.gridheight=1;constraints.weighty=5;
 
1959
    m_plotSurround.add(m_plot, constraints);
 
1960
    
 
1961
    if (m_showAttBars) {
 
1962
      constraints.insets = new Insets(0, 0, 0, 0);
 
1963
      constraints.gridx=4;constraints.gridy=0;constraints.weightx=1;
 
1964
      constraints.gridwidth=1;constraints.gridheight=1;constraints.weighty=5;
 
1965
      m_plotSurround.add(m_attrib, constraints);
 
1966
    }
 
1967
 
 
1968
    setLayout(new BorderLayout());
 
1969
    add(combos, BorderLayout.NORTH);
 
1970
    add(m_plotSurround, BorderLayout.CENTER);
 
1971
    add(m_classSurround, BorderLayout.SOUTH);
 
1972
    
 
1973
    String [] SNames = new String [4];
 
1974
    SNames[0] = "Select Instance";
 
1975
    SNames[1] = "Rectangle";
 
1976
    SNames[2] = "Polygon";
 
1977
    SNames[3] = "Polyline";
 
1978
 
 
1979
    m_ShapeCombo.setModel(new DefaultComboBoxModel(SNames));
 
1980
    m_ShapeCombo.setEnabled(true);
 
1981
  }
 
1982
 
 
1983
  /**
 
1984
   * displays the previously saved instances
 
1985
   * 
 
1986
   * @param insts       the instances to display
 
1987
   * @throws Exception  if display is not possible
 
1988
   */
 
1989
  protected void openVisibleInstances(Instances insts) throws Exception {
 
1990
    PlotData2D tempd = new PlotData2D(insts);
 
1991
    tempd.setPlotName(insts.relationName());
 
1992
    tempd.addInstanceNumberAttribute();
 
1993
    m_plot.m_plot2D.removeAllPlots();
 
1994
    addPlot(tempd);
 
1995
    
 
1996
    // modify title
 
1997
    Component parent = getParent();
 
1998
    while (parent != null) {
 
1999
      if (parent instanceof JFrame) {
 
2000
        ((JFrame) parent).setTitle(
 
2001
            "Weka Classifier Visualize: " 
 
2002
            + insts.relationName() 
 
2003
            + " (display only)");
 
2004
        break;
 
2005
      }
 
2006
      else {
 
2007
        parent = parent.getParent();
 
2008
      }
 
2009
    }
 
2010
  }
 
2011
  
 
2012
  /**
 
2013
   * Loads previously saved instances from a file
 
2014
   */
 
2015
  protected void openVisibleInstances() {
 
2016
    try {
 
2017
      int returnVal = m_FileChooser.showOpenDialog(this);
 
2018
      if (returnVal == JFileChooser.APPROVE_OPTION) {
 
2019
        File sFile = m_FileChooser.getSelectedFile();
 
2020
        if (!sFile.getName().toLowerCase().
 
2021
            endsWith(Instances.FILE_EXTENSION)) {
 
2022
          sFile = new File(sFile.getParent(), sFile.getName() + Instances.FILE_EXTENSION);
 
2023
        }
 
2024
        File selected = sFile;
 
2025
        Instances insts = new Instances(new BufferedReader(new FileReader(selected)));
 
2026
        openVisibleInstances(insts);
 
2027
      }
 
2028
    } catch (Exception ex) {
 
2029
      ex.printStackTrace();
 
2030
      m_plot.m_plot2D.removeAllPlots();
 
2031
      JOptionPane.showMessageDialog(
 
2032
          this, 
 
2033
          ex.getMessage(), 
 
2034
          "Error loading file...", 
 
2035
          JOptionPane.ERROR_MESSAGE);
 
2036
    }
 
2037
  }
 
2038
 
 
2039
  /**
 
2040
   * Save the currently visible set of instances to a file
 
2041
   */
 
2042
  private void saveVisibleInstances() {
 
2043
    FastVector plots = m_plot.m_plot2D.getPlots();
 
2044
    if (plots != null) {
 
2045
      PlotData2D master = (PlotData2D)plots.elementAt(0);
 
2046
      Instances saveInsts = new Instances(master.getPlotInstances());
 
2047
      for (int i = 1; i < plots.size(); i++) {
 
2048
        PlotData2D temp = (PlotData2D)plots.elementAt(i);
 
2049
        Instances addInsts = temp.getPlotInstances();
 
2050
        for (int j = 0; j < addInsts.numInstances(); j++) {
 
2051
          saveInsts.add(addInsts.instance(j));
 
2052
        }
 
2053
      }
 
2054
      try {
 
2055
        int returnVal = m_FileChooser.showSaveDialog(this);
 
2056
        if (returnVal == JFileChooser.APPROVE_OPTION) {
 
2057
          File sFile = m_FileChooser.getSelectedFile();
 
2058
          if (!sFile.getName().toLowerCase().
 
2059
              endsWith(Instances.FILE_EXTENSION)) {
 
2060
            sFile = new File(sFile.getParent(), sFile.getName() 
 
2061
                             + Instances.FILE_EXTENSION);
 
2062
          }
 
2063
          File selected = sFile;
 
2064
          Writer w = new BufferedWriter(new FileWriter(selected));
 
2065
          w.write(saveInsts.toString());
 
2066
          w.close();
 
2067
        }
 
2068
      } catch (Exception ex) {
 
2069
        ex.printStackTrace();
 
2070
      }
 
2071
    }
 
2072
  }
 
2073
 
 
2074
 
 
2075
  /**
 
2076
   * Sets the index used for colouring. If this method is called then
 
2077
   * the supplied index is used and the combo box for selecting colouring
 
2078
   * attribute is disabled.
 
2079
   * @param index the index of the attribute to use for colouring
 
2080
   */
 
2081
  public void setColourIndex(int index) {
 
2082
    if (index >= 0) {
 
2083
      m_ColourCombo.setSelectedIndex(index);
 
2084
    } else {
 
2085
      m_ColourCombo.setSelectedIndex(0);
 
2086
    }
 
2087
    m_ColourCombo.setEnabled(false);
 
2088
  }
 
2089
  
 
2090
  
 
2091
  /**
 
2092
   * Set the index of the attribute for the x axis 
 
2093
   * @param index the index for the x axis
 
2094
   * @exception Exception if index is out of range.
 
2095
   */
 
2096
  public void setXIndex(int index) throws Exception {
 
2097
    if (index >= 0 && index < m_XCombo.getItemCount()) {
 
2098
      m_XCombo.setSelectedIndex(index);
 
2099
    } else {
 
2100
      throw new Exception("x index is out of range!");
 
2101
    }
 
2102
  }
 
2103
 
 
2104
  /**
 
2105
   * Get the index of the attribute on the x axis
 
2106
   * @return the index of the attribute on the x axis
 
2107
   */
 
2108
  public int getXIndex() {
 
2109
    return m_XCombo.getSelectedIndex();
 
2110
  }
 
2111
 
 
2112
  /**
 
2113
   * Set the index of the attribute for the y axis 
 
2114
   * @param index the index for the y axis
 
2115
   * @exception Exception if index is out of range.
 
2116
   */
 
2117
  public void setYIndex(int index) throws Exception {
 
2118
    if (index >= 0 && index < m_YCombo.getItemCount()) {
 
2119
      m_YCombo.setSelectedIndex(index);
 
2120
    } else {
 
2121
      throw new Exception("y index is out of range!");
 
2122
    }
 
2123
  }
 
2124
  
 
2125
  /**
 
2126
   * Get the index of the attribute on the y axis
 
2127
   * @return the index of the attribute on the x axis
 
2128
   */
 
2129
  public int getYIndex() {
 
2130
    return m_YCombo.getSelectedIndex();
 
2131
  }
 
2132
 
 
2133
  /**
 
2134
   * Get the index of the attribute selected for coloring
 
2135
   * @return the index of the attribute on the x axis
 
2136
   */
 
2137
  public int getCIndex() {
 
2138
    return m_ColourCombo.getSelectedIndex();
 
2139
  }
 
2140
 
 
2141
  /**
 
2142
   * Get the index of the shape selected for creating splits.
 
2143
   * @return The index of the shape.
 
2144
   */
 
2145
  public int getSIndex() {
 
2146
    return m_ShapeCombo.getSelectedIndex();
 
2147
  }
 
2148
  
 
2149
  /** 
 
2150
   * Set the shape for creating splits.
 
2151
   * @param index The index of the shape.
 
2152
   * @exception Exception if index is out of range.
 
2153
   */
 
2154
  public void setSIndex(int index) throws Exception {
 
2155
    if (index >= 0 && index < m_ShapeCombo.getItemCount()) {
 
2156
      m_ShapeCombo.setSelectedIndex(index);
 
2157
    }
 
2158
    else {
 
2159
      throw new Exception("s index is out of range!");
 
2160
    }
 
2161
  }
 
2162
 
 
2163
  /**
 
2164
   * Add a listener for this visualize panel
 
2165
   * @param act an ActionListener
 
2166
   */
 
2167
  public void addActionListener(ActionListener act) {
 
2168
    listener = act;
 
2169
  }
 
2170
 
 
2171
  /**
 
2172
   * Set a name for this plot
 
2173
   * @param plotName the name for the plot
 
2174
   */
 
2175
  public void setName(String plotName) {
 
2176
    m_plotName = plotName;
 
2177
  }
 
2178
 
 
2179
  /**
 
2180
   * Returns the name associated with this plot. "" is returned if no
 
2181
   * name is set.
 
2182
   * @return the name of the plot
 
2183
   */
 
2184
  public String getName() {
 
2185
    return m_plotName;
 
2186
  }
 
2187
 
 
2188
  /**
 
2189
   * Get the master plot's instances
 
2190
   * @return the master plot's instances
 
2191
   */
 
2192
  public Instances getInstances() {
 
2193
    return m_plot.m_plotInstances;
 
2194
  }
 
2195
 
 
2196
  /**
 
2197
   * Sets the Colors in use for a different attrib
 
2198
   * if it is not a nominal attrib and or does not have
 
2199
   * more possible values then this will do nothing.
 
2200
   * otherwise it will add default colors to see that
 
2201
   * there is a color for the attrib to begin with.
 
2202
   * @param a The index of the attribute to color.
 
2203
   * @param i The instances object that contains the attribute.
 
2204
   */
 
2205
  protected void newColorAttribute(int a, Instances i) {
 
2206
    if (i.attribute(a).isNominal()) {
 
2207
      for (int noa = m_colorList.size(); noa < i.attribute(a).numValues();
 
2208
           noa++) {
 
2209
        Color pc = m_DefaultColors[noa % 10];
 
2210
        int ija =  noa / 10;
 
2211
        ija *= 2; 
 
2212
        for (int j=0;j<ija;j++) {
 
2213
          pc = pc.brighter();
 
2214
        }
 
2215
        
 
2216
        m_colorList.addElement(pc);
 
2217
      }
 
2218
      m_plot.setColours(m_colorList);
 
2219
      m_attrib.setColours(m_colorList);
 
2220
      m_classPanel.setColours(m_colorList);
 
2221
    }
 
2222
  }
 
2223
 
 
2224
 
 
2225
  /**
 
2226
   * This will set the shapes for the instances.
 
2227
   * @param l A list of the shapes, providing that
 
2228
   * the objects in the lists are non editable the data will be
 
2229
   * kept intact.
 
2230
   */
 
2231
  public void setShapes(FastVector l) {
 
2232
    m_plot.setShapes(l);
 
2233
  }
 
2234
 
 
2235
  /**
 
2236
   * Tells the panel to use a new set of instances.
 
2237
   * @param inst a set of Instances
 
2238
   */
 
2239
  public void setInstances(Instances inst) {
 
2240
    if (inst.numAttributes() > 0 && inst.numInstances() > 0) {
 
2241
      newColorAttribute(inst.numAttributes()-1, inst);
 
2242
    }
 
2243
 
 
2244
    PlotData2D temp = new PlotData2D(inst);
 
2245
    temp.setPlotName(inst.relationName());
 
2246
    
 
2247
    try {
 
2248
      setMasterPlot(temp);
 
2249
    } catch (Exception ex) {
 
2250
      System.err.println(ex);
 
2251
      ex.printStackTrace();
 
2252
    } 
 
2253
  }
 
2254
 
 
2255
  /**
 
2256
   * initializes the comboboxes based on the data
 
2257
   * 
 
2258
   * @param inst        the data to base the combobox-setup on
 
2259
   */
 
2260
  public void setUpComboBoxes(Instances inst) {
 
2261
    setProperties(inst.relationName());
 
2262
    int prefX = -1;
 
2263
    int prefY = -1;
 
2264
    if (inst.numAttributes() > 1) {
 
2265
      prefY = 1;
 
2266
    }
 
2267
    int prefC = -1;
 
2268
    String [] XNames = new String [inst.numAttributes()];
 
2269
    String [] YNames = new String [inst.numAttributes()];
 
2270
    String [] CNames = new String [inst.numAttributes()];
 
2271
    for (int i = 0; i < XNames.length; i++) {
 
2272
      String type = "";
 
2273
      switch (inst.attribute(i).type()) {
 
2274
      case Attribute.NOMINAL:
 
2275
        type = " (Nom)";
 
2276
        break;
 
2277
      case Attribute.NUMERIC:
 
2278
        type = " (Num)";
 
2279
        break;
 
2280
      case Attribute.STRING:
 
2281
        type = " (Str)";
 
2282
        break;
 
2283
      case Attribute.DATE:
 
2284
        type = " (Dat)";
 
2285
        break;
 
2286
      case Attribute.RELATIONAL:
 
2287
        type = " (Rel)";
 
2288
        break;
 
2289
      default:
 
2290
        type = " (???)";
 
2291
      }
 
2292
      XNames[i] = "X: "+ inst.attribute(i).name()+type;
 
2293
      YNames[i] = "Y: "+ inst.attribute(i).name()+type;
 
2294
      CNames[i] = "Colour: "+ inst.attribute(i).name()+type;
 
2295
      if (m_preferredXDimension != null) {
 
2296
        if (m_preferredXDimension.compareTo(inst.attribute(i).name()) == 0) {
 
2297
          prefX = i;
 
2298
          //System.err.println("Found preferred X dimension");
 
2299
        }
 
2300
      }
 
2301
      if (m_preferredYDimension != null) {
 
2302
        if (m_preferredYDimension.compareTo(inst.attribute(i).name()) == 0) {
 
2303
          prefY = i;
 
2304
          //System.err.println("Found preferred Y dimension");
 
2305
        }
 
2306
      }
 
2307
      if (m_preferredColourDimension != null) {
 
2308
        if (m_preferredColourDimension.
 
2309
            compareTo(inst.attribute(i).name()) == 0) {
 
2310
          prefC = i;
 
2311
          //System.err.println("Found preferred Colour dimension");
 
2312
        }
 
2313
      }
 
2314
    }
 
2315
    m_XCombo.setModel(new DefaultComboBoxModel(XNames));
 
2316
    m_YCombo.setModel(new DefaultComboBoxModel(YNames));
 
2317
 
 
2318
    m_ColourCombo.setModel(new DefaultComboBoxModel(CNames));
 
2319
    //m_ShapeCombo.setModel(new DefaultComboBoxModel(SNames));
 
2320
    //m_ShapeCombo.setEnabled(true);
 
2321
    m_XCombo.setEnabled(true);
 
2322
    m_YCombo.setEnabled(true);
 
2323
    
 
2324
    if (m_splitListener == null) {
 
2325
      m_ColourCombo.setEnabled(true);
 
2326
      m_ColourCombo.setSelectedIndex(inst.numAttributes()-1);
 
2327
    }
 
2328
    m_plotSurround.setBorder((BorderFactory.createTitledBorder("Plot: "
 
2329
                              +inst.relationName())));
 
2330
    try {
 
2331
      if (prefX != -1) {
 
2332
        setXIndex(prefX);
 
2333
      }
 
2334
      if (prefY != -1) {
 
2335
        setYIndex(prefY);
 
2336
      }
 
2337
      if (prefC != -1) {
 
2338
        m_ColourCombo.setSelectedIndex(prefC);
 
2339
      }
 
2340
    } catch (Exception ex) {
 
2341
      System.err.println("Problem setting preferred Visualization dimensions");
 
2342
    }
 
2343
  }
 
2344
 
 
2345
  /**
 
2346
   * Set the master plot for the visualize panel
 
2347
   * @param newPlot the new master plot
 
2348
   * @exception Exception if the master plot could not be set
 
2349
   */
 
2350
  public void setMasterPlot(PlotData2D newPlot) throws Exception {
 
2351
    m_plot.setMasterPlot(newPlot);
 
2352
    setUpComboBoxes(newPlot.m_plotInstances);
 
2353
    m_saveBut.setEnabled(true);
 
2354
    repaint();
 
2355
  }
 
2356
 
 
2357
  /**
 
2358
   * Set a new plot to the visualize panel
 
2359
   * @param newPlot the new plot to add
 
2360
   * @exception Exception if the plot could not be added
 
2361
   */
 
2362
  public void addPlot(PlotData2D newPlot) throws Exception {
 
2363
    m_plot.addPlot(newPlot);
 
2364
    if (m_plot.m_plot2D.getMasterPlot() != null) {
 
2365
      setUpComboBoxes(newPlot.m_plotInstances);
 
2366
    }
 
2367
    m_saveBut.setEnabled(true);
 
2368
    repaint();
 
2369
  }
 
2370
 
 
2371
  /**
 
2372
   * Main method for testing this class
 
2373
   * 
 
2374
   * @param args        the commandline parameters
 
2375
   */
 
2376
  public static void main(String [] args) {
 
2377
    try {
 
2378
      if (args.length < 1) {
 
2379
        System.err.println("Usage : weka.gui.visualize.VisualizePanel "
 
2380
                           +"<dataset> [<dataset> <dataset>...]");
 
2381
        System.exit(1);
 
2382
      }
 
2383
 
 
2384
      final javax.swing.JFrame jf = 
 
2385
        new javax.swing.JFrame("Weka Explorer: Visualize");
 
2386
      jf.setSize(500,400);
 
2387
      jf.getContentPane().setLayout(new BorderLayout());
 
2388
      final VisualizePanel sp = new VisualizePanel();
 
2389
      
 
2390
      jf.getContentPane().add(sp, BorderLayout.CENTER);
 
2391
      jf.addWindowListener(new java.awt.event.WindowAdapter() {
 
2392
        public void windowClosing(java.awt.event.WindowEvent e) {
 
2393
          jf.dispose();
 
2394
          System.exit(0);
 
2395
        }
 
2396
      });
 
2397
 
 
2398
      jf.setVisible(true);
 
2399
      if (args.length >= 1) {
 
2400
        for (int j = 0; j < args.length; j++) {
 
2401
          System.err.println("Loading instances from " + args[j]);
 
2402
          java.io.Reader r = new java.io.BufferedReader(
 
2403
                             new java.io.FileReader(args[j]));
 
2404
          Instances i = new Instances(r);
 
2405
          i.setClassIndex(i.numAttributes()-1);
 
2406
          PlotData2D pd1 = new PlotData2D(i);
 
2407
          
 
2408
          if (j == 0) {
 
2409
            pd1.setPlotName("Master plot");
 
2410
            sp.setMasterPlot(pd1);
 
2411
          } else {
 
2412
            pd1.setPlotName("Plot "+(j+1));
 
2413
            pd1.m_useCustomColour = true;
 
2414
            pd1.m_customColour = (j % 2 == 0) ? Color.red : Color.blue; 
 
2415
            sp.addPlot(pd1);
 
2416
          }
 
2417
        }
 
2418
      }
 
2419
    } catch (Exception ex) {
 
2420
      ex.printStackTrace();
 
2421
      System.err.println(ex.getMessage());
 
2422
    }
 
2423
  }
 
2424
}