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.
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.
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.
19
* Copyright (C) 1999 University of Waikato, Hamilton, New Zealand
23
package weka.gui.explorer;
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;
59
import java.awt.BorderLayout;
60
import java.awt.Dimension;
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;
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;
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;
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.
119
* @author Mark Hall (mhall@cs.waikato.ac.nz)
120
* @author Richard Kirkby (rkirkby@cs.waikato.ac.nz)
121
* @version $Revision: 1.60 $
123
public class ClustererPanel
125
implements CapabilitiesFilterChangeListener, ExplorerPanel, LogHandler {
127
/** for serialization */
128
static final long serialVersionUID = -2474932792950820990L;
130
/** the parent frame */
131
protected Explorer m_Explorer = null;
133
/** The filename extension that should be used for model files */
134
public static String MODEL_FILE_EXTENSION = ".model";
136
/** Lets the user configure the clusterer */
137
protected GenericObjectEditor m_ClustererEditor =
138
new GenericObjectEditor();
140
/** The panel showing the current clusterer selection */
141
protected PropertyPanel m_CLPanel = new PropertyPanel(m_ClustererEditor);
143
/** The output area for classification results */
144
protected JTextArea m_OutText = new JTextArea(20, 40);
146
/** The destination for log/status messages */
147
protected Logger m_Log = new SysErrLog();
149
/** The buffer saving object for saving output */
150
SaveBuffer m_SaveOut = new SaveBuffer(m_Log, this);
152
/** A panel controlling results viewing */
153
protected ResultHistoryPanel m_History = new ResultHistoryPanel(m_OutText);
155
/** Click to set test mode to generate a % split */
156
protected JRadioButton m_PercentBut = new JRadioButton("Percentage split");
158
/** Click to set test mode to test on training data */
159
protected JRadioButton m_TrainBut = new JRadioButton("Use training set");
161
/** Click to set test mode to a user-specified test set */
162
protected JRadioButton m_TestSplitBut =
163
new JRadioButton("Supplied test set");
165
/** Click to set test mode to classes to clusters based evaluation */
166
protected JRadioButton m_ClassesToClustersBut =
167
new JRadioButton("Classes to clusters evaluation");
169
/** Lets the user select the class column for classes to clusters based
171
protected JComboBox m_ClassCombo = new JComboBox();
173
/** Label by where the % split is entered */
174
protected JLabel m_PercentLab = new JLabel("%", SwingConstants.RIGHT);
176
/** The field where the % split is entered */
177
protected JTextField m_PercentText = new JTextField("66");
179
/** The button used to open a separate test dataset */
180
protected JButton m_SetTestBut = new JButton("Set...");
182
/** The frame used to show the test set selection panel */
183
protected JFrame m_SetTestFrame;
185
/** The button used to popup a list for choosing attributes to ignore while
187
protected JButton m_ignoreBut = new JButton("Ignore attributes");
189
protected DefaultListModel m_ignoreKeyModel = new DefaultListModel();
190
protected JList m_ignoreKeyList = new JList(m_ignoreKeyModel);
192
// protected Remove m_ignoreFilter = null;
195
* Alters the enabled/disabled status of elements associated with each
198
ActionListener m_RadioListener = new ActionListener() {
199
public void actionPerformed(ActionEvent e) {
204
/** Click to start running the clusterer */
205
protected JButton m_StartBut = new JButton("Start");
207
/** Stop the class combo from taking up to much space */
208
private Dimension COMBO_SIZE = new Dimension(250, m_StartBut
209
.getPreferredSize().height);
211
/** Click to stop a running clusterer */
212
protected JButton m_StopBut = new JButton("Stop");
214
/** The main set of instances we're playing with */
215
protected Instances m_Instances;
217
/** The user-supplied test set (if any) */
218
protected Instances m_TestInstances;
220
/** The current visualization object */
221
protected VisualizePanel m_CurrentVis = null;
223
/** Check to save the predictions in the results list for visualizing
225
protected JCheckBox m_StorePredictionsBut =
226
new JCheckBox("Store clusters for visualization");
228
/** A thread that clustering runs in */
229
protected Thread m_RunThread;
231
/** The instances summary panel displayed by m_SetTestFrame */
232
protected InstancesSummaryPanel m_Summary;
234
/** Filter to ensure only model files are selected */
235
protected FileFilter m_ModelFilter =
236
new ExtensionFileFilter(MODEL_FILE_EXTENSION, "Model object files");
238
/** The file chooser for selecting model files */
239
protected JFileChooser m_FileChooser
240
= new JFileChooser(new File(System.getProperty("user.dir")));
242
/* Register the property editors we need */
244
GenericObjectEditor.registerEditors();
248
* Creates the clusterer panel
250
public ClustererPanel() {
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();
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) {
273
m_TrainBut.setToolTipText("Cluster the same set that the clusterer"
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"
280
m_ClassCombo.setToolTipText("Select the class attribute for class based"
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 "
287
m_ignoreBut.setToolTipText("Ignore attributes during clustering");
289
m_FileChooser.setFileFilter(m_ModelFilter);
290
m_FileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
292
m_ClassCombo.setPreferredSize(COMBO_SIZE);
293
m_ClassCombo.setMaximumSize(COMBO_SIZE);
294
m_ClassCombo.setMinimumSize(COMBO_SIZE);
295
m_ClassCombo.setEnabled(false);
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());
303
ButtonGroup bg = new ButtonGroup();
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) {
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) {
326
m_StopBut.addActionListener(new ActionListener() {
327
public void actionPerformed(ActionEvent e) {
332
m_ignoreBut.addActionListener(new ActionListener() {
333
public void actionPerformed(ActionEvent e) {
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());
346
String name = m_History.getNameAtIndex(index);
347
visualizeClusterer(name, e.getX(), e.getY());
349
visualizeClusterer(null, e.getX(), e.getY());
355
m_ClassCombo.addActionListener(new ActionListener() {
356
public void actionPerformed(ActionEvent e) {
357
updateCapabilitiesFilter(m_ClustererEditor.getCapabilitiesFilter());
362
JPanel p1 = new JPanel();
363
p1.setBorder(BorderFactory.createCompoundBorder(
364
BorderFactory.createTitledBorder("Clusterer"),
365
BorderFactory.createEmptyBorder(0, 5, 5, 5)
367
p1.setLayout(new BorderLayout());
368
p1.add(m_CLPanel, BorderLayout.NORTH);
370
JPanel p2 = new JPanel();
371
GridBagLayout gbL = new GridBagLayout();
373
p2.setBorder(BorderFactory.createCompoundBorder(
374
BorderFactory.createTitledBorder("Cluster mode"),
375
BorderFactory.createEmptyBorder(0, 5, 5, 5)
377
GridBagConstraints gbC = new GridBagConstraints();
378
gbC.anchor = GridBagConstraints.WEST;
379
gbC.gridy = 0; gbC.gridx = 0;
380
gbL.setConstraints(m_TrainBut, gbC);
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);
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);
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);
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);
411
gbC = new GridBagConstraints();
412
gbC.anchor = GridBagConstraints.EAST;
413
gbC.fill = GridBagConstraints.HORIZONTAL;
414
gbC.gridy = 2; gbC.gridx = 2; gbC.weightx = 100;
416
gbL.setConstraints(m_PercentText, gbC);
417
p2.add(m_PercentText);
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);
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);
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);
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);
446
JPanel ib = new JPanel();
447
ib.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
448
ib.setLayout(new GridLayout(1, 1, 5, 5));
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
465
int x = h - vp.getExtentSize().height;
466
vp.setViewPosition(new Point(0, x));
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);
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);
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;
496
gbC.weightx = 100; gbC.weighty = 100;
497
gbL.setConstraints(p3, gbC);
500
setLayout(new BorderLayout());
501
add(p1, BorderLayout.NORTH);
502
add(mondo, BorderLayout.CENTER);
506
* Updates the enabled status of the input fields and labels.
508
protected void updateRadioLinks() {
510
m_SetTestBut.setEnabled(m_TestSplitBut.isSelected());
511
if ((m_SetTestFrame != null) && (!m_TestSplitBut.isSelected())) {
512
m_SetTestFrame.setVisible(false);
514
m_PercentText.setEnabled(m_PercentBut.isSelected());
515
m_PercentLab.setEnabled(m_PercentBut.isSelected());
516
m_ClassCombo.setEnabled(m_ClassesToClustersBut.isSelected());
520
* Sets the Logger to receive informational messages
522
* @param newLog the Logger that will now get info messages
524
public void setLog(Logger newLog) {
530
* Tells the panel to use a new set of instances.
532
* @param inst a set of Instances
534
public void setInstances(Instances inst) {
538
m_ignoreKeyModel.removeAllElements();
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);
546
switch (m_Instances.attribute(i).type()) {
547
case Attribute.NOMINAL:
550
case Attribute.NUMERIC:
553
case Attribute.STRING:
559
case Attribute.RELATIONAL:
565
String attnm = m_Instances.attribute(i).name();
567
attribNames[i] = type + attnm;
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);
578
m_ClassCombo.setSelectedIndex(inst.classIndex());
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.
588
protected void setTestSet() {
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);
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!
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();
611
m_SetTestFrame.setVisible(true);
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
623
public static PlotData2D setUpVisualizableInstances(Instances testInstances,
624
ClusterEvaluation eval)
627
int numClusters = eval.getNumClusters();
628
double [] clusterAssignments = eval.getClusterAssignments();
630
FastVector hv = new FastVector();
633
Attribute predictedCluster;
634
FastVector clustVals = new FastVector();
636
for (int i = 0; i < numClusters; i++) {
637
clustVals.addElement("cluster"+i);
639
predictedCluster = new Attribute("Cluster", clustVals);
640
for (int i = 0; i < testInstances.numAttributes(); i++) {
641
hv.addElement(testInstances.attribute(i).copy());
643
hv.addElement(predictedCluster);
645
newInsts = new Instances(testInstances.relationName()+"_clustered", hv,
646
testInstances.numInstances());
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;
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);
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;
674
PlotData2D plotData = new PlotData2D(newInsts);
675
if (pointShapes != null) {
676
plotData.setShapeType(pointShapes);
678
plotData.addInstanceNumberAttribute();
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.
688
protected void startClusterer() {
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() {
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);
706
boolean saveVis = m_StorePredictionsBut.isSelected();
708
int[] ignoredAtts = null;
712
Clusterer clusterer = (Clusterer) m_ClustererEditor.getValue();
713
Clusterer fullClusterer = null;
714
StringBuffer outBuff = new StringBuffer();
715
String name = (new SimpleDateFormat("HH:mm:ss - "))
717
String cname = clusterer.getClass().getName();
718
if (cname.startsWith("weka.clusterers.")) {
719
name += cname.substring("weka.clusterers.".length());
723
String cmd = m_ClustererEditor.getValue().getClass().getName();
724
if (m_ClustererEditor.getValue() instanceof OptionHandler)
725
cmd += " " + Utils.joinOptions(((OptionHandler) m_ClustererEditor.getValue()).getOptions());
727
m_Log.logMessage("Started " + cname);
728
m_Log.logMessage("Command: " + cmd);
729
if (m_Log instanceof TaskLogger) {
730
((TaskLogger)m_Log).taskStarted();
732
if (m_PercentBut.isSelected()) {
734
percent = Integer.parseInt(m_PercentText.getText());
735
if ((percent <= 0) || (percent >= 100)) {
736
throw new Exception("Percentage must be between 0 and 100");
738
} else if (m_TrainBut.isSelected()) {
740
} else if (m_TestSplitBut.isSelected()) {
742
// Check the test instance compatibility
743
if (userTest == null) {
744
throw new Exception("No user test set has been opened");
746
if (!inst.equalHeaders(userTest)) {
747
throw new Exception("Train and test set are not compatible");
749
} else if (m_ClassesToClustersBut.isSelected()) {
752
throw new Exception("Unknown test mode");
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 "
764
if (!m_ignoreKeyList.isSelectionEmpty()) {
765
trainInst = removeIgnoreCols(trainInst);
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));
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++) {
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;
790
if (m_ClassesToClustersBut.isSelected()) {
791
selected[m_ClassCombo.getSelectedIndex()] = false;
793
for (int i = 0; i < inst.numAttributes(); i++) {
795
outBuff.append(" " + inst.attribute(i).name()
799
if (!m_ignoreKeyList.isSelectionEmpty()
800
|| m_ClassesToClustersBut.isSelected()) {
801
outBuff.append("Ignored:\n");
802
for (int i = 0; i < inst.numAttributes(); i++) {
804
outBuff.append(" " + inst.attribute(i).name()
810
outBuff.append(" [list of attributes omitted]\n");
813
if (!m_ignoreKeyList.isSelectionEmpty()) {
814
ignoredAtts = m_ignoreKeyList.getSelectedIndices();
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();
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;
831
outBuff.append("Test mode: ");
833
case 3: // Test on training
834
outBuff.append("evaluate on training data\n");
836
case 2: // Percent split
837
outBuff.append("split " + percent
838
+ "% train, remainder test\n");
840
case 4: // Test on user split
841
outBuff.append("user supplied test set: "
842
+ userTest.numInstances() + " instances\n");
844
case 5: // Classes to clusters evaluation on training
845
outBuff.append("Classes to clusters evaluation on training data");
849
outBuff.append("\n");
850
m_History.addResult(name, outBuff);
851
m_History.setSingle(name);
853
// Build the model and output it.
854
m_Log.statusMessage("Building model on training data...");
856
// remove the class attribute (if set) and build the clusterer
857
clusterer.buildClusterer(removeClass(trainInst));
860
outBuff.append("\n=== Clustering model (full training set) ===\n\n");
862
outBuff.append(clusterer.toString() + '\n');
864
m_History.updateResult(name);
865
if (clusterer instanceof Drawable) {
867
grph = ((Drawable)clusterer).graph();
868
} catch (Exception ex) {
871
// copy full model for output
872
SerializedObject so = new SerializedObject(clusterer);
873
fullClusterer = (Clusterer) so.getObject();
875
ClusterEvaluation eval = new ClusterEvaluation();
876
eval.setClusterer(clusterer);
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");
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");
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);
908
eval.evaluateClusterer(userTestT);
909
predData = setUpVisualizableInstances(userTest, eval);
910
outBuff.append("=== Model and evaluation on test set ===\n");
914
throw new Exception("Test mode not implemented");
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"
927
"Evaluate clusterer",
928
JOptionPane.ERROR_MESSAGE);
929
m_Log.statusMessage("Problem evaluating clusterer");
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()+")");
938
m_CurrentVis.addPlot(predData);
939
} catch (Exception ex) {
940
System.err.println(ex);
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);
949
vv.addElement(m_CurrentVis);
955
m_History.addObject(name, vv);
957
if (isInterrupted()) {
958
m_Log.logMessage("Interrupted " + cname);
959
m_Log.statusMessage("See error log");
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();
971
m_RunThread.setPriority(Thread.MIN_PRIORITY);
976
private Instances removeClass(Instances inst) {
977
Remove af = new Remove();
978
Instances retI = null;
981
if (inst.classIndex() < 0) {
984
af.setAttributeIndices(""+(inst.classIndex()+1));
985
af.setInvertSelection(false);
986
af.setInputFormat(inst);
987
retI = Filter.useFilter(inst, af);
989
} catch (Exception e) {
995
private Instances removeIgnoreCols(Instances inst) {
997
// If the user is doing classes to clusters evaluation and
998
// they have opted to ignore the class, then unselect the class in
1000
if (m_ClassesToClustersBut.isSelected()) {
1001
int classIndex = m_ClassCombo.getSelectedIndex();
1002
if (m_ignoreKeyList.isSelectedIndex(classIndex)) {
1003
m_ignoreKeyList.removeSelectionInterval(classIndex, classIndex);
1006
int [] selected = m_ignoreKeyList.getSelectedIndices();
1007
Remove af = new Remove();
1008
Instances retI = null;
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();
1022
private Instances removeIgnoreCols(Instances inst, int[] toIgnore) {
1024
Remove af = new Remove();
1025
Instances retI = null;
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();
1040
* Stops the currently running clusterer (if any).
1042
protected void stopClusterer() {
1044
if (m_RunThread != null) {
1045
m_RunThread.interrupt();
1047
// This is deprecated (and theoretically the interrupt should do).
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
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,
1067
jf.getContentPane().add(tv, BorderLayout.CENTER);
1068
jf.addWindowListener(new java.awt.event.WindowAdapter() {
1069
public void windowClosing(java.awt.event.WindowEvent e) {
1074
jf.setVisible(true);
1079
* Pops up a visualize panel to display cluster assignments
1080
* @param sp the visualize panel to display
1082
protected void visualizeClusterAssignments(VisualizePanel sp) {
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) {
1096
jf.setVisible(true);
1101
* Handles constructing a popup menu with visualization options
1102
* @param name the name of the result history list entry clicked on by
1104
* @param x the x coordinate for popping up the menu
1105
* @param y the y coordinate for popping up the menu
1107
protected void visualizeClusterer(String name, int x, int y) {
1108
final String selectedName = name;
1109
JPopupMenu resultListMenu = new JPopupMenu();
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);
1119
visMainBuffer.setEnabled(false);
1121
resultListMenu.add(visMainBuffer);
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);
1131
visSepBuffer.setEnabled(false);
1133
resultListMenu.add(visSepBuffer);
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);
1143
saveOutput.setEnabled(false);
1145
resultListMenu.add(saveOutput);
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);
1155
deleteOutput.setEnabled(false);
1157
resultListMenu.add(deleteOutput);
1159
resultListMenu.addSeparator();
1161
JMenuItem loadModel = new JMenuItem("Load model");
1162
loadModel.addActionListener(new ActionListener() {
1163
public void actionPerformed(ActionEvent e) {
1167
resultListMenu.add(loadModel);
1169
FastVector o = null;
1170
if (selectedName != null) {
1171
o = (FastVector)m_History.getNamedObject(selectedName);
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;
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;
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;
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);
1211
saveModel.setEnabled(false);
1213
resultListMenu.add(saveModel);
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);
1224
reEvaluate.setEnabled(false);
1226
resultListMenu.add(reEvaluate);
1228
resultListMenu.addSeparator();
1230
JMenuItem visClusts = new JMenuItem("Visualize cluster assignments");
1232
visClusts.addActionListener(new ActionListener() {
1233
public void actionPerformed(ActionEvent e) {
1234
visualizeClusterAssignments(vp);
1239
visClusts.setEnabled(false);
1241
resultListMenu.add(visClusts);
1243
JMenuItem visTree = new JMenuItem("Visualize tree");
1245
visTree.addActionListener(new ActionListener() {
1246
public void actionPerformed(ActionEvent e) {
1248
if (vp != null) title = vp.getName();
1249
else title = selectedName;
1250
visualizeTree(grph, title);
1254
visTree.setEnabled(false);
1256
resultListMenu.add(visTree);
1258
resultListMenu.show(m_History.getList(), x, y);
1262
* Save the currently selected clusterer output to a file.
1263
* @param name the name of the buffer to save
1265
protected void saveBuffer(String name) {
1266
StringBuffer sb = m_History.getNamedBuffer(name);
1268
if (m_SaveOut.save(sb)) {
1269
m_Log.logMessage("Save successful.");
1274
private void setIgnoreColumns() {
1275
ListSelectorDialog jd = new ListSelectorDialog(null, m_ignoreKeyList);
1278
int result = jd.showDialog();
1280
if (result != ListSelectorDialog.APPROVE_OPTION) {
1281
// clear selected indices
1282
m_ignoreKeyList.clearSelection();
1287
* Saves the currently selected clusterer
1289
protected void saveClusterer(String name, Clusterer clusterer,
1290
Instances trainHeader, int[] ignoredAtts) {
1293
boolean saveOK = true;
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);
1302
m_Log.statusMessage("Saving model to file...");
1305
OutputStream os = new FileOutputStream(sFile);
1306
if (sFile.getName().endsWith(".gz")) {
1307
os = new GZIPOutputStream(os);
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) {
1317
JOptionPane.showMessageDialog(null, e, "Save Failed",
1318
JOptionPane.ERROR_MESSAGE);
1322
m_Log.logMessage("Saved model (" + name
1323
+ ") to file '" + sFile.getName() + "'");
1324
m_Log.statusMessage("OK");
1331
protected void loadClusterer() {
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;
1340
m_Log.statusMessage("Loading model from file...");
1343
InputStream is = new FileInputStream(selected);
1344
if (selected.getName().endsWith(".gz")) {
1345
is = new GZIPInputStream(is);
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) {
1356
JOptionPane.showMessageDialog(null, e, "Load Failed",
1357
JOptionPane.ERROR_MESSAGE);
1360
m_Log.statusMessage("OK");
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();
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));
1378
outBuff.append("\n");
1380
if (trainHeader != null) {
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;
1390
if (ignoredAtts != null)
1391
for (int i=0; i<ignoredAtts.length; i++)
1392
selectedAtts[ignoredAtts[i]] = false;
1394
for (int i = 0; i < trainHeader.numAttributes(); i++) {
1395
if (selectedAtts[i]) {
1396
outBuff.append(" " + trainHeader.attribute(i).name()
1400
if (ignoredAtts != null) {
1401
outBuff.append("Ignored:\n");
1402
for (int i=0; i<ignoredAtts.length; i++)
1404
+ trainHeader.attribute(ignoredAtts[i]).name()
1408
outBuff.append(" [list of attributes omitted]\n");
1411
outBuff.append("\nTraining data unknown\n");
1414
outBuff.append("\n=== Clustering model ===\n\n");
1415
outBuff.append(clusterer.toString() + "\n");
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
1425
if (clusterer instanceof Drawable) {
1427
grph = ((Drawable)clusterer).graph();
1428
} catch (Exception ex) {
1431
if (grph != null) vv.addElement(grph);
1433
m_History.addObject(name, vv);
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.
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
1448
protected void reevaluateModel(final String name,
1449
final Clusterer clusterer,
1450
final Instances trainHeader,
1451
final int[] ignoredAtts) {
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() {
1459
// Copy the current state of things
1460
m_Log.statusMessage("Setting up...");
1462
StringBuffer outBuff = m_History.getNamedBuffer(name);
1463
Instances userTest = null;
1465
PlotData2D predData = null;
1466
if (m_TestInstances != null) {
1467
userTest = new Instances(m_TestInstances);
1470
boolean saveVis = m_StorePredictionsBut.isSelected();
1474
if (userTest == null) {
1475
throw new Exception("No user test set has been opened");
1477
if (trainHeader != null && !trainHeader.equalHeaders(userTest)) {
1478
throw new Exception("Train and test set are not compatible");
1481
m_Log.statusMessage("Evaluating on test data...");
1482
m_Log.logMessage("Re-evaluating clusterer (" + name + ") on test set");
1484
m_Log.logMessage("Started reevaluate model");
1485
if (m_Log instanceof TaskLogger) {
1486
((TaskLogger)m_Log).taskStarted();
1488
ClusterEvaluation eval = new ClusterEvaluation();
1489
eval.setClusterer(clusterer);
1491
Instances userTestT = new Instances(userTest);
1492
if (ignoredAtts != null) {
1493
userTestT = removeIgnoreCols(userTestT, ignoredAtts);
1496
eval.evaluateClusterer(userTestT);
1498
predData = setUpVisualizableInstances(userTest, eval);
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");
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"
1520
"Evaluate clusterer",
1521
JOptionPane.ERROR_MESSAGE);
1522
m_Log.statusMessage("Problem evaluating clusterer");
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()+")");
1532
m_CurrentVis.addPlot(predData);
1533
} catch (Exception ex) {
1534
System.err.println(ex);
1537
FastVector vv = new FastVector();
1538
vv.addElement(clusterer);
1539
if (trainHeader != null) vv.addElement(trainHeader);
1540
if (ignoredAtts != null) vv.addElement(ignoredAtts);
1542
vv.addElement(m_CurrentVis);
1544
vv.addElement(grph);
1548
m_History.addObject(name, vv);
1551
if (isInterrupted()) {
1552
m_Log.logMessage("Interrupted reevaluate model");
1553
m_Log.statusMessage("See error log");
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();
1566
m_RunThread.setPriority(Thread.MIN_PRIORITY);
1567
m_RunThread.start();
1572
* updates the capabilities filter of the GOE
1574
* @param filter the new filter to use
1576
protected void updateCapabilitiesFilter(Capabilities filter) {
1578
Capabilities filterClass;
1580
if (filter == null) {
1581
m_ClustererEditor.setCapabilitiesFilter(new Capabilities(null));
1585
if (!ExplorerDefaults.getInitGenericObjectEditorFilter())
1586
tempInst = new Instances(m_Instances, 0);
1588
tempInst = new Instances(m_Instances);
1589
tempInst.setClassIndex(-1);
1592
filterClass = Capabilities.forInstances(tempInst);
1594
catch (Exception e) {
1595
filterClass = new Capabilities(null);
1598
m_ClustererEditor.setCapabilitiesFilter(filterClass);
1602
* method gets called in case of a change event
1604
* @param e the associated change event
1606
public void capabilitiesFilterChanged(CapabilitiesFilterChangeEvent e) {
1607
if (e.getFilter() == null)
1608
updateCapabilitiesFilter(null);
1610
updateCapabilitiesFilter((Capabilities) e.getFilter().clone());
1614
* Sets the Explorer to use as parent frame (used for sending notifications
1615
* about changes in the data)
1617
* @param parent the parent frame
1619
public void setExplorer(Explorer parent) {
1620
m_Explorer = parent;
1624
* returns the parent Explorer frame
1626
* @return the parent
1628
public Explorer getExplorer() {
1633
* Returns the title for the tab in the Explorer
1635
* @return the title of this tab
1637
public String getTabTitle() {
1642
* Returns the tooltip for the tab in the Explorer
1644
* @return the tooltip of this tab
1646
public String getTabTitleToolTip() {
1647
return "Identify instance clusters";
1651
* Tests out the clusterer panel from the command line.
1653
* @param args may optionally contain the name of a dataset to load.
1655
public static void main(String [] args) {
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();
1665
jf.getContentPane().add(lp, BorderLayout.SOUTH);
1666
jf.addWindowListener(new java.awt.event.WindowAdapter() {
1667
public void windowClosing(java.awt.event.WindowEvent e) {
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);
1682
} catch (Exception ex) {
1683
ex.printStackTrace();
1684
System.err.println(ex.getMessage());