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

« back to all changes in this revision

Viewing changes to weka/gui/explorer/ClustererPanel.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
 *    ClustererPanel.java
 
19
 *    Copyright (C) 1999 University of Waikato, Hamilton, New Zealand
 
20
 *
 
21
 */
 
22
 
 
23
package weka.gui.explorer;
 
24
 
 
25
import weka.clusterers.ClusterEvaluation;
 
26
import weka.clusterers.Clusterer;
 
27
import weka.core.Attribute;
 
28
import weka.core.Capabilities;
 
29
import weka.core.Drawable;
 
30
import weka.core.FastVector;
 
31
import weka.core.Instance;
 
32
import weka.core.Instances;
 
33
import weka.core.OptionHandler;
 
34
import weka.core.SerializedObject;
 
35
import weka.core.Utils;
 
36
import weka.filters.Filter;
 
37
import weka.filters.unsupervised.attribute.Remove;
 
38
import weka.gui.ExtensionFileFilter;
 
39
import weka.gui.GenericObjectEditor;
 
40
import weka.gui.InstancesSummaryPanel;
 
41
import weka.gui.ListSelectorDialog;
 
42
import weka.gui.Logger;
 
43
import weka.gui.PropertyPanel;
 
44
import weka.gui.ResultHistoryPanel;
 
45
import weka.gui.SaveBuffer;
 
46
import weka.gui.SetInstancesPanel;
 
47
import weka.gui.SysErrLog;
 
48
import weka.gui.TaskLogger;
 
49
import weka.gui.explorer.Explorer.CapabilitiesFilterChangeEvent;
 
50
import weka.gui.explorer.Explorer.CapabilitiesFilterChangeListener;
 
51
import weka.gui.explorer.Explorer.ExplorerPanel;
 
52
import weka.gui.explorer.Explorer.LogHandler;
 
53
import weka.gui.treevisualizer.PlaceNode2;
 
54
import weka.gui.treevisualizer.TreeVisualizer;
 
55
import weka.gui.visualize.Plot2D;
 
56
import weka.gui.visualize.PlotData2D;
 
57
import weka.gui.visualize.VisualizePanel;
 
58
 
 
59
import java.awt.BorderLayout;
 
60
import java.awt.Dimension;
 
61
import java.awt.Font;
 
62
import java.awt.GridBagConstraints;
 
63
import java.awt.GridBagLayout;
 
64
import java.awt.GridLayout;
 
65
import java.awt.Insets;
 
66
import java.awt.Point;
 
67
import java.awt.event.ActionEvent;
 
68
import java.awt.event.ActionListener;
 
69
import java.awt.event.InputEvent;
 
70
import java.awt.event.MouseAdapter;
 
71
import java.awt.event.MouseEvent;
 
72
import java.beans.PropertyChangeEvent;
 
73
import java.beans.PropertyChangeListener;
 
74
import java.io.File;
 
75
import java.io.FileInputStream;
 
76
import java.io.FileOutputStream;
 
77
import java.io.InputStream;
 
78
import java.io.ObjectInputStream;
 
79
import java.io.ObjectOutputStream;
 
80
import java.io.OutputStream;
 
81
import java.text.SimpleDateFormat;
 
82
import java.util.Date;
 
83
import java.util.Random;
 
84
import java.util.zip.GZIPInputStream;
 
85
import java.util.zip.GZIPOutputStream;
 
86
 
 
87
import javax.swing.BorderFactory;
 
88
import javax.swing.ButtonGroup;
 
89
import javax.swing.DefaultComboBoxModel;
 
90
import javax.swing.DefaultListModel;
 
91
import javax.swing.JButton;
 
92
import javax.swing.JCheckBox;
 
93
import javax.swing.JComboBox;
 
94
import javax.swing.JFileChooser;
 
95
import javax.swing.JFrame;
 
96
import javax.swing.JLabel;
 
97
import javax.swing.JList;
 
98
import javax.swing.JMenuItem;
 
99
import javax.swing.JOptionPane;
 
100
import javax.swing.JPanel;
 
101
import javax.swing.JPopupMenu;
 
102
import javax.swing.JRadioButton;
 
103
import javax.swing.JScrollPane;
 
104
import javax.swing.JTextArea;
 
105
import javax.swing.JTextField;
 
106
import javax.swing.JViewport;
 
107
import javax.swing.SwingConstants;
 
108
import javax.swing.event.ChangeEvent;
 
109
import javax.swing.event.ChangeListener;
 
110
import javax.swing.filechooser.FileFilter;
 
111
 
 
112
/** 
 
113
 * This panel allows the user to select and configure a clusterer, and evaluate
 
114
 * the clusterer using a number of testing modes (test on the training data,
 
115
 * train/test on a percentage split, test on a
 
116
 * separate split). The results of clustering runs are stored in a result
 
117
 * history so that previous results are accessible.
 
118
 *
 
119
 * @author Mark Hall (mhall@cs.waikato.ac.nz)
 
120
 * @author Richard Kirkby (rkirkby@cs.waikato.ac.nz)
 
121
 * @version $Revision: 1.60 $
 
122
 */
 
123
public class ClustererPanel
 
124
  extends JPanel
 
125
  implements CapabilitiesFilterChangeListener, ExplorerPanel, LogHandler {
 
126
 
 
127
  /** for serialization */
 
128
  static final long serialVersionUID = -2474932792950820990L;
 
129
 
 
130
  /** the parent frame */
 
131
  protected Explorer m_Explorer = null;
 
132
  
 
133
  /** The filename extension that should be used for model files */
 
134
  public static String MODEL_FILE_EXTENSION = ".model";
 
135
 
 
136
  /** Lets the user configure the clusterer */
 
137
  protected GenericObjectEditor m_ClustererEditor =
 
138
    new GenericObjectEditor();
 
139
 
 
140
  /** The panel showing the current clusterer selection */
 
141
  protected PropertyPanel m_CLPanel = new PropertyPanel(m_ClustererEditor);
 
142
  
 
143
  /** The output area for classification results */
 
144
  protected JTextArea m_OutText = new JTextArea(20, 40);
 
145
 
 
146
  /** The destination for log/status messages */
 
147
  protected Logger m_Log = new SysErrLog();
 
148
 
 
149
  /** The buffer saving object for saving output */
 
150
  SaveBuffer m_SaveOut = new SaveBuffer(m_Log, this);
 
151
 
 
152
  /** A panel controlling results viewing */
 
153
  protected ResultHistoryPanel m_History = new ResultHistoryPanel(m_OutText);
 
154
 
 
155
  /** Click to set test mode to generate a % split */
 
156
  protected JRadioButton m_PercentBut = new JRadioButton("Percentage split");
 
157
 
 
158
  /** Click to set test mode to test on training data */
 
159
  protected JRadioButton m_TrainBut = new JRadioButton("Use training set");
 
160
 
 
161
  /** Click to set test mode to a user-specified test set */
 
162
  protected JRadioButton m_TestSplitBut =
 
163
    new JRadioButton("Supplied test set");
 
164
 
 
165
  /** Click to set test mode to classes to clusters based evaluation */
 
166
  protected JRadioButton m_ClassesToClustersBut = 
 
167
    new JRadioButton("Classes to clusters evaluation");
 
168
 
 
169
  /** Lets the user select the class column for classes to clusters based
 
170
      evaluation */
 
171
  protected JComboBox m_ClassCombo = new JComboBox();
 
172
 
 
173
  /** Label by where the % split is entered */
 
174
  protected JLabel m_PercentLab = new JLabel("%", SwingConstants.RIGHT);
 
175
 
 
176
  /** The field where the % split is entered */
 
177
  protected JTextField m_PercentText = new JTextField("66");
 
178
 
 
179
  /** The button used to open a separate test dataset */
 
180
  protected JButton m_SetTestBut = new JButton("Set...");
 
181
 
 
182
  /** The frame used to show the test set selection panel */
 
183
  protected JFrame m_SetTestFrame;
 
184
 
 
185
  /** The button used to popup a list for choosing attributes to ignore while
 
186
      clustering */
 
187
  protected JButton m_ignoreBut = new JButton("Ignore attributes");
 
188
 
 
189
  protected DefaultListModel m_ignoreKeyModel = new DefaultListModel();
 
190
  protected JList m_ignoreKeyList = new JList(m_ignoreKeyModel);
 
191
 
 
192
  //  protected Remove m_ignoreFilter = null;
 
193
  
 
194
  /**
 
195
   * Alters the enabled/disabled status of elements associated with each
 
196
   * radio button
 
197
   */
 
198
  ActionListener m_RadioListener = new ActionListener() {
 
199
    public void actionPerformed(ActionEvent e) {
 
200
      updateRadioLinks();
 
201
    }
 
202
  };
 
203
 
 
204
  /** Click to start running the clusterer */
 
205
  protected JButton m_StartBut = new JButton("Start");
 
206
 
 
207
  /** Stop the class combo from taking up to much space */
 
208
  private Dimension COMBO_SIZE = new Dimension(250, m_StartBut
 
209
                                               .getPreferredSize().height);
 
210
 
 
211
  /** Click to stop a running clusterer */
 
212
  protected JButton m_StopBut = new JButton("Stop");
 
213
 
 
214
  /** The main set of instances we're playing with */
 
215
  protected Instances m_Instances;
 
216
 
 
217
  /** The user-supplied test set (if any) */
 
218
  protected Instances m_TestInstances;
 
219
 
 
220
  /** The current visualization object */
 
221
  protected VisualizePanel m_CurrentVis = null;
 
222
 
 
223
  /** Check to save the predictions in the results list for visualizing
 
224
      later on */
 
225
  protected JCheckBox m_StorePredictionsBut = 
 
226
    new JCheckBox("Store clusters for visualization");
 
227
  
 
228
  /** A thread that clustering runs in */
 
229
  protected Thread m_RunThread;
 
230
  
 
231
  /** The instances summary panel displayed by m_SetTestFrame */
 
232
  protected InstancesSummaryPanel m_Summary;
 
233
 
 
234
  /** Filter to ensure only model files are selected */  
 
235
  protected FileFilter m_ModelFilter =
 
236
    new ExtensionFileFilter(MODEL_FILE_EXTENSION, "Model object files");
 
237
 
 
238
  /** The file chooser for selecting model files */
 
239
  protected JFileChooser m_FileChooser 
 
240
    = new JFileChooser(new File(System.getProperty("user.dir")));
 
241
 
 
242
  /* Register the property editors we need */
 
243
  static {
 
244
     GenericObjectEditor.registerEditors();
 
245
  }
 
246
  
 
247
  /**
 
248
   * Creates the clusterer panel
 
249
   */
 
250
  public ClustererPanel() {
 
251
 
 
252
    // Connect / configure the components
 
253
    m_OutText.setEditable(false);
 
254
    m_OutText.setFont(new Font("Monospaced", Font.PLAIN, 12));
 
255
    m_OutText.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
 
256
    m_OutText.addMouseListener(new MouseAdapter() {
 
257
      public void mouseClicked(MouseEvent e) {
 
258
        if ((e.getModifiers() & InputEvent.BUTTON1_MASK)
 
259
            != InputEvent.BUTTON1_MASK) {
 
260
          m_OutText.selectAll();
 
261
        }
 
262
      }
 
263
    });
 
264
    m_History.setBorder(BorderFactory.createTitledBorder("Result list (right-click for options)"));
 
265
    m_ClustererEditor.setClassType(Clusterer.class);
 
266
    m_ClustererEditor.setValue(ExplorerDefaults.getClusterer());
 
267
    m_ClustererEditor.addPropertyChangeListener(new PropertyChangeListener() {
 
268
      public void propertyChange(PropertyChangeEvent e) {
 
269
        repaint();
 
270
      }
 
271
    });
 
272
 
 
273
    m_TrainBut.setToolTipText("Cluster the same set that the clusterer"
 
274
                              + " is trained on");
 
275
    m_PercentBut.setToolTipText("Train on a percentage of the data and"
 
276
                                + " cluster the remainder");
 
277
    m_TestSplitBut.setToolTipText("Cluster a user-specified dataset");
 
278
    m_ClassesToClustersBut.setToolTipText("Evaluate clusters with respect to a"
 
279
                                          +" class");
 
280
    m_ClassCombo.setToolTipText("Select the class attribute for class based"
 
281
                                +" evaluation");
 
282
    m_StartBut.setToolTipText("Starts the clustering");
 
283
    m_StopBut.setToolTipText("Stops a running clusterer");
 
284
    m_StorePredictionsBut.
 
285
      setToolTipText("Store predictions in the result list for later "
 
286
                     +"visualization");
 
287
    m_ignoreBut.setToolTipText("Ignore attributes during clustering");
 
288
 
 
289
    m_FileChooser.setFileFilter(m_ModelFilter);
 
290
    m_FileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
 
291
 
 
292
    m_ClassCombo.setPreferredSize(COMBO_SIZE);
 
293
    m_ClassCombo.setMaximumSize(COMBO_SIZE);
 
294
    m_ClassCombo.setMinimumSize(COMBO_SIZE);
 
295
    m_ClassCombo.setEnabled(false);
 
296
 
 
297
    m_PercentBut.setSelected(ExplorerDefaults.getClustererTestMode() == 2);
 
298
    m_TrainBut.setSelected(ExplorerDefaults.getClustererTestMode() == 3);
 
299
    m_TestSplitBut.setSelected(ExplorerDefaults.getClustererTestMode() == 4);
 
300
    m_ClassesToClustersBut.setSelected(ExplorerDefaults.getClustererTestMode() == 5);
 
301
    m_StorePredictionsBut.setSelected(ExplorerDefaults.getClustererStoreClustersForVis());
 
302
    updateRadioLinks();
 
303
    ButtonGroup bg = new ButtonGroup();
 
304
    bg.add(m_TrainBut);
 
305
    bg.add(m_PercentBut);
 
306
    bg.add(m_TestSplitBut);
 
307
    bg.add(m_ClassesToClustersBut);
 
308
    m_TrainBut.addActionListener(m_RadioListener);
 
309
    m_PercentBut.addActionListener(m_RadioListener);
 
310
    m_TestSplitBut.addActionListener(m_RadioListener);
 
311
    m_ClassesToClustersBut.addActionListener(m_RadioListener);
 
312
    m_SetTestBut.addActionListener(new ActionListener() {
 
313
      public void actionPerformed(ActionEvent e) {
 
314
        setTestSet();
 
315
      }
 
316
    });
 
317
 
 
318
    m_StartBut.setEnabled(false);
 
319
    m_StopBut.setEnabled(false);
 
320
    m_ignoreBut.setEnabled(false);
 
321
    m_StartBut.addActionListener(new ActionListener() {
 
322
      public void actionPerformed(ActionEvent e) {
 
323
        startClusterer();
 
324
      }
 
325
    });
 
326
    m_StopBut.addActionListener(new ActionListener() {
 
327
      public void actionPerformed(ActionEvent e) {
 
328
        stopClusterer();
 
329
      }
 
330
    });
 
331
 
 
332
    m_ignoreBut.addActionListener(new ActionListener() {
 
333
        public void actionPerformed(ActionEvent e) {
 
334
          setIgnoreColumns();
 
335
        }
 
336
      });
 
337
   
 
338
    m_History.setHandleRightClicks(false);
 
339
    // see if we can popup a menu for the selected result
 
340
    m_History.getList().addMouseListener(new MouseAdapter() {
 
341
        public void mouseClicked(MouseEvent e) {
 
342
          if (((e.getModifiers() & InputEvent.BUTTON1_MASK)
 
343
               != InputEvent.BUTTON1_MASK) || e.isAltDown()) {
 
344
            int index = m_History.getList().locationToIndex(e.getPoint());
 
345
            if (index != -1) {
 
346
              String name = m_History.getNameAtIndex(index);
 
347
              visualizeClusterer(name, e.getX(), e.getY());
 
348
            } else {
 
349
              visualizeClusterer(null, e.getX(), e.getY());
 
350
            }
 
351
          }
 
352
        }
 
353
      });
 
354
    
 
355
    m_ClassCombo.addActionListener(new ActionListener() {
 
356
      public void actionPerformed(ActionEvent e) {
 
357
        updateCapabilitiesFilter(m_ClustererEditor.getCapabilitiesFilter());
 
358
      }
 
359
    });
 
360
 
 
361
    // Layout the GUI
 
362
    JPanel p1 = new JPanel();
 
363
    p1.setBorder(BorderFactory.createCompoundBorder(
 
364
                 BorderFactory.createTitledBorder("Clusterer"),
 
365
                 BorderFactory.createEmptyBorder(0, 5, 5, 5)
 
366
                 ));
 
367
    p1.setLayout(new BorderLayout());
 
368
    p1.add(m_CLPanel, BorderLayout.NORTH);
 
369
 
 
370
    JPanel p2 = new JPanel();
 
371
    GridBagLayout gbL = new GridBagLayout();
 
372
    p2.setLayout(gbL);
 
373
    p2.setBorder(BorderFactory.createCompoundBorder(
 
374
                 BorderFactory.createTitledBorder("Cluster mode"),
 
375
                 BorderFactory.createEmptyBorder(0, 5, 5, 5)
 
376
                 ));
 
377
    GridBagConstraints gbC = new GridBagConstraints();
 
378
    gbC.anchor = GridBagConstraints.WEST;
 
379
    gbC.gridy = 0;     gbC.gridx = 0;
 
380
    gbL.setConstraints(m_TrainBut, gbC);
 
381
    p2.add(m_TrainBut);
 
382
 
 
383
    gbC = new GridBagConstraints();
 
384
    gbC.anchor = GridBagConstraints.WEST;
 
385
    gbC.gridy = 1;     gbC.gridx = 0;
 
386
    gbL.setConstraints(m_TestSplitBut, gbC);
 
387
    p2.add(m_TestSplitBut);
 
388
 
 
389
    gbC = new GridBagConstraints();
 
390
    gbC.anchor = GridBagConstraints.EAST;
 
391
    gbC.fill = GridBagConstraints.HORIZONTAL;
 
392
    gbC.gridy = 1;     gbC.gridx = 1;    gbC.gridwidth = 2;
 
393
    gbC.insets = new Insets(2, 10, 2, 0);
 
394
    gbL.setConstraints(m_SetTestBut, gbC);
 
395
    p2.add(m_SetTestBut);
 
396
 
 
397
    gbC = new GridBagConstraints();
 
398
    gbC.anchor = GridBagConstraints.WEST;
 
399
    gbC.gridy = 2;     gbC.gridx = 0;
 
400
    gbL.setConstraints(m_PercentBut, gbC);
 
401
    p2.add(m_PercentBut);
 
402
 
 
403
    gbC = new GridBagConstraints();
 
404
    gbC.anchor = GridBagConstraints.EAST;
 
405
    gbC.fill = GridBagConstraints.HORIZONTAL;
 
406
    gbC.gridy = 2;     gbC.gridx = 1;
 
407
    gbC.insets = new Insets(2, 10, 2, 10);
 
408
    gbL.setConstraints(m_PercentLab, gbC);
 
409
    p2.add(m_PercentLab);
 
410
 
 
411
    gbC = new GridBagConstraints();
 
412
    gbC.anchor = GridBagConstraints.EAST;
 
413
    gbC.fill = GridBagConstraints.HORIZONTAL;
 
414
    gbC.gridy = 2;     gbC.gridx = 2;  gbC.weightx = 100;
 
415
    gbC.ipadx = 20;
 
416
    gbL.setConstraints(m_PercentText, gbC);
 
417
    p2.add(m_PercentText);
 
418
 
 
419
    gbC = new GridBagConstraints();
 
420
    gbC.anchor = GridBagConstraints.WEST;
 
421
    gbC.gridy = 3;     gbC.gridx = 0;  gbC.gridwidth = 2;
 
422
    gbL.setConstraints(m_ClassesToClustersBut, gbC);
 
423
    p2.add(m_ClassesToClustersBut);
 
424
 
 
425
    m_ClassCombo.setBorder(BorderFactory.createEmptyBorder(0, 20, 0, 0));
 
426
    gbC = new GridBagConstraints();
 
427
    gbC.anchor = GridBagConstraints.WEST;
 
428
    gbC.gridy = 4;     gbC.gridx = 0;  gbC.gridwidth = 2;
 
429
    gbL.setConstraints(m_ClassCombo, gbC);
 
430
    p2.add(m_ClassCombo);
 
431
 
 
432
    gbC = new GridBagConstraints();
 
433
    gbC.anchor = GridBagConstraints.WEST;
 
434
    gbC.gridy = 5;     gbC.gridx = 0;  gbC.gridwidth = 2;
 
435
    gbL.setConstraints(m_StorePredictionsBut, gbC);
 
436
    p2.add(m_StorePredictionsBut);
 
437
 
 
438
    JPanel buttons = new JPanel();
 
439
    buttons.setLayout(new GridLayout(2, 1));
 
440
    JPanel ssButs = new JPanel();
 
441
    ssButs.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
 
442
    ssButs.setLayout(new GridLayout(1, 2, 5, 5));
 
443
    ssButs.add(m_StartBut);
 
444
    ssButs.add(m_StopBut);
 
445
 
 
446
    JPanel ib = new JPanel();
 
447
    ib.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
 
448
    ib.setLayout(new GridLayout(1, 1, 5, 5));
 
449
    ib.add(m_ignoreBut);
 
450
    buttons.add(ib);
 
451
    buttons.add(ssButs);
 
452
    
 
453
    JPanel p3 = new JPanel();
 
454
    p3.setBorder(BorderFactory.createTitledBorder("Clusterer output"));
 
455
    p3.setLayout(new BorderLayout());
 
456
    final JScrollPane js = new JScrollPane(m_OutText);
 
457
    p3.add(js, BorderLayout.CENTER);
 
458
    js.getViewport().addChangeListener(new ChangeListener() {
 
459
      private int lastHeight;
 
460
      public void stateChanged(ChangeEvent e) {
 
461
        JViewport vp = (JViewport)e.getSource();
 
462
        int h = vp.getViewSize().height; 
 
463
        if (h != lastHeight) { // i.e. an addition not just a user scrolling
 
464
          lastHeight = h;
 
465
          int x = h - vp.getExtentSize().height;
 
466
          vp.setViewPosition(new Point(0, x));
 
467
        }
 
468
      }
 
469
    });    
 
470
 
 
471
    JPanel mondo = new JPanel();
 
472
    gbL = new GridBagLayout();
 
473
    mondo.setLayout(gbL);
 
474
    gbC = new GridBagConstraints();
 
475
    //    gbC.anchor = GridBagConstraints.WEST;
 
476
    gbC.fill = GridBagConstraints.HORIZONTAL;
 
477
    gbC.gridy = 0;     gbC.gridx = 0;
 
478
    gbL.setConstraints(p2, gbC);
 
479
    mondo.add(p2);
 
480
    gbC = new GridBagConstraints();
 
481
    gbC.anchor = GridBagConstraints.NORTH;
 
482
    gbC.fill = GridBagConstraints.HORIZONTAL;
 
483
    gbC.gridy = 1;     gbC.gridx = 0;
 
484
    gbL.setConstraints(buttons, gbC);
 
485
    mondo.add(buttons);
 
486
    gbC = new GridBagConstraints();
 
487
    //gbC.anchor = GridBagConstraints.NORTH;
 
488
    gbC.fill = GridBagConstraints.BOTH;
 
489
    gbC.gridy = 2;     gbC.gridx = 0; gbC.weightx = 0;
 
490
    gbL.setConstraints(m_History, gbC);
 
491
    mondo.add(m_History);
 
492
    gbC = new GridBagConstraints();
 
493
    gbC.fill = GridBagConstraints.BOTH;
 
494
    gbC.gridy = 0;     gbC.gridx = 1;
 
495
    gbC.gridheight = 3;
 
496
    gbC.weightx = 100; gbC.weighty = 100;
 
497
    gbL.setConstraints(p3, gbC);
 
498
    mondo.add(p3);
 
499
 
 
500
    setLayout(new BorderLayout());
 
501
    add(p1, BorderLayout.NORTH);
 
502
    add(mondo, BorderLayout.CENTER);
 
503
  }
 
504
  
 
505
  /**
 
506
   * Updates the enabled status of the input fields and labels.
 
507
   */
 
508
  protected void updateRadioLinks() {
 
509
    
 
510
    m_SetTestBut.setEnabled(m_TestSplitBut.isSelected());
 
511
    if ((m_SetTestFrame != null) && (!m_TestSplitBut.isSelected())) {
 
512
      m_SetTestFrame.setVisible(false);
 
513
    }
 
514
    m_PercentText.setEnabled(m_PercentBut.isSelected());
 
515
    m_PercentLab.setEnabled(m_PercentBut.isSelected());
 
516
    m_ClassCombo.setEnabled(m_ClassesToClustersBut.isSelected());
 
517
  }
 
518
 
 
519
  /**
 
520
   * Sets the Logger to receive informational messages
 
521
   *
 
522
   * @param newLog the Logger that will now get info messages
 
523
   */
 
524
  public void setLog(Logger newLog) {
 
525
 
 
526
    m_Log = newLog;
 
527
  }
 
528
 
 
529
  /**
 
530
   * Tells the panel to use a new set of instances.
 
531
   *
 
532
   * @param inst a set of Instances
 
533
   */
 
534
  public void setInstances(Instances inst) {
 
535
 
 
536
    m_Instances = inst;
 
537
   
 
538
    m_ignoreKeyModel.removeAllElements();
 
539
    
 
540
    String [] attribNames = new String [m_Instances.numAttributes()];
 
541
    for (int i = 0; i < m_Instances.numAttributes(); i++) {
 
542
      String name = m_Instances.attribute(i).name();
 
543
      m_ignoreKeyModel.addElement(name);
 
544
 
 
545
       String type = "";
 
546
      switch (m_Instances.attribute(i).type()) {
 
547
      case Attribute.NOMINAL:
 
548
        type = "(Nom) ";
 
549
        break;
 
550
      case Attribute.NUMERIC:
 
551
        type = "(Num) ";
 
552
        break;
 
553
      case Attribute.STRING:
 
554
        type = "(Str) ";
 
555
        break;
 
556
      case Attribute.DATE:
 
557
        type = "(Dat) ";
 
558
        break;
 
559
      case Attribute.RELATIONAL:
 
560
        type = "(Rel) ";
 
561
        break;
 
562
      default:
 
563
        type = "(???) ";
 
564
      }
 
565
      String attnm = m_Instances.attribute(i).name();
 
566
     
 
567
      attribNames[i] = type + attnm;
 
568
    }
 
569
 
 
570
    
 
571
    m_StartBut.setEnabled(m_RunThread == null);
 
572
    m_StopBut.setEnabled(m_RunThread != null);
 
573
    m_ignoreBut.setEnabled(true);
 
574
    m_ClassCombo.setModel(new DefaultComboBoxModel(attribNames));
 
575
    if (inst.classIndex() == -1)
 
576
      m_ClassCombo.setSelectedIndex(attribNames.length - 1);
 
577
    else
 
578
      m_ClassCombo.setSelectedIndex(inst.classIndex());
 
579
    updateRadioLinks();
 
580
  }
 
581
 
 
582
  /**
 
583
   * Sets the user test set. Information about the current test set
 
584
   * is displayed in an InstanceSummaryPanel and the user is given the
 
585
   * ability to load another set from a file or url.
 
586
   *
 
587
   */
 
588
  protected void setTestSet() {
 
589
 
 
590
    if (m_SetTestFrame == null) {
 
591
      final SetInstancesPanel sp = new SetInstancesPanel();
 
592
      sp.setReadIncrementally(false);
 
593
      m_Summary = sp.getSummary();
 
594
      if (m_TestInstances != null) {
 
595
        sp.setInstances(m_TestInstances);
 
596
      }
 
597
      sp.addPropertyChangeListener(new PropertyChangeListener() {
 
598
        public void propertyChange(PropertyChangeEvent e) {
 
599
          m_TestInstances = sp.getInstances();
 
600
          m_TestInstances.setClassIndex(-1);  // make sure that no class attribute is set!
 
601
        }
 
602
      });
 
603
      // Add propertychangelistener to update m_TestInstances whenever
 
604
      // it changes in the settestframe
 
605
      m_SetTestFrame = new JFrame("Test Instances");
 
606
      sp.setParentFrame(m_SetTestFrame);   // enable Close-Button
 
607
      m_SetTestFrame.getContentPane().setLayout(new BorderLayout());
 
608
      m_SetTestFrame.getContentPane().add(sp, BorderLayout.CENTER);
 
609
      m_SetTestFrame.pack();
 
610
    }
 
611
    m_SetTestFrame.setVisible(true);
 
612
  }
 
613
 
 
614
  /**
 
615
   * Sets up the structure for the visualizable instances. This dataset
 
616
   * contains the original attributes plus the clusterer's cluster assignments
 
617
   * @param testInstances the instances that the clusterer has clustered
 
618
   * @param eval the evaluation to use
 
619
   * @return a PlotData2D object encapsulating the visualizable instances. The    
 
620
   * instances contain one more attribute (predicted
 
621
   * cluster) than the testInstances
 
622
   */
 
623
  public static PlotData2D setUpVisualizableInstances(Instances testInstances,
 
624
                                                      ClusterEvaluation eval) 
 
625
    throws Exception {
 
626
 
 
627
    int numClusters = eval.getNumClusters();
 
628
    double [] clusterAssignments = eval.getClusterAssignments();
 
629
 
 
630
    FastVector hv = new FastVector();
 
631
    Instances newInsts;
 
632
 
 
633
    Attribute predictedCluster;
 
634
    FastVector clustVals = new FastVector();
 
635
 
 
636
    for (int i = 0; i < numClusters; i++) {
 
637
      clustVals.addElement("cluster"+i);
 
638
    }
 
639
    predictedCluster = new Attribute("Cluster", clustVals);
 
640
    for (int i = 0; i < testInstances.numAttributes(); i++) {
 
641
      hv.addElement(testInstances.attribute(i).copy());
 
642
    }
 
643
    hv.addElement(predictedCluster);
 
644
    
 
645
    newInsts = new Instances(testInstances.relationName()+"_clustered", hv, 
 
646
                             testInstances.numInstances());
 
647
 
 
648
    double [] values;
 
649
    int j;
 
650
    int [] pointShapes = null;
 
651
    int [] classAssignments = null;
 
652
    if (testInstances.classIndex() >= 0) {
 
653
      classAssignments = eval.getClassesToClusters();
 
654
      pointShapes = new int[testInstances.numInstances()];
 
655
      for (int i = 0; i < testInstances.numInstances(); i++) {
 
656
        pointShapes[i] = Plot2D.CONST_AUTOMATIC_SHAPE;
 
657
      }
 
658
    }
 
659
 
 
660
    for (int i = 0; i < testInstances.numInstances(); i++) {
 
661
      values = new double[newInsts.numAttributes()];
 
662
      for (j = 0; j < testInstances.numAttributes(); j++) {
 
663
        values[j] = testInstances.instance(i).value(j);
 
664
      }
 
665
      values[j] = clusterAssignments[i];
 
666
      newInsts.add(new Instance(1.0, values));
 
667
      if (pointShapes != null) {
 
668
        if ((int)testInstances.instance(i).classValue() != 
 
669
            classAssignments[(int)clusterAssignments[i]]) {
 
670
          pointShapes[i] = Plot2D.ERROR_SHAPE;
 
671
        }
 
672
      }
 
673
    }
 
674
    PlotData2D plotData = new PlotData2D(newInsts);
 
675
    if (pointShapes != null) {
 
676
      plotData.setShapeType(pointShapes);
 
677
    }
 
678
    plotData.addInstanceNumberAttribute();
 
679
    return plotData;
 
680
  }
 
681
  
 
682
  /**
 
683
   * Starts running the currently configured clusterer with the current
 
684
   * settings. This is run in a separate thread, and will only start if
 
685
   * there is no clusterer already running. The clusterer output is sent
 
686
   * to the results history panel.
 
687
   */
 
688
  protected void startClusterer() {
 
689
 
 
690
    if (m_RunThread == null) {
 
691
      m_StartBut.setEnabled(false);
 
692
      m_StopBut.setEnabled(true);
 
693
      m_ignoreBut.setEnabled(false);
 
694
      m_RunThread = new Thread() {
 
695
        public void run() {
 
696
          // Copy the current state of things
 
697
          m_Log.statusMessage("Setting up...");
 
698
          Instances inst = new Instances(m_Instances);
 
699
          inst.setClassIndex(-1);
 
700
          Instances userTest = null;
 
701
          PlotData2D predData = null;
 
702
          if (m_TestInstances != null) {
 
703
            userTest = new Instances(m_TestInstances);
 
704
          }
 
705
          
 
706
          boolean saveVis = m_StorePredictionsBut.isSelected();
 
707
          String grph = null;
 
708
          int[] ignoredAtts = null;
 
709
 
 
710
          int testMode = 0;
 
711
          int percent = 66;
 
712
          Clusterer clusterer = (Clusterer) m_ClustererEditor.getValue();
 
713
          Clusterer fullClusterer = null;
 
714
          StringBuffer outBuff = new StringBuffer();
 
715
          String name = (new SimpleDateFormat("HH:mm:ss - "))
 
716
          .format(new Date());
 
717
          String cname = clusterer.getClass().getName();
 
718
          if (cname.startsWith("weka.clusterers.")) {
 
719
            name += cname.substring("weka.clusterers.".length());
 
720
          } else {
 
721
            name += cname;
 
722
          }
 
723
          String cmd = m_ClustererEditor.getValue().getClass().getName();
 
724
          if (m_ClustererEditor.getValue() instanceof OptionHandler)
 
725
            cmd += " " + Utils.joinOptions(((OptionHandler) m_ClustererEditor.getValue()).getOptions());
 
726
          try {
 
727
            m_Log.logMessage("Started " + cname);
 
728
            m_Log.logMessage("Command: " + cmd);
 
729
            if (m_Log instanceof TaskLogger) {
 
730
              ((TaskLogger)m_Log).taskStarted();
 
731
            }
 
732
            if (m_PercentBut.isSelected()) {
 
733
              testMode = 2;
 
734
              percent = Integer.parseInt(m_PercentText.getText());
 
735
              if ((percent <= 0) || (percent >= 100)) {
 
736
                throw new Exception("Percentage must be between 0 and 100");
 
737
              }
 
738
            } else if (m_TrainBut.isSelected()) {
 
739
              testMode = 3;
 
740
            } else if (m_TestSplitBut.isSelected()) {
 
741
              testMode = 4;
 
742
              // Check the test instance compatibility
 
743
              if (userTest == null) {
 
744
                throw new Exception("No user test set has been opened");
 
745
              }
 
746
              if (!inst.equalHeaders(userTest)) {
 
747
                throw new Exception("Train and test set are not compatible");
 
748
              }
 
749
            } else if (m_ClassesToClustersBut.isSelected()) {
 
750
              testMode = 5;
 
751
            } else {
 
752
              throw new Exception("Unknown test mode");
 
753
            }
 
754
 
 
755
            Instances trainInst = new Instances(inst);
 
756
            if (m_ClassesToClustersBut.isSelected()) {
 
757
              trainInst.setClassIndex(m_ClassCombo.getSelectedIndex());
 
758
              inst.setClassIndex(m_ClassCombo.getSelectedIndex());
 
759
              if (inst.classAttribute().isNumeric()) {
 
760
                throw new Exception("Class must be nominal for class based "
 
761
                                    +"evaluation!");
 
762
              }
 
763
            }
 
764
            if (!m_ignoreKeyList.isSelectionEmpty()) {
 
765
              trainInst = removeIgnoreCols(trainInst);
 
766
            }
 
767
 
 
768
            // Output some header information
 
769
            outBuff.append("=== Run information ===\n\n");
 
770
            outBuff.append("Scheme:       " + cname);
 
771
            if (clusterer instanceof OptionHandler) {
 
772
              String [] o = ((OptionHandler) clusterer).getOptions();
 
773
              outBuff.append(" " + Utils.joinOptions(o));
 
774
            }
 
775
            outBuff.append("\n");
 
776
            outBuff.append("Relation:     " + inst.relationName() + '\n');
 
777
            outBuff.append("Instances:    " + inst.numInstances() + '\n');
 
778
            outBuff.append("Attributes:   " + inst.numAttributes() + '\n');
 
779
            if (inst.numAttributes() < 100) {
 
780
              boolean [] selected = new boolean [inst.numAttributes()];
 
781
              for (int i = 0; i < inst.numAttributes(); i++) {
 
782
                selected[i] = true;
 
783
              }
 
784
              if (!m_ignoreKeyList.isSelectionEmpty()) {
 
785
                int [] indices = m_ignoreKeyList.getSelectedIndices();
 
786
                for (int i = 0; i < indices.length; i++) {
 
787
                  selected[indices[i]] = false;
 
788
                }
 
789
              }
 
790
              if (m_ClassesToClustersBut.isSelected()) {
 
791
                selected[m_ClassCombo.getSelectedIndex()] = false;
 
792
              }
 
793
              for (int i = 0; i < inst.numAttributes(); i++) {
 
794
                if (selected[i]) {
 
795
                  outBuff.append("              " + inst.attribute(i).name()
 
796
                                 + '\n');
 
797
                }
 
798
              }
 
799
              if (!m_ignoreKeyList.isSelectionEmpty() 
 
800
                  || m_ClassesToClustersBut.isSelected()) {
 
801
                outBuff.append("Ignored:\n");
 
802
                for (int i = 0; i < inst.numAttributes(); i++) {
 
803
                  if (!selected[i]) {
 
804
                    outBuff.append("              " + inst.attribute(i).name()
 
805
                                   + '\n');
 
806
                  }
 
807
                }
 
808
              }
 
809
            } else {
 
810
              outBuff.append("              [list of attributes omitted]\n");
 
811
            }
 
812
 
 
813
            if (!m_ignoreKeyList.isSelectionEmpty()) {
 
814
              ignoredAtts = m_ignoreKeyList.getSelectedIndices();
 
815
            }
 
816
 
 
817
            if (m_ClassesToClustersBut.isSelected()) {
 
818
              // add class to ignored list
 
819
              if (ignoredAtts == null) {
 
820
                ignoredAtts = new int[1];
 
821
                ignoredAtts[0] = m_ClassCombo.getSelectedIndex();
 
822
              } else {
 
823
                int[] newIgnoredAtts = new int[ignoredAtts.length+1];
 
824
                System.arraycopy(ignoredAtts, 0, newIgnoredAtts, 0, ignoredAtts.length);
 
825
                newIgnoredAtts[ignoredAtts.length] = m_ClassCombo.getSelectedIndex();
 
826
                ignoredAtts = newIgnoredAtts;
 
827
              }
 
828
            }
 
829
 
 
830
 
 
831
            outBuff.append("Test mode:    ");
 
832
            switch (testMode) {
 
833
              case 3: // Test on training
 
834
              outBuff.append("evaluate on training data\n");
 
835
              break;
 
836
              case 2: // Percent split
 
837
              outBuff.append("split " + percent
 
838
                               + "% train, remainder test\n");
 
839
              break;
 
840
              case 4: // Test on user split
 
841
              outBuff.append("user supplied test set: "
 
842
                             + userTest.numInstances() + " instances\n");
 
843
              break;
 
844
            case 5: // Classes to clusters evaluation on training
 
845
              outBuff.append("Classes to clusters evaluation on training data");
 
846
              
 
847
              break;
 
848
            }
 
849
            outBuff.append("\n");
 
850
            m_History.addResult(name, outBuff);
 
851
            m_History.setSingle(name);
 
852
            
 
853
            // Build the model and output it.
 
854
            m_Log.statusMessage("Building model on training data...");
 
855
 
 
856
            // remove the class attribute (if set) and build the clusterer
 
857
            clusterer.buildClusterer(removeClass(trainInst));
 
858
            
 
859
            if (testMode == 2) {
 
860
              outBuff.append("\n=== Clustering model (full training set) ===\n\n");
 
861
            
 
862
              outBuff.append(clusterer.toString() + '\n');
 
863
            }
 
864
            m_History.updateResult(name);
 
865
            if (clusterer instanceof Drawable) {
 
866
              try {
 
867
                grph = ((Drawable)clusterer).graph();
 
868
              } catch (Exception ex) {
 
869
              }
 
870
            }
 
871
            // copy full model for output
 
872
            SerializedObject so = new SerializedObject(clusterer);
 
873
            fullClusterer = (Clusterer) so.getObject();
 
874
            
 
875
            ClusterEvaluation eval = new ClusterEvaluation();
 
876
            eval.setClusterer(clusterer);
 
877
            switch (testMode) {
 
878
              case 3: case 5: // Test on training
 
879
              m_Log.statusMessage("Clustering training data...");
 
880
              eval.evaluateClusterer(trainInst);
 
881
              predData = setUpVisualizableInstances(inst,eval);
 
882
              outBuff.append("=== Model and evaluation on training set ===\n\n");
 
883
              break;
 
884
 
 
885
              case 2: // Percent split
 
886
              m_Log.statusMessage("Randomizing instances...");
 
887
              inst.randomize(new Random(1));
 
888
              trainInst.randomize(new Random(1));
 
889
              int trainSize = trainInst.numInstances() * percent / 100;
 
890
              int testSize = trainInst.numInstances() - trainSize;
 
891
              Instances train = new Instances(trainInst, 0, trainSize);
 
892
              Instances test = new Instances(trainInst, trainSize, testSize);
 
893
              Instances testVis = new Instances(inst, trainSize, testSize);
 
894
              m_Log.statusMessage("Building model on training split...");
 
895
              clusterer.buildClusterer(train);
 
896
              m_Log.statusMessage("Evaluating on test split...");
 
897
              eval.evaluateClusterer(test);
 
898
              predData = setUpVisualizableInstances(testVis, eval);
 
899
              outBuff.append("=== Model and evaluation on test split ===\n");
 
900
              break;
 
901
                
 
902
              case 4: // Test on user split
 
903
              m_Log.statusMessage("Evaluating on test data...");
 
904
              Instances userTestT = new Instances(userTest);
 
905
              if (!m_ignoreKeyList.isSelectionEmpty()) {
 
906
                userTestT = removeIgnoreCols(userTestT);
 
907
              }
 
908
              eval.evaluateClusterer(userTestT);
 
909
              predData = setUpVisualizableInstances(userTest, eval);
 
910
              outBuff.append("=== Model and evaluation on test set ===\n");
 
911
              break;
 
912
 
 
913
              default:
 
914
              throw new Exception("Test mode not implemented");
 
915
            }
 
916
            outBuff.append(eval.clusterResultsToString());
 
917
            outBuff.append("\n");
 
918
            m_History.updateResult(name);
 
919
            m_Log.logMessage("Finished " + cname);
 
920
            m_Log.statusMessage("OK");
 
921
          } catch (Exception ex) {
 
922
            ex.printStackTrace();
 
923
            m_Log.logMessage(ex.getMessage());
 
924
            JOptionPane.showMessageDialog(ClustererPanel.this,
 
925
                                          "Problem evaluating clusterer:\n"
 
926
                                          + ex.getMessage(),
 
927
                                          "Evaluate clusterer",
 
928
                                          JOptionPane.ERROR_MESSAGE);
 
929
            m_Log.statusMessage("Problem evaluating clusterer");
 
930
          } finally {
 
931
            if (predData != null) {
 
932
              m_CurrentVis = new VisualizePanel();
 
933
              m_CurrentVis.setName(name+" ("+inst.relationName()+")");
 
934
              m_CurrentVis.setLog(m_Log);
 
935
              predData.setPlotName(name+" ("+inst.relationName()+")");
 
936
              
 
937
              try {
 
938
                m_CurrentVis.addPlot(predData);
 
939
              } catch (Exception ex) {
 
940
                System.err.println(ex);
 
941
              }
 
942
 
 
943
              FastVector vv = new FastVector();
 
944
              vv.addElement(fullClusterer);
 
945
              Instances trainHeader = new Instances(m_Instances, 0);
 
946
              vv.addElement(trainHeader);
 
947
              if (ignoredAtts != null) vv.addElement(ignoredAtts);
 
948
              if (saveVis) {
 
949
                vv.addElement(m_CurrentVis);
 
950
                if (grph != null) {
 
951
                  vv.addElement(grph);
 
952
                }
 
953
                
 
954
              }
 
955
              m_History.addObject(name, vv);
 
956
            }
 
957
            if (isInterrupted()) {
 
958
              m_Log.logMessage("Interrupted " + cname);
 
959
              m_Log.statusMessage("See error log");
 
960
            }
 
961
            m_RunThread = null;
 
962
            m_StartBut.setEnabled(true);
 
963
            m_StopBut.setEnabled(false);
 
964
            m_ignoreBut.setEnabled(true);
 
965
            if (m_Log instanceof TaskLogger) {
 
966
              ((TaskLogger)m_Log).taskFinished();
 
967
            }
 
968
          }
 
969
        }
 
970
      };
 
971
      m_RunThread.setPriority(Thread.MIN_PRIORITY);
 
972
      m_RunThread.start();
 
973
    }
 
974
  }
 
975
 
 
976
  private Instances removeClass(Instances inst) {
 
977
    Remove af = new Remove();
 
978
    Instances retI = null;
 
979
    
 
980
    try {
 
981
      if (inst.classIndex() < 0) {
 
982
        retI = inst;
 
983
      } else {
 
984
        af.setAttributeIndices(""+(inst.classIndex()+1));
 
985
        af.setInvertSelection(false);
 
986
        af.setInputFormat(inst);
 
987
        retI = Filter.useFilter(inst, af);
 
988
      }
 
989
    } catch (Exception e) {
 
990
      e.printStackTrace();
 
991
    }
 
992
    return retI;
 
993
  }
 
994
 
 
995
  private Instances removeIgnoreCols(Instances inst) {
 
996
    
 
997
    // If the user is doing classes to clusters evaluation and
 
998
    // they have opted to ignore the class, then unselect the class in
 
999
    // the ignore list
 
1000
    if (m_ClassesToClustersBut.isSelected()) {
 
1001
      int classIndex = m_ClassCombo.getSelectedIndex();
 
1002
      if (m_ignoreKeyList.isSelectedIndex(classIndex)) {
 
1003
        m_ignoreKeyList.removeSelectionInterval(classIndex, classIndex);
 
1004
      }
 
1005
    }
 
1006
    int [] selected = m_ignoreKeyList.getSelectedIndices();
 
1007
    Remove af = new Remove();
 
1008
    Instances retI = null;
 
1009
 
 
1010
    try {
 
1011
      af.setAttributeIndicesArray(selected);
 
1012
      af.setInvertSelection(false);
 
1013
      af.setInputFormat(inst);
 
1014
      retI = Filter.useFilter(inst, af);
 
1015
    } catch (Exception e) {
 
1016
      e.printStackTrace();
 
1017
    }
 
1018
    
 
1019
    return retI;
 
1020
  }
 
1021
 
 
1022
  private Instances removeIgnoreCols(Instances inst, int[] toIgnore) {
 
1023
 
 
1024
    Remove af = new Remove();
 
1025
    Instances retI = null;
 
1026
 
 
1027
    try {
 
1028
      af.setAttributeIndicesArray(toIgnore);
 
1029
      af.setInvertSelection(false);
 
1030
      af.setInputFormat(inst);
 
1031
      retI = Filter.useFilter(inst, af);
 
1032
    } catch (Exception e) {
 
1033
      e.printStackTrace();
 
1034
    }
 
1035
    
 
1036
    return retI;
 
1037
  }
 
1038
 
 
1039
  /**
 
1040
   * Stops the currently running clusterer (if any).
 
1041
   */
 
1042
  protected void stopClusterer() {
 
1043
 
 
1044
    if (m_RunThread != null) {
 
1045
      m_RunThread.interrupt();
 
1046
      
 
1047
      // This is deprecated (and theoretically the interrupt should do).
 
1048
      m_RunThread.stop();
 
1049
      
 
1050
    }
 
1051
  }
 
1052
 
 
1053
  /**
 
1054
   * Pops up a TreeVisualizer for the clusterer from the currently
 
1055
   * selected item in the results list
 
1056
   * @param dottyString the description of the tree in dotty format
 
1057
   * @param treeName the title to assign to the display
 
1058
   */
 
1059
  protected void visualizeTree(String dottyString, String treeName) {
 
1060
    final javax.swing.JFrame jf = 
 
1061
      new javax.swing.JFrame("Weka Classifier Tree Visualizer: "+treeName);
 
1062
    jf.setSize(500,400);
 
1063
    jf.getContentPane().setLayout(new BorderLayout());
 
1064
    TreeVisualizer tv = new TreeVisualizer(null,
 
1065
                                           dottyString,
 
1066
                                           new PlaceNode2());
 
1067
    jf.getContentPane().add(tv, BorderLayout.CENTER);
 
1068
    jf.addWindowListener(new java.awt.event.WindowAdapter() {
 
1069
        public void windowClosing(java.awt.event.WindowEvent e) {
 
1070
          jf.dispose();
 
1071
        }
 
1072
      });
 
1073
    
 
1074
    jf.setVisible(true);
 
1075
    tv.fitToScreen();
 
1076
  }
 
1077
 
 
1078
  /**
 
1079
   * Pops up a visualize panel to display cluster assignments
 
1080
   * @param sp the visualize panel to display
 
1081
   */
 
1082
  protected void visualizeClusterAssignments(VisualizePanel sp) {
 
1083
    if (sp != null) {
 
1084
      String plotName = sp.getName();
 
1085
      final javax.swing.JFrame jf = 
 
1086
        new javax.swing.JFrame("Weka Clusterer Visualize: "+plotName);
 
1087
      jf.setSize(500,400);
 
1088
      jf.getContentPane().setLayout(new BorderLayout());
 
1089
      jf.getContentPane().add(sp, BorderLayout.CENTER);
 
1090
      jf.addWindowListener(new java.awt.event.WindowAdapter() {
 
1091
          public void windowClosing(java.awt.event.WindowEvent e) {
 
1092
            jf.dispose();
 
1093
          }
 
1094
        });
 
1095
 
 
1096
      jf.setVisible(true);
 
1097
    }
 
1098
  }
 
1099
 
 
1100
  /**
 
1101
   * Handles constructing a popup menu with visualization options
 
1102
   * @param name the name of the result history list entry clicked on by
 
1103
   * the user
 
1104
   * @param x the x coordinate for popping up the menu
 
1105
   * @param y the y coordinate for popping up the menu
 
1106
   */
 
1107
  protected void visualizeClusterer(String name, int x, int y) {
 
1108
    final String selectedName = name;
 
1109
    JPopupMenu resultListMenu = new JPopupMenu();
 
1110
 
 
1111
    JMenuItem visMainBuffer = new JMenuItem("View in main window");
 
1112
    if (selectedName != null) {
 
1113
      visMainBuffer.addActionListener(new ActionListener() {
 
1114
          public void actionPerformed(ActionEvent e) {
 
1115
            m_History.setSingle(selectedName);
 
1116
          }
 
1117
        });
 
1118
    } else {
 
1119
      visMainBuffer.setEnabled(false);
 
1120
    }
 
1121
    resultListMenu.add(visMainBuffer);
 
1122
 
 
1123
    JMenuItem visSepBuffer = new JMenuItem("View in separate window");
 
1124
    if (selectedName != null) {
 
1125
    visSepBuffer.addActionListener(new ActionListener() {
 
1126
        public void actionPerformed(ActionEvent e) {
 
1127
          m_History.openFrame(selectedName);
 
1128
        }
 
1129
      });
 
1130
    } else {
 
1131
      visSepBuffer.setEnabled(false);
 
1132
    }
 
1133
    resultListMenu.add(visSepBuffer);
 
1134
 
 
1135
    JMenuItem saveOutput = new JMenuItem("Save result buffer");
 
1136
    if (selectedName != null) {
 
1137
      saveOutput.addActionListener(new ActionListener() {
 
1138
          public void actionPerformed(ActionEvent e) {
 
1139
            saveBuffer(selectedName);
 
1140
          }
 
1141
        });
 
1142
    } else {
 
1143
      saveOutput.setEnabled(false);
 
1144
    }
 
1145
    resultListMenu.add(saveOutput);
 
1146
    
 
1147
    JMenuItem deleteOutput = new JMenuItem("Delete result buffer");
 
1148
    if (selectedName != null) {
 
1149
      deleteOutput.addActionListener(new ActionListener() {
 
1150
        public void actionPerformed(ActionEvent e) {
 
1151
          m_History.removeResult(selectedName);
 
1152
        }
 
1153
      });
 
1154
    } else {
 
1155
      deleteOutput.setEnabled(false);
 
1156
    }
 
1157
    resultListMenu.add(deleteOutput);
 
1158
 
 
1159
    resultListMenu.addSeparator();
 
1160
 
 
1161
    JMenuItem loadModel = new JMenuItem("Load model");
 
1162
    loadModel.addActionListener(new ActionListener() {
 
1163
        public void actionPerformed(ActionEvent e) {
 
1164
          loadClusterer();
 
1165
        }
 
1166
      });
 
1167
    resultListMenu.add(loadModel);
 
1168
 
 
1169
    FastVector o = null;
 
1170
    if (selectedName != null) {
 
1171
      o = (FastVector)m_History.getNamedObject(selectedName);
 
1172
    }
 
1173
 
 
1174
    VisualizePanel temp_vp = null;
 
1175
    String temp_grph = null;
 
1176
    Clusterer temp_clusterer = null;
 
1177
    Instances temp_trainHeader = null;
 
1178
    int[] temp_ignoreAtts = null;
 
1179
    
 
1180
    if (o != null) {
 
1181
      for (int i = 0; i < o.size(); i++) {
 
1182
        Object temp = o.elementAt(i);
 
1183
        if (temp instanceof Clusterer) {
 
1184
          temp_clusterer = (Clusterer)temp;
 
1185
        } else if (temp instanceof Instances) { // training header
 
1186
          temp_trainHeader = (Instances)temp;
 
1187
        } else if (temp instanceof int[]) { // ignored attributes
 
1188
          temp_ignoreAtts = (int[])temp;
 
1189
        } else if (temp instanceof VisualizePanel) { // normal errors
 
1190
          temp_vp = (VisualizePanel)temp;
 
1191
        } else if (temp instanceof String) { // graphable output
 
1192
          temp_grph = (String)temp;
 
1193
        }
 
1194
      } 
 
1195
    }
 
1196
      
 
1197
    final VisualizePanel vp = temp_vp;
 
1198
    final String grph = temp_grph;
 
1199
    final Clusterer clusterer = temp_clusterer;
 
1200
    final Instances trainHeader = temp_trainHeader;
 
1201
    final int[] ignoreAtts = temp_ignoreAtts;
 
1202
    
 
1203
    JMenuItem saveModel = new JMenuItem("Save model");
 
1204
    if (clusterer != null) {
 
1205
      saveModel.addActionListener(new ActionListener() {
 
1206
          public void actionPerformed(ActionEvent e) {
 
1207
            saveClusterer(selectedName, clusterer, trainHeader, ignoreAtts);
 
1208
          }
 
1209
        });
 
1210
    } else {
 
1211
      saveModel.setEnabled(false);
 
1212
    }
 
1213
    resultListMenu.add(saveModel);
 
1214
    
 
1215
    JMenuItem reEvaluate =
 
1216
      new JMenuItem("Re-evaluate model on current test set");
 
1217
    if (clusterer != null && m_TestInstances != null) {
 
1218
      reEvaluate.addActionListener(new ActionListener() {
 
1219
          public void actionPerformed(ActionEvent e) {
 
1220
            reevaluateModel(selectedName, clusterer, trainHeader, ignoreAtts);
 
1221
          }
 
1222
        }); 
 
1223
    } else {
 
1224
      reEvaluate.setEnabled(false);
 
1225
    }
 
1226
    resultListMenu.add(reEvaluate);
 
1227
    
 
1228
    resultListMenu.addSeparator();
 
1229
    
 
1230
    JMenuItem visClusts = new JMenuItem("Visualize cluster assignments");
 
1231
    if (vp != null) {
 
1232
      visClusts.addActionListener(new ActionListener() {
 
1233
            public void actionPerformed(ActionEvent e) {
 
1234
              visualizeClusterAssignments(vp);
 
1235
            }
 
1236
          });
 
1237
      
 
1238
    } else {
 
1239
      visClusts.setEnabled(false);
 
1240
    }
 
1241
    resultListMenu.add(visClusts);
 
1242
 
 
1243
    JMenuItem visTree = new JMenuItem("Visualize tree");
 
1244
    if (grph != null) {
 
1245
      visTree.addActionListener(new ActionListener() {
 
1246
          public void actionPerformed(ActionEvent e) {
 
1247
            String title;
 
1248
            if (vp != null) title = vp.getName();
 
1249
            else title = selectedName;
 
1250
            visualizeTree(grph, title);
 
1251
          }
 
1252
        });
 
1253
    } else {
 
1254
      visTree.setEnabled(false);
 
1255
    }
 
1256
    resultListMenu.add(visTree);
 
1257
 
 
1258
    resultListMenu.show(m_History.getList(), x, y);
 
1259
  }
 
1260
  
 
1261
  /**
 
1262
   * Save the currently selected clusterer output to a file.
 
1263
   * @param name the name of the buffer to save
 
1264
   */
 
1265
  protected void saveBuffer(String name) {
 
1266
    StringBuffer sb = m_History.getNamedBuffer(name);
 
1267
    if (sb != null) {
 
1268
      if (m_SaveOut.save(sb)) {
 
1269
        m_Log.logMessage("Save successful.");
 
1270
      }
 
1271
    }
 
1272
  }
 
1273
 
 
1274
  private void setIgnoreColumns() {
 
1275
    ListSelectorDialog jd = new ListSelectorDialog(null, m_ignoreKeyList);
 
1276
 
 
1277
    // Open the dialog
 
1278
    int result = jd.showDialog();
 
1279
    
 
1280
    if (result != ListSelectorDialog.APPROVE_OPTION) {
 
1281
      // clear selected indices
 
1282
      m_ignoreKeyList.clearSelection();
 
1283
    }
 
1284
  }
 
1285
 
 
1286
  /**
 
1287
   * Saves the currently selected clusterer
 
1288
   */
 
1289
  protected void saveClusterer(String name, Clusterer clusterer,
 
1290
                               Instances trainHeader, int[] ignoredAtts) {
 
1291
 
 
1292
    File sFile = null;
 
1293
    boolean saveOK = true;
 
1294
 
 
1295
    int returnVal = m_FileChooser.showSaveDialog(this);
 
1296
    if (returnVal == JFileChooser.APPROVE_OPTION) {
 
1297
      sFile = m_FileChooser.getSelectedFile();
 
1298
      if (!sFile.getName().toLowerCase().endsWith(MODEL_FILE_EXTENSION)) {
 
1299
        sFile = new File(sFile.getParent(), sFile.getName() 
 
1300
                         + MODEL_FILE_EXTENSION);
 
1301
      }
 
1302
      m_Log.statusMessage("Saving model to file...");
 
1303
      
 
1304
      try {
 
1305
        OutputStream os = new FileOutputStream(sFile);
 
1306
        if (sFile.getName().endsWith(".gz")) {
 
1307
          os = new GZIPOutputStream(os);
 
1308
        }
 
1309
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(os);
 
1310
        objectOutputStream.writeObject(clusterer);
 
1311
        if (trainHeader != null) objectOutputStream.writeObject(trainHeader);
 
1312
        if (ignoredAtts != null) objectOutputStream.writeObject(ignoredAtts);
 
1313
        objectOutputStream.flush();
 
1314
        objectOutputStream.close();
 
1315
      } catch (Exception e) {
 
1316
        
 
1317
        JOptionPane.showMessageDialog(null, e, "Save Failed",
 
1318
                                      JOptionPane.ERROR_MESSAGE);
 
1319
        saveOK = false;
 
1320
      }
 
1321
      if (saveOK)
 
1322
        m_Log.logMessage("Saved model (" + name
 
1323
                         + ") to file '" + sFile.getName() + "'");
 
1324
      m_Log.statusMessage("OK");
 
1325
    }
 
1326
  }
 
1327
 
 
1328
  /**
 
1329
   * Loads a clusterer
 
1330
   */
 
1331
  protected void loadClusterer() {
 
1332
 
 
1333
    int returnVal = m_FileChooser.showOpenDialog(this);
 
1334
    if (returnVal == JFileChooser.APPROVE_OPTION) {
 
1335
      File selected = m_FileChooser.getSelectedFile();
 
1336
      Clusterer clusterer = null;
 
1337
      Instances trainHeader = null;
 
1338
      int[] ignoredAtts = null;
 
1339
 
 
1340
      m_Log.statusMessage("Loading model from file...");
 
1341
 
 
1342
      try {
 
1343
        InputStream is = new FileInputStream(selected);
 
1344
        if (selected.getName().endsWith(".gz")) {
 
1345
          is = new GZIPInputStream(is);
 
1346
        }
 
1347
        ObjectInputStream objectInputStream = new ObjectInputStream(is);
 
1348
        clusterer = (Clusterer) objectInputStream.readObject();
 
1349
        try { // see if we can load the header & ignored attribute info
 
1350
          trainHeader = (Instances) objectInputStream.readObject();
 
1351
          ignoredAtts = (int[]) objectInputStream.readObject();
 
1352
        } catch (Exception e) {} // don't fuss if we can't
 
1353
        objectInputStream.close();
 
1354
      } catch (Exception e) {
 
1355
        
 
1356
        JOptionPane.showMessageDialog(null, e, "Load Failed",
 
1357
                                      JOptionPane.ERROR_MESSAGE);
 
1358
      } 
 
1359
 
 
1360
      m_Log.statusMessage("OK");
 
1361
      
 
1362
      if (clusterer != null) {
 
1363
        m_Log.logMessage("Loaded model from file '" + selected.getName()+ "'");
 
1364
        String name = (new SimpleDateFormat("HH:mm:ss - ")).format(new Date());
 
1365
        String cname = clusterer.getClass().getName();
 
1366
        if (cname.startsWith("weka.clusterers."))
 
1367
          cname = cname.substring("weka.clusterers.".length());
 
1368
        name += cname + " from file '" + selected.getName() + "'";
 
1369
        StringBuffer outBuff = new StringBuffer();
 
1370
 
 
1371
        outBuff.append("=== Model information ===\n\n");
 
1372
        outBuff.append("Filename:     " + selected.getName() + "\n");
 
1373
        outBuff.append("Scheme:       " + clusterer.getClass().getName());
 
1374
        if (clusterer instanceof OptionHandler) {
 
1375
          String [] o = ((OptionHandler) clusterer).getOptions();
 
1376
          outBuff.append(" " + Utils.joinOptions(o));
 
1377
        }
 
1378
        outBuff.append("\n");
 
1379
 
 
1380
        if (trainHeader != null) {
 
1381
 
 
1382
          outBuff.append("Relation:     " + trainHeader.relationName() + '\n');
 
1383
          outBuff.append("Attributes:   " + trainHeader.numAttributes() + '\n');
 
1384
          if (trainHeader.numAttributes() < 100) {
 
1385
            boolean [] selectedAtts = new boolean [trainHeader.numAttributes()];
 
1386
            for (int i = 0; i < trainHeader.numAttributes(); i++) {
 
1387
              selectedAtts[i] = true;
 
1388
            }
 
1389
            
 
1390
            if (ignoredAtts != null)
 
1391
              for (int i=0; i<ignoredAtts.length; i++)
 
1392
                selectedAtts[ignoredAtts[i]] = false;
 
1393
           
 
1394
            for (int i = 0; i < trainHeader.numAttributes(); i++) {
 
1395
              if (selectedAtts[i]) {
 
1396
                outBuff.append("              " + trainHeader.attribute(i).name()
 
1397
                               + '\n');
 
1398
              }
 
1399
            }
 
1400
            if (ignoredAtts != null) {
 
1401
              outBuff.append("Ignored:\n");
 
1402
              for (int i=0; i<ignoredAtts.length; i++)
 
1403
                outBuff.append("              "
 
1404
                               + trainHeader.attribute(ignoredAtts[i]).name()
 
1405
                               + '\n');
 
1406
            }
 
1407
          } else {
 
1408
            outBuff.append("              [list of attributes omitted]\n");
 
1409
          }
 
1410
        } else {
 
1411
          outBuff.append("\nTraining data unknown\n");
 
1412
        } 
 
1413
        
 
1414
        outBuff.append("\n=== Clustering model ===\n\n");
 
1415
        outBuff.append(clusterer.toString() + "\n");
 
1416
 
 
1417
        m_History.addResult(name, outBuff);
 
1418
        m_History.setSingle(name);
 
1419
        FastVector vv = new FastVector();
 
1420
        vv.addElement(clusterer);
 
1421
        if (trainHeader != null) vv.addElement(trainHeader);
 
1422
        if (ignoredAtts != null) vv.addElement(ignoredAtts);
 
1423
        // allow visualization of graphable classifiers
 
1424
        String grph = null;
 
1425
        if (clusterer instanceof Drawable) {
 
1426
          try {
 
1427
            grph = ((Drawable)clusterer).graph();
 
1428
          } catch (Exception ex) {
 
1429
          }
 
1430
        }
 
1431
        if (grph != null) vv.addElement(grph);
 
1432
        
 
1433
        m_History.addObject(name, vv);
 
1434
        
 
1435
      }
 
1436
    }
 
1437
  }
 
1438
 
 
1439
  /**
 
1440
   * Re-evaluates the named clusterer with the current test set. Unpredictable
 
1441
   * things will happen if the data set is not compatible with the clusterer.
 
1442
   *
 
1443
   * @param name the name of the clusterer entry
 
1444
   * @param clusterer the clusterer to evaluate
 
1445
   * @param trainHeader the header of the training set
 
1446
   * @param ignoredAtts ignored attributes
 
1447
   */
 
1448
  protected void reevaluateModel(final String name, 
 
1449
                                 final Clusterer clusterer,
 
1450
                                 final Instances trainHeader, 
 
1451
                                 final int[] ignoredAtts) {
 
1452
 
 
1453
    if (m_RunThread == null) {
 
1454
      m_StartBut.setEnabled(false);
 
1455
      m_StopBut.setEnabled(true);
 
1456
      m_ignoreBut.setEnabled(false);
 
1457
      m_RunThread = new Thread() {
 
1458
          public void run() {
 
1459
            // Copy the current state of things
 
1460
            m_Log.statusMessage("Setting up...");
 
1461
 
 
1462
            StringBuffer outBuff = m_History.getNamedBuffer(name);
 
1463
            Instances userTest = null;
 
1464
 
 
1465
            PlotData2D predData = null;
 
1466
            if (m_TestInstances != null) {
 
1467
              userTest = new Instances(m_TestInstances);
 
1468
            }
 
1469
    
 
1470
            boolean saveVis = m_StorePredictionsBut.isSelected();
 
1471
            String grph = null;
 
1472
 
 
1473
            try {
 
1474
              if (userTest == null) {
 
1475
                throw new Exception("No user test set has been opened");
 
1476
              }
 
1477
              if (trainHeader != null && !trainHeader.equalHeaders(userTest)) {
 
1478
                throw new Exception("Train and test set are not compatible");
 
1479
              }
 
1480
 
 
1481
              m_Log.statusMessage("Evaluating on test data...");
 
1482
              m_Log.logMessage("Re-evaluating clusterer (" + name + ") on test set");
 
1483
 
 
1484
              m_Log.logMessage("Started reevaluate model");
 
1485
              if (m_Log instanceof TaskLogger) {
 
1486
                ((TaskLogger)m_Log).taskStarted();
 
1487
              }
 
1488
              ClusterEvaluation eval = new ClusterEvaluation();
 
1489
              eval.setClusterer(clusterer);
 
1490
    
 
1491
              Instances userTestT = new Instances(userTest);
 
1492
              if (ignoredAtts != null) {
 
1493
                userTestT = removeIgnoreCols(userTestT, ignoredAtts);
 
1494
              }
 
1495
 
 
1496
              eval.evaluateClusterer(userTestT);
 
1497
      
 
1498
              predData = setUpVisualizableInstances(userTest, eval);
 
1499
 
 
1500
              outBuff.append("\n=== Re-evaluation on test set ===\n\n");
 
1501
              outBuff.append("User supplied test set\n");  
 
1502
              outBuff.append("Relation:     " + userTest.relationName() + '\n');
 
1503
              outBuff.append("Instances:    " + userTest.numInstances() + '\n');
 
1504
              outBuff.append("Attributes:   " + userTest.numAttributes() + "\n\n");
 
1505
              if (trainHeader == null)
 
1506
                outBuff.append("NOTE - if test set is not compatible then results are "
 
1507
                               + "unpredictable\n\n");
 
1508
      
 
1509
              outBuff.append(eval.clusterResultsToString());
 
1510
              outBuff.append("\n");
 
1511
              m_History.updateResult(name);
 
1512
              m_Log.logMessage("Finished re-evaluation");
 
1513
              m_Log.statusMessage("OK");
 
1514
            } catch (Exception ex) {
 
1515
              ex.printStackTrace();
 
1516
              m_Log.logMessage(ex.getMessage());
 
1517
              JOptionPane.showMessageDialog(ClustererPanel.this,
 
1518
                                            "Problem evaluating clusterer:\n"
 
1519
                                            + ex.getMessage(),
 
1520
                                            "Evaluate clusterer",
 
1521
                                            JOptionPane.ERROR_MESSAGE);
 
1522
              m_Log.statusMessage("Problem evaluating clusterer");
 
1523
 
 
1524
            } finally {
 
1525
              if (predData != null) {
 
1526
                m_CurrentVis = new VisualizePanel();
 
1527
                m_CurrentVis.setName(name+" ("+userTest.relationName()+")");
 
1528
                m_CurrentVis.setLog(m_Log);
 
1529
                predData.setPlotName(name+" ("+userTest.relationName()+")");
 
1530
        
 
1531
                try {
 
1532
                  m_CurrentVis.addPlot(predData);
 
1533
                } catch (Exception ex) {
 
1534
                  System.err.println(ex);
 
1535
                }
 
1536
        
 
1537
                FastVector vv = new FastVector();
 
1538
                vv.addElement(clusterer);
 
1539
                if (trainHeader != null) vv.addElement(trainHeader);
 
1540
                if (ignoredAtts != null) vv.addElement(ignoredAtts);
 
1541
                if (saveVis) {
 
1542
                  vv.addElement(m_CurrentVis);
 
1543
                  if (grph != null) {
 
1544
                    vv.addElement(grph);
 
1545
                  }
 
1546
          
 
1547
                }
 
1548
                m_History.addObject(name, vv);
 
1549
 
 
1550
              }
 
1551
              if (isInterrupted()) {
 
1552
                m_Log.logMessage("Interrupted reevaluate model");
 
1553
                m_Log.statusMessage("See error log");
 
1554
              }
 
1555
              m_RunThread = null;
 
1556
              m_StartBut.setEnabled(true);
 
1557
              m_StopBut.setEnabled(false);
 
1558
              m_ignoreBut.setEnabled(true);
 
1559
              if (m_Log instanceof TaskLogger) {
 
1560
                ((TaskLogger)m_Log).taskFinished();
 
1561
              }
 
1562
            }
 
1563
          }
 
1564
      
 
1565
        };
 
1566
      m_RunThread.setPriority(Thread.MIN_PRIORITY);
 
1567
      m_RunThread.start();
 
1568
    }
 
1569
  }
 
1570
  
 
1571
  /**
 
1572
   * updates the capabilities filter of the GOE
 
1573
   * 
 
1574
   * @param filter      the new filter to use
 
1575
   */
 
1576
  protected void updateCapabilitiesFilter(Capabilities filter) {
 
1577
    Instances           tempInst;
 
1578
    Capabilities        filterClass;
 
1579
 
 
1580
    if (filter == null) {
 
1581
      m_ClustererEditor.setCapabilitiesFilter(new Capabilities(null));
 
1582
      return;
 
1583
    }
 
1584
    
 
1585
    if (!ExplorerDefaults.getInitGenericObjectEditorFilter())
 
1586
      tempInst = new Instances(m_Instances, 0);
 
1587
    else
 
1588
      tempInst = new Instances(m_Instances);
 
1589
    tempInst.setClassIndex(-1);
 
1590
 
 
1591
    try {
 
1592
      filterClass = Capabilities.forInstances(tempInst);
 
1593
    }
 
1594
    catch (Exception e) {
 
1595
      filterClass = new Capabilities(null);
 
1596
    }
 
1597
    
 
1598
    m_ClustererEditor.setCapabilitiesFilter(filterClass);
 
1599
  }
 
1600
  
 
1601
  /**
 
1602
   * method gets called in case of a change event
 
1603
   * 
 
1604
   * @param e           the associated change event
 
1605
   */
 
1606
  public void capabilitiesFilterChanged(CapabilitiesFilterChangeEvent e) {
 
1607
    if (e.getFilter() == null)
 
1608
      updateCapabilitiesFilter(null);
 
1609
    else
 
1610
      updateCapabilitiesFilter((Capabilities) e.getFilter().clone());
 
1611
  }
 
1612
 
 
1613
  /**
 
1614
   * Sets the Explorer to use as parent frame (used for sending notifications
 
1615
   * about changes in the data)
 
1616
   * 
 
1617
   * @param parent      the parent frame
 
1618
   */
 
1619
  public void setExplorer(Explorer parent) {
 
1620
    m_Explorer = parent;
 
1621
  }
 
1622
  
 
1623
  /**
 
1624
   * returns the parent Explorer frame
 
1625
   * 
 
1626
   * @return            the parent
 
1627
   */
 
1628
  public Explorer getExplorer() {
 
1629
    return m_Explorer;
 
1630
  }
 
1631
  
 
1632
  /**
 
1633
   * Returns the title for the tab in the Explorer
 
1634
   * 
 
1635
   * @return            the title of this tab
 
1636
   */
 
1637
  public String getTabTitle() {
 
1638
    return "Cluster";
 
1639
  }
 
1640
  
 
1641
  /**
 
1642
   * Returns the tooltip for the tab in the Explorer
 
1643
   * 
 
1644
   * @return            the tooltip of this tab
 
1645
   */
 
1646
  public String getTabTitleToolTip() {
 
1647
    return "Identify instance clusters";
 
1648
  }
 
1649
 
 
1650
  /**
 
1651
   * Tests out the clusterer panel from the command line.
 
1652
   *
 
1653
   * @param args may optionally contain the name of a dataset to load.
 
1654
   */
 
1655
  public static void main(String [] args) {
 
1656
 
 
1657
    try {
 
1658
      final javax.swing.JFrame jf =
 
1659
        new javax.swing.JFrame("Weka Explorer: Cluster");
 
1660
      jf.getContentPane().setLayout(new BorderLayout());
 
1661
      final ClustererPanel sp = new ClustererPanel();
 
1662
      jf.getContentPane().add(sp, BorderLayout.CENTER);
 
1663
      weka.gui.LogPanel lp = new weka.gui.LogPanel();
 
1664
      sp.setLog(lp);
 
1665
      jf.getContentPane().add(lp, BorderLayout.SOUTH);
 
1666
      jf.addWindowListener(new java.awt.event.WindowAdapter() {
 
1667
        public void windowClosing(java.awt.event.WindowEvent e) {
 
1668
          jf.dispose();
 
1669
          System.exit(0);
 
1670
        }
 
1671
      });
 
1672
      jf.pack();
 
1673
      jf.setSize(800, 600);
 
1674
      jf.setVisible(true);
 
1675
      if (args.length == 1) {
 
1676
        System.err.println("Loading instances from " + args[0]);
 
1677
        java.io.Reader r = new java.io.BufferedReader(
 
1678
                           new java.io.FileReader(args[0]));
 
1679
        Instances i = new Instances(r);
 
1680
        sp.setInstances(i);
 
1681
      }
 
1682
    } catch (Exception ex) {
 
1683
      ex.printStackTrace();
 
1684
      System.err.println(ex.getMessage());
 
1685
    }
 
1686
  }
 
1687
}