source: src/main/java/weka/gui/explorer/ClassifierPanel.java @ 24

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

Import di weka.

File size: 86.3 KB
Line 
1/*
2 *    This program is free software; you can redistribute it and/or modify
3 *    it under the terms of the GNU General Public License as published by
4 *    the Free Software Foundation; either version 2 of the License, or
5 *    (at your option) any later version.
6 *
7 *    This program is distributed in the hope that it will be useful,
8 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
9 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10 *    GNU General Public License for more details.
11 *
12 *    You should have received a copy of the GNU General Public License
13 *    along with this program; if not, write to the Free Software
14 *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
15 */
16
17/*
18 *    ClassifierPanel.java
19 *    Copyright (C) 1999 University of Waikato, Hamilton, New Zealand
20 *
21 */
22
23package weka.gui.explorer;
24
25import weka.classifiers.Classifier;
26import weka.classifiers.AbstractClassifier;
27import weka.classifiers.CostMatrix;
28import weka.classifiers.Evaluation;
29import weka.classifiers.Sourcable;
30import weka.classifiers.evaluation.CostCurve;
31import weka.classifiers.evaluation.MarginCurve;
32import weka.classifiers.evaluation.ThresholdCurve;
33import weka.classifiers.evaluation.output.prediction.AbstractOutput;
34import weka.classifiers.evaluation.output.prediction.Null;
35import weka.classifiers.pmml.consumer.PMMLClassifier;
36import weka.core.Attribute;
37import weka.core.Capabilities;
38import weka.core.CapabilitiesHandler;
39import weka.core.Drawable;
40import weka.core.FastVector;
41import weka.core.Instance;
42import weka.core.Instances;
43import weka.core.OptionHandler;
44import weka.core.Range;
45import weka.core.SerializedObject;
46import weka.core.Utils;
47import weka.core.Version;
48import weka.core.converters.IncrementalConverter;
49import weka.core.converters.Loader;
50import weka.core.converters.ConverterUtils.DataSource;
51import weka.core.pmml.PMMLFactory;
52import weka.core.pmml.PMMLModel;
53import weka.gui.CostMatrixEditor;
54import weka.gui.ExtensionFileFilter;
55import weka.gui.GenericObjectEditor;
56import weka.gui.Logger;
57import weka.gui.PropertyDialog;
58import weka.gui.PropertyPanel;
59import weka.gui.ResultHistoryPanel;
60import weka.gui.SaveBuffer;
61import weka.gui.SetInstancesPanel;
62import weka.gui.SysErrLog;
63import weka.gui.TaskLogger;
64import weka.gui.beans.CostBenefitAnalysis;
65import weka.gui.explorer.Explorer.CapabilitiesFilterChangeEvent;
66import weka.gui.explorer.Explorer.CapabilitiesFilterChangeListener;
67import weka.gui.explorer.Explorer.ExplorerPanel;
68import weka.gui.explorer.Explorer.LogHandler;
69import weka.gui.graphvisualizer.BIFFormatException;
70import weka.gui.graphvisualizer.GraphVisualizer;
71import weka.gui.treevisualizer.PlaceNode2;
72import weka.gui.treevisualizer.TreeVisualizer;
73import weka.gui.visualize.PlotData2D;
74import weka.gui.visualize.ThresholdVisualizePanel;
75import weka.gui.visualize.VisualizePanel;
76import weka.gui.visualize.plugins.ErrorVisualizePlugin;
77import weka.gui.visualize.plugins.GraphVisualizePlugin;
78import weka.gui.visualize.plugins.TreeVisualizePlugin;
79import weka.gui.visualize.plugins.VisualizePlugin;
80
81import java.awt.BorderLayout;
82import java.awt.Dimension;
83import java.awt.FlowLayout;
84import java.awt.Font;
85import java.awt.GridBagConstraints;
86import java.awt.GridBagLayout;
87import java.awt.GridLayout;
88import java.awt.Insets;
89import java.awt.Point;
90import java.awt.event.ActionEvent;
91import java.awt.event.ActionListener;
92import java.awt.event.InputEvent;
93import java.awt.event.MouseAdapter;
94import java.awt.event.MouseEvent;
95import java.beans.PropertyChangeEvent;
96import java.beans.PropertyChangeListener;
97import java.io.File;
98import java.io.FileInputStream;
99import java.io.FileOutputStream;
100import java.io.InputStream;
101import java.io.ObjectInputStream;
102import java.io.ObjectOutputStream;
103import java.io.OutputStream;
104import java.text.SimpleDateFormat;
105import java.util.Date;
106import java.util.Random;
107import java.util.Vector;
108import java.util.zip.GZIPInputStream;
109import java.util.zip.GZIPOutputStream;
110
111import javax.swing.BorderFactory;
112import javax.swing.ButtonGroup;
113import javax.swing.DefaultComboBoxModel;
114import javax.swing.JButton;
115import javax.swing.JCheckBox;
116import javax.swing.JComboBox;
117import javax.swing.JDialog;
118import javax.swing.JFileChooser;
119import javax.swing.JFrame;
120import javax.swing.JLabel;
121import javax.swing.JMenu;
122import javax.swing.JMenuItem;
123import javax.swing.JOptionPane;
124import javax.swing.JPanel;
125import javax.swing.JPopupMenu;
126import javax.swing.JRadioButton;
127import javax.swing.JScrollPane;
128import javax.swing.JTextArea;
129import javax.swing.JTextField;
130import javax.swing.JViewport;
131import javax.swing.SwingConstants;
132import javax.swing.event.ChangeEvent;
133import javax.swing.event.ChangeListener;
134import javax.swing.filechooser.FileFilter;
135
136/**
137 * This panel allows the user to select and configure a classifier, set the
138 * attribute of the current dataset to be used as the class, and evaluate
139 * the classifier using a number of testing modes (test on the training data,
140 * train/test on a percentage split, n-fold cross-validation, test on a
141 * separate split). The results of classification runs are stored in a result
142 * history so that previous results are accessible.
143 *
144 * @author Len Trigg (trigg@cs.waikato.ac.nz)
145 * @author Mark Hall (mhall@cs.waikato.ac.nz)
146 * @author Richard Kirkby (rkirkby@cs.waikato.ac.nz)
147 * @version $Revision: 5958 $
148 */
149public class ClassifierPanel 
150  extends JPanel
151  implements CapabilitiesFilterChangeListener, ExplorerPanel, LogHandler {
152   
153  /** for serialization */
154  static final long serialVersionUID = 6959973704963624003L;
155
156  /** the parent frame */
157  protected Explorer m_Explorer = null;
158
159  /** The filename extension that should be used for model files */
160  public static String MODEL_FILE_EXTENSION = ".model";
161 
162  /** The filename extension that should be used for PMML xml files */
163  public static String PMML_FILE_EXTENSION = ".xml";
164
165  /** Lets the user configure the classifier */
166  protected GenericObjectEditor m_ClassifierEditor =
167    new GenericObjectEditor();
168
169  /** The panel showing the current classifier selection */
170  protected PropertyPanel m_CEPanel = new PropertyPanel(m_ClassifierEditor);
171 
172  /** The output area for classification results */
173  protected JTextArea m_OutText = new JTextArea(20, 40);
174
175  /** The destination for log/status messages */
176  protected Logger m_Log = new SysErrLog();
177
178  /** The buffer saving object for saving output */
179  SaveBuffer m_SaveOut = new SaveBuffer(m_Log, this);
180
181  /** A panel controlling results viewing */
182  protected ResultHistoryPanel m_History = new ResultHistoryPanel(m_OutText);
183
184  /** Lets the user select the class column */
185  protected JComboBox m_ClassCombo = new JComboBox();
186
187  /** Click to set test mode to cross-validation */
188  protected JRadioButton m_CVBut = new JRadioButton("Cross-validation");
189
190  /** Click to set test mode to generate a % split */
191  protected JRadioButton m_PercentBut = new JRadioButton("Percentage split");
192
193  /** Click to set test mode to test on training data */
194  protected JRadioButton m_TrainBut = new JRadioButton("Use training set");
195
196  /** Click to set test mode to a user-specified test set */
197  protected JRadioButton m_TestSplitBut =
198    new JRadioButton("Supplied test set");
199
200  /** Check to save the predictions in the results list for visualizing
201      later on */
202  protected JCheckBox m_StorePredictionsBut = 
203    new JCheckBox("Store predictions for visualization");
204
205  /** Check to output the model built from the training data */
206  protected JCheckBox m_OutputModelBut = new JCheckBox("Output model");
207
208  /** Check to output true/false positives, precision/recall for each class */
209  protected JCheckBox m_OutputPerClassBut =
210    new JCheckBox("Output per-class stats");
211
212  /** Check to output a confusion matrix */
213  protected JCheckBox m_OutputConfusionBut =
214    new JCheckBox("Output confusion matrix");
215
216  /** Check to output entropy statistics */
217  protected JCheckBox m_OutputEntropyBut =
218    new JCheckBox("Output entropy evaluation measures");
219
220  /** Lets the user configure the ClassificationOutput. */
221  protected GenericObjectEditor m_ClassificationOutputEditor = new GenericObjectEditor(true);
222
223  /** ClassificationOutput configuration. */
224  protected PropertyPanel m_ClassificationOutputPanel = new PropertyPanel(m_ClassificationOutputEditor);
225 
226  /** the range of attributes to output */
227  protected Range m_OutputAdditionalAttributesRange = null;
228 
229  /** Check to evaluate w.r.t a cost matrix */
230  protected JCheckBox m_EvalWRTCostsBut =
231    new JCheckBox("Cost-sensitive evaluation");
232
233  /** for the cost matrix */
234  protected JButton m_SetCostsBut = new JButton("Set...");
235
236  /** Label by where the cv folds are entered */
237  protected JLabel m_CVLab = new JLabel("Folds", SwingConstants.RIGHT);
238
239  /** The field where the cv folds are entered */
240  protected JTextField m_CVText = new JTextField("10", 3);
241
242  /** Label by where the % split is entered */
243  protected JLabel m_PercentLab = new JLabel("%", SwingConstants.RIGHT);
244
245  /** The field where the % split is entered */
246  protected JTextField m_PercentText = new JTextField("66", 3);
247
248  /** The button used to open a separate test dataset */
249  protected JButton m_SetTestBut = new JButton("Set...");
250
251  /** The frame used to show the test set selection panel */
252  protected JFrame m_SetTestFrame;
253
254  /** The frame used to show the cost matrix editing panel */
255  protected PropertyDialog m_SetCostsFrame;
256
257  /**
258   * Alters the enabled/disabled status of elements associated with each
259   * radio button
260   */
261  ActionListener m_RadioListener = new ActionListener() {
262    public void actionPerformed(ActionEvent e) {
263      updateRadioLinks();
264    }
265  };
266
267  /** Button for further output/visualize options */
268  JButton m_MoreOptions = new JButton("More options...");
269
270  /** User specified random seed for cross validation or % split */
271  protected JTextField m_RandomSeedText = new JTextField("1", 3);
272 
273  /** the label for the random seed textfield */
274  protected JLabel m_RandomLab = new JLabel("Random seed for XVal / % Split", 
275                                            SwingConstants.RIGHT);
276
277  /** Whether randomization is turned off to preserve order */
278  protected JCheckBox m_PreserveOrderBut = new JCheckBox("Preserve order for % Split");
279
280  /** Whether to output the source code (only for classifiers importing Sourcable) */
281  protected JCheckBox m_OutputSourceCode = new JCheckBox("Output source code");
282
283  /** The name of the generated class (only applicable to Sourcable schemes) */
284  protected JTextField m_SourceCodeClass = new JTextField("WekaClassifier", 10);
285 
286  /** Click to start running the classifier */
287  protected JButton m_StartBut = new JButton("Start");
288
289  /** Click to stop a running classifier */
290  protected JButton m_StopBut = new JButton("Stop");
291
292  /** Stop the class combo from taking up to much space */
293  private Dimension COMBO_SIZE = new Dimension(150, m_StartBut
294                                               .getPreferredSize().height);
295
296  /** The cost matrix editor for evaluation costs */
297  protected CostMatrixEditor m_CostMatrixEditor = new CostMatrixEditor();
298
299  /** The main set of instances we're playing with */
300  protected Instances m_Instances;
301
302  /** The loader used to load the user-supplied test set (if any) */
303  protected Loader m_TestLoader;
304 
305  /** A thread that classification runs in */
306  protected Thread m_RunThread;
307
308  /** The current visualization object */
309  protected VisualizePanel m_CurrentVis = null;
310
311  /** Filter to ensure only model files are selected */ 
312  protected FileFilter m_ModelFilter =
313    new ExtensionFileFilter(MODEL_FILE_EXTENSION, "Model object files");
314 
315  protected FileFilter m_PMMLModelFilter =
316    new ExtensionFileFilter(PMML_FILE_EXTENSION, "PMML model files");
317
318  /** The file chooser for selecting model files */
319  protected JFileChooser m_FileChooser
320    = new JFileChooser(new File(System.getProperty("user.dir")));
321
322  /* Register the property editors we need */
323  static {
324     GenericObjectEditor.registerEditors();
325  }
326 
327  /**
328   * Creates the classifier panel
329   */
330  public ClassifierPanel() {
331
332    // Connect / configure the components
333    m_OutText.setEditable(false);
334    m_OutText.setFont(new Font("Monospaced", Font.PLAIN, 12));
335    m_OutText.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
336    m_OutText.addMouseListener(new MouseAdapter() {
337      public void mouseClicked(MouseEvent e) {
338        if ((e.getModifiers() & InputEvent.BUTTON1_MASK)
339            != InputEvent.BUTTON1_MASK) {
340          m_OutText.selectAll();
341        }
342      }
343    });
344    m_History.setBorder(BorderFactory.createTitledBorder("Result list (right-click for options)"));
345    m_ClassifierEditor.setClassType(Classifier.class);
346    m_ClassifierEditor.setValue(ExplorerDefaults.getClassifier());
347    m_ClassifierEditor.addPropertyChangeListener(new PropertyChangeListener() {
348      public void propertyChange(PropertyChangeEvent e) {
349        m_StartBut.setEnabled(true);
350        // Check capabilities
351        Capabilities currentFilter = m_ClassifierEditor.getCapabilitiesFilter();
352        Classifier classifier = (Classifier) m_ClassifierEditor.getValue();
353        Capabilities currentSchemeCapabilities =  null;
354        if (classifier != null && currentFilter != null && 
355            (classifier instanceof CapabilitiesHandler)) {
356          currentSchemeCapabilities = ((CapabilitiesHandler)classifier).getCapabilities();
357         
358          if (!currentSchemeCapabilities.supportsMaybe(currentFilter) &&
359              !currentSchemeCapabilities.supports(currentFilter)) {
360            m_StartBut.setEnabled(false);
361          }
362        }
363        repaint();
364      }
365    });
366
367    m_ClassCombo.setToolTipText("Select the attribute to use as the class");
368    m_TrainBut.setToolTipText("Test on the same set that the classifier"
369                              + " is trained on");
370    m_CVBut.setToolTipText("Perform a n-fold cross-validation");
371    m_PercentBut.setToolTipText("Train on a percentage of the data and"
372                                + " test on the remainder");
373    m_TestSplitBut.setToolTipText("Test on a user-specified dataset");
374    m_StartBut.setToolTipText("Starts the classification");
375    m_StopBut.setToolTipText("Stops a running classification");
376    m_StorePredictionsBut.
377      setToolTipText("Store predictions in the result list for later "
378                     +"visualization");
379    m_OutputModelBut
380      .setToolTipText("Output the model obtained from the full training set");
381    m_OutputPerClassBut.setToolTipText("Output precision/recall & true/false"
382                                    + " positives for each class");
383    m_OutputConfusionBut
384      .setToolTipText("Output the matrix displaying class confusions");
385    m_OutputEntropyBut
386      .setToolTipText("Output entropy-based evaluation measures");
387    m_EvalWRTCostsBut
388      .setToolTipText("Evaluate errors with respect to a cost matrix");
389    m_RandomLab.setToolTipText("The seed value for randomization");
390    m_RandomSeedText.setToolTipText(m_RandomLab.getToolTipText());
391    m_PreserveOrderBut.setToolTipText("Preserves the order in a percentage split");
392    m_OutputSourceCode.setToolTipText(
393      "Whether to output the built classifier as Java source code");
394    m_SourceCodeClass.setToolTipText("The classname of the built classifier");
395
396    m_FileChooser.addChoosableFileFilter(m_PMMLModelFilter);
397    m_FileChooser.setFileFilter(m_ModelFilter);
398   
399    m_FileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
400
401    m_ClassificationOutputEditor.setClassType(AbstractOutput.class);
402    m_ClassificationOutputEditor.setValue(new Null());
403   
404    m_StorePredictionsBut.setSelected(ExplorerDefaults.getClassifierStorePredictionsForVis());
405    m_OutputModelBut.setSelected(ExplorerDefaults.getClassifierOutputModel());
406    m_OutputPerClassBut.setSelected(ExplorerDefaults.getClassifierOutputPerClassStats());
407    m_OutputConfusionBut.setSelected(ExplorerDefaults.getClassifierOutputConfusionMatrix());
408    m_EvalWRTCostsBut.setSelected(ExplorerDefaults.getClassifierCostSensitiveEval());
409    m_OutputEntropyBut.setSelected(ExplorerDefaults.getClassifierOutputEntropyEvalMeasures());
410    m_RandomSeedText.setText("" + ExplorerDefaults.getClassifierRandomSeed());
411    m_PreserveOrderBut.setSelected(ExplorerDefaults.getClassifierPreserveOrder());
412    m_OutputSourceCode.addActionListener(new ActionListener() {
413      public void actionPerformed(ActionEvent e) {
414        m_SourceCodeClass.setEnabled(m_OutputSourceCode.isSelected());
415      }
416    });
417    m_OutputSourceCode.setSelected(ExplorerDefaults.getClassifierOutputSourceCode());
418    m_SourceCodeClass.setText(ExplorerDefaults.getClassifierSourceCodeClass());
419    m_SourceCodeClass.setEnabled(m_OutputSourceCode.isSelected());
420    m_ClassCombo.setEnabled(false);
421    m_ClassCombo.setPreferredSize(COMBO_SIZE);
422    m_ClassCombo.setMaximumSize(COMBO_SIZE);
423    m_ClassCombo.setMinimumSize(COMBO_SIZE);
424
425    m_CVBut.setSelected(true);
426    // see "testMode" variable in startClassifier
427    m_CVBut.setSelected(ExplorerDefaults.getClassifierTestMode() == 1);
428    m_PercentBut.setSelected(ExplorerDefaults.getClassifierTestMode() == 2);
429    m_TrainBut.setSelected(ExplorerDefaults.getClassifierTestMode() == 3);
430    m_TestSplitBut.setSelected(ExplorerDefaults.getClassifierTestMode() == 4);
431    m_PercentText.setText("" + ExplorerDefaults.getClassifierPercentageSplit());
432    m_CVText.setText("" + ExplorerDefaults.getClassifierCrossvalidationFolds());
433    updateRadioLinks();
434    ButtonGroup bg = new ButtonGroup();
435    bg.add(m_TrainBut);
436    bg.add(m_CVBut);
437    bg.add(m_PercentBut);
438    bg.add(m_TestSplitBut);
439    m_TrainBut.addActionListener(m_RadioListener);
440    m_CVBut.addActionListener(m_RadioListener);
441    m_PercentBut.addActionListener(m_RadioListener);
442    m_TestSplitBut.addActionListener(m_RadioListener);
443    m_SetTestBut.addActionListener(new ActionListener() {
444      public void actionPerformed(ActionEvent e) {
445        setTestSet();
446      }
447    });
448    m_EvalWRTCostsBut.addActionListener(new ActionListener() {
449      public void actionPerformed(ActionEvent e) {
450        m_SetCostsBut.setEnabled(m_EvalWRTCostsBut.isSelected());
451        if ((m_SetCostsFrame != null) 
452            && (!m_EvalWRTCostsBut.isSelected())) {
453          m_SetCostsFrame.setVisible(false);
454        }
455      }
456    });
457    m_CostMatrixEditor.setValue(new CostMatrix(1));
458    m_SetCostsBut.setEnabled(m_EvalWRTCostsBut.isSelected());
459    m_SetCostsBut.addActionListener(new ActionListener() {
460      public void actionPerformed(ActionEvent e) {
461        m_SetCostsBut.setEnabled(false);
462        if (m_SetCostsFrame == null) {
463          if (PropertyDialog.getParentDialog(ClassifierPanel.this) != null)
464            m_SetCostsFrame = new PropertyDialog(
465                PropertyDialog.getParentDialog(ClassifierPanel.this), 
466                m_CostMatrixEditor, 100, 100);
467          else
468            m_SetCostsFrame = new PropertyDialog(
469                PropertyDialog.getParentFrame(ClassifierPanel.this), 
470                m_CostMatrixEditor, 100, 100);
471          m_SetCostsFrame.setTitle("Cost Matrix Editor");
472          //    pd.setSize(250,150);
473          m_SetCostsFrame.addWindowListener(new java.awt.event.WindowAdapter() {
474            public void windowClosing(java.awt.event.WindowEvent p) {
475              m_SetCostsBut.setEnabled(m_EvalWRTCostsBut.isSelected());
476              if ((m_SetCostsFrame != null) 
477                  && (!m_EvalWRTCostsBut.isSelected())) {
478                m_SetCostsFrame.setVisible(false);
479              }
480            }
481          });
482          m_SetCostsFrame.setVisible(true);
483        }
484       
485        // do we need to change the size of the matrix?
486        int classIndex = m_ClassCombo.getSelectedIndex();
487        int numClasses = m_Instances.attribute(classIndex).numValues();
488        if (numClasses != ((CostMatrix) m_CostMatrixEditor.getValue()).numColumns())
489          m_CostMatrixEditor.setValue(new CostMatrix(numClasses));
490       
491        m_SetCostsFrame.setVisible(true);
492      }
493    });
494
495    m_StartBut.setEnabled(false);
496    m_StopBut.setEnabled(false);
497    m_StartBut.addActionListener(new ActionListener() {
498      public void actionPerformed(ActionEvent e) {
499        startClassifier();
500      }
501    });
502    m_StopBut.addActionListener(new ActionListener() {
503      public void actionPerformed(ActionEvent e) {
504        stopClassifier();
505      }
506    });
507   
508    m_ClassCombo.addActionListener(new ActionListener() {
509      public void actionPerformed(ActionEvent e) {
510        int selected = m_ClassCombo.getSelectedIndex();
511        if (selected != -1) {
512          boolean isNominal = m_Instances.attribute(selected).isNominal();
513          m_OutputPerClassBut.setEnabled(isNominal);
514          m_OutputConfusionBut.setEnabled(isNominal);   
515        }
516        updateCapabilitiesFilter(m_ClassifierEditor.getCapabilitiesFilter());
517      }
518    });
519
520    m_History.setHandleRightClicks(false);
521    // see if we can popup a menu for the selected result
522    m_History.getList().addMouseListener(new MouseAdapter() {
523        public void mouseClicked(MouseEvent e) {
524          if (((e.getModifiers() & InputEvent.BUTTON1_MASK)
525               != InputEvent.BUTTON1_MASK) || e.isAltDown()) {
526            int index = m_History.getList().locationToIndex(e.getPoint());
527            if (index != -1) {
528              String name = m_History.getNameAtIndex(index);
529              visualize(name, e.getX(), e.getY());
530            } else {
531              visualize(null, e.getX(), e.getY());
532            }
533          }
534        }
535      });
536
537    m_MoreOptions.addActionListener(new ActionListener() {
538      public void actionPerformed(ActionEvent e) {
539        m_MoreOptions.setEnabled(false);
540        JPanel moreOptionsPanel = new JPanel();
541        moreOptionsPanel.setBorder(BorderFactory.createEmptyBorder(0, 5, 5, 5));
542        moreOptionsPanel.setLayout(new GridLayout(10, 1));
543        moreOptionsPanel.add(m_OutputModelBut);
544        moreOptionsPanel.add(m_OutputPerClassBut);       
545        moreOptionsPanel.add(m_OutputEntropyBut);         
546        moreOptionsPanel.add(m_OutputConfusionBut);       
547        moreOptionsPanel.add(m_StorePredictionsBut);
548        JPanel classOutPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
549        classOutPanel.add(new JLabel("Output predictions"));
550        classOutPanel.add(m_ClassificationOutputPanel);
551        moreOptionsPanel.add(classOutPanel);
552        JPanel costMatrixOption = new JPanel(new FlowLayout(FlowLayout.LEFT));
553        costMatrixOption.add(m_EvalWRTCostsBut);
554        costMatrixOption.add(m_SetCostsBut);
555        moreOptionsPanel.add(costMatrixOption);
556        JPanel seedPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
557        seedPanel.add(m_RandomLab);
558        seedPanel.add(m_RandomSeedText);
559        moreOptionsPanel.add(seedPanel);
560        moreOptionsPanel.add(m_PreserveOrderBut);
561        JPanel sourcePanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
562        m_OutputSourceCode.setEnabled(m_ClassifierEditor.getValue() instanceof Sourcable);
563        m_SourceCodeClass.setEnabled(m_OutputSourceCode.isEnabled() && m_OutputSourceCode.isSelected());
564        sourcePanel.add(m_OutputSourceCode);
565        sourcePanel.add(m_SourceCodeClass);
566        moreOptionsPanel.add(sourcePanel);
567
568        JPanel all = new JPanel();
569        all.setLayout(new BorderLayout());     
570
571        JButton oK = new JButton("OK");
572        JPanel okP = new JPanel();
573        okP.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
574        okP.setLayout(new GridLayout(1,1,5,5));
575        okP.add(oK);
576
577        all.add(moreOptionsPanel, BorderLayout.CENTER);
578        all.add(okP, BorderLayout.SOUTH);
579       
580        final JDialog jd = 
581          new JDialog(PropertyDialog.getParentFrame(ClassifierPanel.this), "Classifier evaluation options");
582        jd.getContentPane().setLayout(new BorderLayout());
583        jd.getContentPane().add(all, BorderLayout.CENTER);
584        jd.addWindowListener(new java.awt.event.WindowAdapter() {
585          public void windowClosing(java.awt.event.WindowEvent w) {
586            jd.dispose();
587            m_MoreOptions.setEnabled(true);
588          }
589        });
590        oK.addActionListener(new ActionListener() {
591          public void actionPerformed(ActionEvent a) {
592            m_MoreOptions.setEnabled(true);
593            jd.dispose();
594          }
595        });
596        jd.pack();
597       
598        // panel height is only available now
599        m_ClassificationOutputPanel.setPreferredSize(new Dimension(300, m_ClassificationOutputPanel.getHeight()));
600        jd.pack();
601       
602        jd.setLocation(m_MoreOptions.getLocationOnScreen());
603        jd.setVisible(true);
604      }
605    });
606
607    // Layout the GUI
608    JPanel p1 = new JPanel();
609    p1.setBorder(BorderFactory.createCompoundBorder(
610                 BorderFactory.createTitledBorder("Classifier"),
611                 BorderFactory.createEmptyBorder(0, 5, 5, 5)
612                 ));
613    p1.setLayout(new BorderLayout());
614    p1.add(m_CEPanel, BorderLayout.NORTH);
615
616    JPanel p2 = new JPanel();
617    GridBagLayout gbL = new GridBagLayout();
618    p2.setLayout(gbL);
619    p2.setBorder(BorderFactory.createCompoundBorder(
620                 BorderFactory.createTitledBorder("Test options"),
621                 BorderFactory.createEmptyBorder(0, 5, 5, 5)
622                 ));
623    GridBagConstraints gbC = new GridBagConstraints();
624    gbC.anchor = GridBagConstraints.WEST;
625    gbC.gridy = 0;     gbC.gridx = 0;
626    gbL.setConstraints(m_TrainBut, gbC);
627    p2.add(m_TrainBut);
628
629    gbC = new GridBagConstraints();
630    gbC.anchor = GridBagConstraints.WEST;
631    gbC.gridy = 1;     gbC.gridx = 0;
632    gbL.setConstraints(m_TestSplitBut, gbC);
633    p2.add(m_TestSplitBut);
634
635    gbC = new GridBagConstraints();
636    gbC.anchor = GridBagConstraints.EAST;
637    gbC.fill = GridBagConstraints.HORIZONTAL;
638    gbC.gridy = 1;     gbC.gridx = 1;    gbC.gridwidth = 2;
639    gbC.insets = new Insets(2, 10, 2, 0);
640    gbL.setConstraints(m_SetTestBut, gbC);
641    p2.add(m_SetTestBut);
642
643    gbC = new GridBagConstraints();
644    gbC.anchor = GridBagConstraints.WEST;
645    gbC.gridy = 2;     gbC.gridx = 0;
646    gbL.setConstraints(m_CVBut, gbC);
647    p2.add(m_CVBut);
648
649    gbC = new GridBagConstraints();
650    gbC.anchor = GridBagConstraints.EAST;
651    gbC.fill = GridBagConstraints.HORIZONTAL;
652    gbC.gridy = 2;     gbC.gridx = 1;
653    gbC.insets = new Insets(2, 10, 2, 10);
654    gbL.setConstraints(m_CVLab, gbC);
655    p2.add(m_CVLab);
656
657    gbC = new GridBagConstraints();
658    gbC.anchor = GridBagConstraints.EAST;
659    gbC.fill = GridBagConstraints.HORIZONTAL;
660    gbC.gridy = 2;     gbC.gridx = 2;  gbC.weightx = 100;
661    gbC.ipadx = 20;
662    gbL.setConstraints(m_CVText, gbC);
663    p2.add(m_CVText);
664
665    gbC = new GridBagConstraints();
666    gbC.anchor = GridBagConstraints.WEST;
667    gbC.gridy = 3;     gbC.gridx = 0;
668    gbL.setConstraints(m_PercentBut, gbC);
669    p2.add(m_PercentBut);
670
671    gbC = new GridBagConstraints();
672    gbC.anchor = GridBagConstraints.EAST;
673    gbC.fill = GridBagConstraints.HORIZONTAL;
674    gbC.gridy = 3;     gbC.gridx = 1;
675    gbC.insets = new Insets(2, 10, 2, 10);
676    gbL.setConstraints(m_PercentLab, gbC);
677    p2.add(m_PercentLab);
678
679    gbC = new GridBagConstraints();
680    gbC.anchor = GridBagConstraints.EAST;
681    gbC.fill = GridBagConstraints.HORIZONTAL;
682    gbC.gridy = 3;     gbC.gridx = 2;  gbC.weightx = 100;
683    gbC.ipadx = 20;
684    gbL.setConstraints(m_PercentText, gbC);
685    p2.add(m_PercentText);
686
687
688    gbC = new GridBagConstraints();
689    gbC.anchor = GridBagConstraints.WEST;
690    gbC.fill = GridBagConstraints.HORIZONTAL;
691    gbC.gridy = 4;     gbC.gridx = 0;  gbC.weightx = 100;
692    gbC.gridwidth = 3;
693
694    gbC.insets = new Insets(3, 0, 1, 0);
695    gbL.setConstraints(m_MoreOptions, gbC);
696    p2.add(m_MoreOptions);
697
698    JPanel buttons = new JPanel();
699    buttons.setLayout(new GridLayout(2, 2));
700    buttons.add(m_ClassCombo);
701    m_ClassCombo.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
702    JPanel ssButs = new JPanel();
703    ssButs.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
704    ssButs.setLayout(new GridLayout(1, 2, 5, 5));
705    ssButs.add(m_StartBut);
706    ssButs.add(m_StopBut);
707
708    buttons.add(ssButs);
709   
710    JPanel p3 = new JPanel();
711    p3.setBorder(BorderFactory.createTitledBorder("Classifier output"));
712    p3.setLayout(new BorderLayout());
713    final JScrollPane js = new JScrollPane(m_OutText);
714    p3.add(js, BorderLayout.CENTER);
715    js.getViewport().addChangeListener(new ChangeListener() {
716      private int lastHeight;
717      public void stateChanged(ChangeEvent e) {
718        JViewport vp = (JViewport)e.getSource();
719        int h = vp.getViewSize().height; 
720        if (h != lastHeight) { // i.e. an addition not just a user scrolling
721          lastHeight = h;
722          int x = h - vp.getExtentSize().height;
723          vp.setViewPosition(new Point(0, x));
724        }
725      }
726    });
727   
728    JPanel mondo = new JPanel();
729    gbL = new GridBagLayout();
730    mondo.setLayout(gbL);
731    gbC = new GridBagConstraints();
732    //    gbC.anchor = GridBagConstraints.WEST;
733    gbC.fill = GridBagConstraints.HORIZONTAL;
734    gbC.gridy = 0;     gbC.gridx = 0;
735    gbL.setConstraints(p2, gbC);
736    mondo.add(p2);
737    gbC = new GridBagConstraints();
738    gbC.anchor = GridBagConstraints.NORTH;
739    gbC.fill = GridBagConstraints.HORIZONTAL;
740    gbC.gridy = 1;     gbC.gridx = 0;
741    gbL.setConstraints(buttons, gbC);
742    mondo.add(buttons);
743    gbC = new GridBagConstraints();
744    //gbC.anchor = GridBagConstraints.NORTH;
745    gbC.fill = GridBagConstraints.BOTH;
746    gbC.gridy = 2;     gbC.gridx = 0; gbC.weightx = 0;
747    gbL.setConstraints(m_History, gbC);
748    mondo.add(m_History);
749    gbC = new GridBagConstraints();
750    gbC.fill = GridBagConstraints.BOTH;
751    gbC.gridy = 0;     gbC.gridx = 1;
752    gbC.gridheight = 3;
753    gbC.weightx = 100; gbC.weighty = 100;
754    gbL.setConstraints(p3, gbC);
755    mondo.add(p3);
756
757    setLayout(new BorderLayout());
758    add(p1, BorderLayout.NORTH);
759    add(mondo, BorderLayout.CENTER);
760  }
761
762 
763  /**
764   * Updates the enabled status of the input fields and labels.
765   */
766  protected void updateRadioLinks() {
767   
768    m_SetTestBut.setEnabled(m_TestSplitBut.isSelected());
769    if ((m_SetTestFrame != null) && (!m_TestSplitBut.isSelected())) {
770      m_SetTestFrame.setVisible(false);
771    }
772    m_CVText.setEnabled(m_CVBut.isSelected());
773    m_CVLab.setEnabled(m_CVBut.isSelected());
774    m_PercentText.setEnabled(m_PercentBut.isSelected());
775    m_PercentLab.setEnabled(m_PercentBut.isSelected());
776  }
777
778  /**
779   * Sets the Logger to receive informational messages
780   *
781   * @param newLog the Logger that will now get info messages
782   */
783  public void setLog(Logger newLog) {
784
785    m_Log = newLog;
786  }
787
788  /**
789   * Tells the panel to use a new set of instances.
790   *
791   * @param inst a set of Instances
792   */
793  public void setInstances(Instances inst) {
794    m_Instances = inst;
795
796    String [] attribNames = new String [m_Instances.numAttributes()];
797    for (int i = 0; i < attribNames.length; i++) {
798      String type = "";
799      switch (m_Instances.attribute(i).type()) {
800      case Attribute.NOMINAL:
801        type = "(Nom) ";
802        break;
803      case Attribute.NUMERIC:
804        type = "(Num) ";
805        break;
806      case Attribute.STRING:
807        type = "(Str) ";
808        break;
809      case Attribute.DATE:
810        type = "(Dat) ";
811        break;
812      case Attribute.RELATIONAL:
813        type = "(Rel) ";
814        break;
815      default:
816        type = "(???) ";
817      }
818      attribNames[i] = type + m_Instances.attribute(i).name();
819    }
820    m_ClassCombo.setModel(new DefaultComboBoxModel(attribNames));
821    if (attribNames.length > 0) {
822      if (inst.classIndex() == -1)
823        m_ClassCombo.setSelectedIndex(attribNames.length - 1);
824      else
825        m_ClassCombo.setSelectedIndex(inst.classIndex());
826      m_ClassCombo.setEnabled(true);
827      m_StartBut.setEnabled(m_RunThread == null);
828      m_StopBut.setEnabled(m_RunThread != null);
829    } else {
830      m_StartBut.setEnabled(false);
831      m_StopBut.setEnabled(false);
832    }
833  }
834
835  /**
836   * Sets the user test set. Information about the current test set
837   * is displayed in an InstanceSummaryPanel and the user is given the
838   * ability to load another set from a file or url.
839   *
840   */
841  protected void setTestSet() {
842
843    if (m_SetTestFrame == null) {
844      final SetInstancesPanel sp = new SetInstancesPanel(true);
845
846      if (m_TestLoader != null) {
847        try {
848          if (m_TestLoader.getStructure() != null) {
849            sp.setInstances(m_TestLoader.getStructure());
850          }
851        } catch (Exception ex) {
852          ex.printStackTrace();
853        }
854      }
855      sp.addPropertyChangeListener(new PropertyChangeListener() {
856        public void propertyChange(PropertyChangeEvent e) {
857          m_TestLoader = sp.getLoader();
858        }
859      });
860      // Add propertychangelistener to update m_TestLoader whenever
861      // it changes in the settestframe
862      m_SetTestFrame = new JFrame("Test Instances");
863      sp.setParentFrame(m_SetTestFrame);   // enable Close-Button
864      m_SetTestFrame.getContentPane().setLayout(new BorderLayout());
865      m_SetTestFrame.getContentPane().add(sp, BorderLayout.CENTER);
866      m_SetTestFrame.pack();
867    }
868    m_SetTestFrame.setVisible(true);
869  }
870
871  /**
872   * outputs the header for the predictions on the data.
873   *
874   * @param outBuff                     the buffer to add the output to
875   * @param classificationOutput        for generating the classification output
876   * @param title                       the title to print
877   */
878  protected void printPredictionsHeader(StringBuffer outBuff, AbstractOutput classificationOutput, String title) {
879    if (classificationOutput.generatesOutput())
880      outBuff.append("=== Predictions on " + title + " ===\n\n");
881    classificationOutput.printHeader();
882  }
883 
884  /**
885   * Starts running the currently configured classifier with the current
886   * settings. This is run in a separate thread, and will only start if
887   * there is no classifier already running. The classifier output is sent
888   * to the results history panel.
889   */
890  protected void startClassifier() {
891
892    if (m_RunThread == null) {
893      synchronized (this) {
894        m_StartBut.setEnabled(false);
895        m_StopBut.setEnabled(true);
896      }
897      m_RunThread = new Thread() {
898        public void run() {
899          // Copy the current state of things
900          m_Log.statusMessage("Setting up...");
901          CostMatrix costMatrix = null;
902          Instances inst = new Instances(m_Instances);
903          DataSource source = null;
904          Instances userTestStructure = null;
905          ClassifierErrorsPlotInstances plotInstances = null;
906         
907          // for timing
908          long trainTimeStart = 0, trainTimeElapsed = 0;
909
910          try {
911            if (m_TestLoader != null && m_TestLoader.getStructure() != null) {
912              m_TestLoader.reset();
913              source = new DataSource(m_TestLoader);
914              userTestStructure = source.getStructure();
915            }
916          } catch (Exception ex) {
917            ex.printStackTrace();
918          }
919          if (m_EvalWRTCostsBut.isSelected()) {
920            costMatrix = new CostMatrix((CostMatrix) m_CostMatrixEditor
921                                        .getValue());
922          }
923          boolean outputModel = m_OutputModelBut.isSelected();
924          boolean outputConfusion = m_OutputConfusionBut.isSelected();
925          boolean outputPerClass = m_OutputPerClassBut.isSelected();
926          boolean outputSummary = true;
927          boolean outputEntropy = m_OutputEntropyBut.isSelected();
928          boolean saveVis = m_StorePredictionsBut.isSelected();
929          boolean outputPredictionsText = (m_ClassificationOutputEditor.getValue().getClass() != Null.class);
930
931          String grph = null;
932
933          int testMode = 0;
934          int numFolds = 10;
935          double percent = 66;
936          int classIndex = m_ClassCombo.getSelectedIndex();
937          Classifier classifier = (Classifier) m_ClassifierEditor.getValue();
938          Classifier template = null;
939          try {
940            template = AbstractClassifier.makeCopy(classifier);
941          } catch (Exception ex) {
942            m_Log.logMessage("Problem copying classifier: " + ex.getMessage());
943          }
944          Classifier fullClassifier = null;
945          StringBuffer outBuff = new StringBuffer();
946          AbstractOutput classificationOutput = null; 
947          if (outputPredictionsText) {
948            classificationOutput = (AbstractOutput) m_ClassificationOutputEditor.getValue();
949            Instances header = new Instances(inst, 0);
950            header.setClassIndex(classIndex);
951            classificationOutput.setHeader(header);
952            classificationOutput.setBuffer(outBuff);
953          }
954          String name = (new SimpleDateFormat("HH:mm:ss - "))
955          .format(new Date());
956          String cname = classifier.getClass().getName();
957          if (cname.startsWith("weka.classifiers.")) {
958            name += cname.substring("weka.classifiers.".length());
959          } else {
960            name += cname;
961          }
962          String cmd = m_ClassifierEditor.getValue().getClass().getName();
963          if (m_ClassifierEditor.getValue() instanceof OptionHandler)
964            cmd += " " + Utils.joinOptions(((OptionHandler) m_ClassifierEditor.getValue()).getOptions());
965          Evaluation eval = null;
966          try {
967            if (m_CVBut.isSelected()) {
968              testMode = 1;
969              numFolds = Integer.parseInt(m_CVText.getText());
970              if (numFolds <= 1) {
971                throw new Exception("Number of folds must be greater than 1");
972              }
973            } else if (m_PercentBut.isSelected()) {
974              testMode = 2;
975              percent = Double.parseDouble(m_PercentText.getText());
976              if ((percent <= 0) || (percent >= 100)) {
977                throw new Exception("Percentage must be between 0 and 100");
978              }
979            } else if (m_TrainBut.isSelected()) {
980              testMode = 3;
981            } else if (m_TestSplitBut.isSelected()) {
982              testMode = 4;
983              // Check the test instance compatibility
984              if (source == null) {
985                throw new Exception("No user test set has been specified");
986              }
987              if (!inst.equalHeaders(userTestStructure)) {
988                throw new Exception("Train and test set are not compatible\n" + inst.equalHeadersMsg(userTestStructure));
989              }
990              userTestStructure.setClassIndex(classIndex);
991            } else {
992              throw new Exception("Unknown test mode");
993            }
994            inst.setClassIndex(classIndex);
995
996            // set up the structure of the plottable instances for
997            // visualization
998            plotInstances = ExplorerDefaults.getClassifierErrorsPlotInstances();
999            plotInstances.setInstances(inst);
1000            plotInstances.setClassifier(classifier);
1001            plotInstances.setClassIndex(inst.classIndex());
1002            plotInstances.setSaveForVisualization(saveVis);
1003
1004            // Output some header information
1005            m_Log.logMessage("Started " + cname);
1006            m_Log.logMessage("Command: " + cmd);
1007            if (m_Log instanceof TaskLogger) {
1008              ((TaskLogger)m_Log).taskStarted();
1009            }
1010            outBuff.append("=== Run information ===\n\n");
1011            outBuff.append("Scheme:       " + cname);
1012            if (classifier instanceof OptionHandler) {
1013              String [] o = ((OptionHandler) classifier).getOptions();
1014              outBuff.append(" " + Utils.joinOptions(o));
1015            }
1016            outBuff.append("\n");
1017            outBuff.append("Relation:     " + inst.relationName() + '\n');
1018            outBuff.append("Instances:    " + inst.numInstances() + '\n');
1019            outBuff.append("Attributes:   " + inst.numAttributes() + '\n');
1020            if (inst.numAttributes() < 100) {
1021              for (int i = 0; i < inst.numAttributes(); i++) {
1022                outBuff.append("              " + inst.attribute(i).name()
1023                               + '\n');
1024              }
1025            } else {
1026              outBuff.append("              [list of attributes omitted]\n");
1027            }
1028
1029            outBuff.append("Test mode:    ");
1030            switch (testMode) {
1031              case 3: // Test on training
1032                outBuff.append("evaluate on training data\n");
1033                break;
1034              case 1: // CV mode
1035                outBuff.append("" + numFolds + "-fold cross-validation\n");
1036                break;
1037              case 2: // Percent split
1038                outBuff.append("split " + percent
1039                    + "% train, remainder test\n");
1040                break;
1041              case 4: // Test on user split
1042                if (source.isIncremental())
1043                  outBuff.append("user supplied test set: "
1044                      + " size unknown (reading incrementally)\n");
1045                else
1046                  outBuff.append("user supplied test set: "
1047                      + source.getDataSet().numInstances() + " instances\n");
1048                break;
1049            }
1050            if (costMatrix != null) {
1051               outBuff.append("Evaluation cost matrix:\n")
1052               .append(costMatrix.toString()).append("\n");
1053            }
1054            outBuff.append("\n");
1055            m_History.addResult(name, outBuff);
1056            m_History.setSingle(name);
1057           
1058            // Build the model and output it.
1059            if (outputModel || (testMode == 3) || (testMode == 4)) {
1060              m_Log.statusMessage("Building model on training data...");
1061
1062              trainTimeStart = System.currentTimeMillis();
1063              classifier.buildClassifier(inst);
1064              trainTimeElapsed = System.currentTimeMillis() - trainTimeStart;
1065            }
1066
1067            if (outputModel) {
1068              outBuff.append("=== Classifier model (full training set) ===\n\n");
1069              outBuff.append(classifier.toString() + "\n");
1070              outBuff.append("\nTime taken to build model: " +
1071                             Utils.doubleToString(trainTimeElapsed / 1000.0,2)
1072                             + " seconds\n\n");
1073              m_History.updateResult(name);
1074              if (classifier instanceof Drawable) {
1075                grph = null;
1076                try {
1077                  grph = ((Drawable)classifier).graph();
1078                } catch (Exception ex) {
1079                }
1080              }
1081              // copy full model for output
1082              SerializedObject so = new SerializedObject(classifier);
1083              fullClassifier = (Classifier) so.getObject();
1084            }
1085           
1086            switch (testMode) {
1087              case 3: // Test on training
1088              m_Log.statusMessage("Evaluating on training data...");
1089              eval = new Evaluation(inst, costMatrix);
1090              plotInstances.setEvaluation(eval);
1091              plotInstances.setUp();
1092             
1093              if (outputPredictionsText) {
1094                printPredictionsHeader(outBuff, classificationOutput, "training set");
1095              }
1096
1097              for (int jj=0;jj<inst.numInstances();jj++) {
1098                plotInstances.process(inst.instance(jj), classifier, eval);
1099               
1100                if (outputPredictionsText) {
1101                  classificationOutput.printClassification(classifier, inst.instance(jj), jj);
1102                }
1103                if ((jj % 100) == 0) {
1104                  m_Log.statusMessage("Evaluating on training data. Processed "
1105                                      +jj+" instances...");
1106                }
1107              }
1108              if (outputPredictionsText)
1109                classificationOutput.printFooter();
1110              if (outputPredictionsText && classificationOutput.generatesOutput()) {
1111                outBuff.append("\n");
1112              } 
1113              outBuff.append("=== Evaluation on training set ===\n");
1114              break;
1115
1116              case 1: // CV mode
1117              m_Log.statusMessage("Randomizing instances...");
1118              int rnd = 1;
1119              try {
1120                rnd = Integer.parseInt(m_RandomSeedText.getText().trim());
1121                // System.err.println("Using random seed "+rnd);
1122              } catch (Exception ex) {
1123                m_Log.logMessage("Trouble parsing random seed value");
1124                rnd = 1;
1125              }
1126              Random random = new Random(rnd);
1127              inst.randomize(random);
1128              if (inst.attribute(classIndex).isNominal()) {
1129                m_Log.statusMessage("Stratifying instances...");
1130                inst.stratify(numFolds);
1131              }
1132              eval = new Evaluation(inst, costMatrix);
1133              plotInstances.setEvaluation(eval);
1134              plotInstances.setUp();
1135     
1136              if (outputPredictionsText) {
1137                printPredictionsHeader(outBuff, classificationOutput, "test data");
1138              }
1139
1140              // Make some splits and do a CV
1141              for (int fold = 0; fold < numFolds; fold++) {
1142                m_Log.statusMessage("Creating splits for fold "
1143                                    + (fold + 1) + "...");
1144                Instances train = inst.trainCV(numFolds, fold, random);
1145                eval.setPriors(train);
1146                m_Log.statusMessage("Building model for fold "
1147                                    + (fold + 1) + "...");
1148                Classifier current = null;
1149                try {
1150                  current = AbstractClassifier.makeCopy(template);
1151                } catch (Exception ex) {
1152                  m_Log.logMessage("Problem copying classifier: " + ex.getMessage());
1153                }
1154                current.buildClassifier(train);
1155                Instances test = inst.testCV(numFolds, fold);
1156                m_Log.statusMessage("Evaluating model for fold "
1157                                    + (fold + 1) + "...");
1158                for (int jj=0;jj<test.numInstances();jj++) {
1159                  plotInstances.process(test.instance(jj), current, eval);
1160                  if (outputPredictionsText) {
1161                    classificationOutput.printClassification(current, test.instance(jj), jj);
1162                  }
1163                }
1164              }
1165              if (outputPredictionsText)
1166                classificationOutput.printFooter();
1167              if (outputPredictionsText) {
1168                outBuff.append("\n");
1169              } 
1170              if (inst.attribute(classIndex).isNominal()) {
1171                outBuff.append("=== Stratified cross-validation ===\n");
1172              } else {
1173                outBuff.append("=== Cross-validation ===\n");
1174              }
1175              break;
1176               
1177              case 2: // Percent split
1178              if (!m_PreserveOrderBut.isSelected()) {
1179                m_Log.statusMessage("Randomizing instances...");
1180                try {
1181                  rnd = Integer.parseInt(m_RandomSeedText.getText().trim());
1182                } catch (Exception ex) {
1183                  m_Log.logMessage("Trouble parsing random seed value");
1184                  rnd = 1;
1185                }
1186                inst.randomize(new Random(rnd));
1187              }
1188              int trainSize = (int) Math.round(inst.numInstances() * percent / 100);
1189              int testSize = inst.numInstances() - trainSize;
1190              Instances train = new Instances(inst, 0, trainSize);
1191              Instances test = new Instances(inst, trainSize, testSize);
1192              m_Log.statusMessage("Building model on training split ("+trainSize+" instances)...");
1193              Classifier current = null;
1194              try {
1195                current = AbstractClassifier.makeCopy(template);
1196              } catch (Exception ex) {
1197                m_Log.logMessage("Problem copying classifier: " + ex.getMessage());
1198              }
1199              current.buildClassifier(train);
1200              eval = new Evaluation(train, costMatrix);
1201              plotInstances.setEvaluation(eval);
1202              plotInstances.setUp();
1203              m_Log.statusMessage("Evaluating on test split...");
1204             
1205              if (outputPredictionsText) {
1206                printPredictionsHeader(outBuff, classificationOutput, "test split");
1207              }
1208     
1209              for (int jj=0;jj<test.numInstances();jj++) {
1210                plotInstances.process(test.instance(jj), current, eval);
1211                if (outputPredictionsText) { 
1212                  classificationOutput.printClassification(current, test.instance(jj), jj);
1213                }
1214                if ((jj % 100) == 0) {
1215                  m_Log.statusMessage("Evaluating on test split. Processed "
1216                                      +jj+" instances...");
1217                }
1218              }
1219              if (outputPredictionsText)
1220                classificationOutput.printFooter();
1221              if (outputPredictionsText) {
1222                outBuff.append("\n");
1223              } 
1224              outBuff.append("=== Evaluation on test split ===\n");
1225              break;
1226               
1227              case 4: // Test on user split
1228              m_Log.statusMessage("Evaluating on test data...");
1229              eval = new Evaluation(inst, costMatrix);
1230              plotInstances.setEvaluation(eval);
1231              plotInstances.setUp();
1232             
1233              if (outputPredictionsText) {
1234                printPredictionsHeader(outBuff, classificationOutput, "test set");
1235              }
1236
1237              Instance instance;
1238              int jj = 0;
1239              while (source.hasMoreElements(userTestStructure)) {
1240                instance = source.nextElement(userTestStructure);
1241                plotInstances.process(instance, classifier, eval);
1242                if (outputPredictionsText) {
1243                  classificationOutput.printClassification(classifier, instance, jj);
1244                }
1245                if ((++jj % 100) == 0) {
1246                  m_Log.statusMessage("Evaluating on test data. Processed "
1247                      +jj+" instances...");
1248                }
1249              }
1250
1251              if (outputPredictionsText)
1252                classificationOutput.printFooter();
1253              if (outputPredictionsText) {
1254                outBuff.append("\n");
1255              } 
1256              outBuff.append("=== Evaluation on test set ===\n");
1257              break;
1258
1259              default:
1260              throw new Exception("Test mode not implemented");
1261            }
1262           
1263            if (outputSummary) {
1264              outBuff.append(eval.toSummaryString(outputEntropy) + "\n");
1265            }
1266
1267            if (inst.attribute(classIndex).isNominal()) {
1268
1269              if (outputPerClass) {
1270                outBuff.append(eval.toClassDetailsString() + "\n");
1271              }
1272
1273              if (outputConfusion) {
1274                outBuff.append(eval.toMatrixString() + "\n");
1275              }
1276            }
1277
1278            if (   (fullClassifier instanceof Sourcable) 
1279                 && m_OutputSourceCode.isSelected()) {
1280              outBuff.append("=== Source code ===\n\n");
1281              outBuff.append(
1282                Evaluation.wekaStaticWrapper(
1283                    ((Sourcable) fullClassifier),
1284                    m_SourceCodeClass.getText()));
1285            }
1286
1287            m_History.updateResult(name);
1288            m_Log.logMessage("Finished " + cname);
1289            m_Log.statusMessage("OK");
1290          } catch (Exception ex) {
1291            ex.printStackTrace();
1292            m_Log.logMessage(ex.getMessage());
1293            JOptionPane.showMessageDialog(ClassifierPanel.this,
1294                                          "Problem evaluating classifier:\n"
1295                                          + ex.getMessage(),
1296                                          "Evaluate classifier",
1297                                          JOptionPane.ERROR_MESSAGE);
1298            m_Log.statusMessage("Problem evaluating classifier");
1299          } finally {
1300            try {
1301              if (!saveVis && outputModel) {
1302                  FastVector vv = new FastVector();
1303                  vv.addElement(fullClassifier);
1304                  Instances trainHeader = new Instances(m_Instances, 0);
1305                  trainHeader.setClassIndex(classIndex);
1306                  vv.addElement(trainHeader);
1307                  if (grph != null) {
1308                    vv.addElement(grph);
1309                  }
1310                  m_History.addObject(name, vv);
1311              } else if (saveVis && plotInstances != null && plotInstances.getPlotInstances().numInstances() > 0) {
1312                m_CurrentVis = new VisualizePanel();
1313                m_CurrentVis.setName(name+" ("+inst.relationName()+")");
1314                m_CurrentVis.setLog(m_Log);
1315                m_CurrentVis.addPlot(plotInstances.getPlotData(cname));
1316                m_CurrentVis.setColourIndex(plotInstances.getPlotInstances().classIndex()+1);
1317                plotInstances.cleanUp();
1318           
1319                FastVector vv = new FastVector();
1320                if (outputModel) {
1321                  vv.addElement(fullClassifier);
1322                  Instances trainHeader = new Instances(m_Instances, 0);
1323                  trainHeader.setClassIndex(classIndex);
1324                  vv.addElement(trainHeader);
1325                  if (grph != null) {
1326                    vv.addElement(grph);
1327                  }
1328                }
1329                vv.addElement(m_CurrentVis);
1330               
1331                if ((eval != null) && (eval.predictions() != null)) {
1332                  vv.addElement(eval.predictions());
1333                  vv.addElement(inst.classAttribute());
1334                }
1335                m_History.addObject(name, vv);
1336              }
1337            } catch (Exception ex) {
1338              ex.printStackTrace();
1339            }
1340           
1341            if (isInterrupted()) {
1342              m_Log.logMessage("Interrupted " + cname);
1343              m_Log.statusMessage("Interrupted");
1344            }
1345
1346            synchronized (this) {
1347              m_StartBut.setEnabled(true);
1348              m_StopBut.setEnabled(false);
1349              m_RunThread = null;
1350            }
1351            if (m_Log instanceof TaskLogger) {
1352              ((TaskLogger)m_Log).taskFinished();
1353            }
1354          }
1355        }
1356      };
1357      m_RunThread.setPriority(Thread.MIN_PRIORITY);
1358      m_RunThread.start();
1359    }
1360  }
1361
1362  /**
1363   * Handles constructing a popup menu with visualization options.
1364   * @param name the name of the result history list entry clicked on by
1365   * the user
1366   * @param x the x coordinate for popping up the menu
1367   * @param y the y coordinate for popping up the menu
1368   */
1369  protected void visualize(String name, int x, int y) {
1370    final String selectedName = name;
1371    JPopupMenu resultListMenu = new JPopupMenu();
1372   
1373    JMenuItem visMainBuffer = new JMenuItem("View in main window");
1374    if (selectedName != null) {
1375      visMainBuffer.addActionListener(new ActionListener() {
1376          public void actionPerformed(ActionEvent e) {
1377            m_History.setSingle(selectedName);
1378          }
1379        });
1380    } else {
1381      visMainBuffer.setEnabled(false);
1382    }
1383    resultListMenu.add(visMainBuffer);
1384   
1385    JMenuItem visSepBuffer = new JMenuItem("View in separate window");
1386    if (selectedName != null) {
1387      visSepBuffer.addActionListener(new ActionListener() {
1388        public void actionPerformed(ActionEvent e) {
1389          m_History.openFrame(selectedName);
1390        }
1391      });
1392    } else {
1393      visSepBuffer.setEnabled(false);
1394    }
1395    resultListMenu.add(visSepBuffer);
1396   
1397    JMenuItem saveOutput = new JMenuItem("Save result buffer");
1398    if (selectedName != null) {
1399      saveOutput.addActionListener(new ActionListener() {
1400          public void actionPerformed(ActionEvent e) {
1401            saveBuffer(selectedName);
1402          }
1403        });
1404    } else {
1405      saveOutput.setEnabled(false);
1406    }
1407    resultListMenu.add(saveOutput);
1408   
1409    JMenuItem deleteOutput = new JMenuItem("Delete result buffer");
1410    if (selectedName != null) {
1411      deleteOutput.addActionListener(new ActionListener() {
1412        public void actionPerformed(ActionEvent e) {
1413          m_History.removeResult(selectedName);
1414        }
1415      });
1416    } else {
1417      deleteOutput.setEnabled(false);
1418    }
1419    resultListMenu.add(deleteOutput);
1420
1421    resultListMenu.addSeparator();
1422   
1423    JMenuItem loadModel = new JMenuItem("Load model");
1424    loadModel.addActionListener(new ActionListener() {
1425        public void actionPerformed(ActionEvent e) {
1426          loadClassifier();
1427        }
1428      });
1429    resultListMenu.add(loadModel);
1430
1431    FastVector o = null;
1432    if (selectedName != null) {
1433      o = (FastVector)m_History.getNamedObject(selectedName);
1434    }
1435
1436    VisualizePanel temp_vp = null;
1437    String temp_grph = null;
1438    FastVector temp_preds = null;
1439    Attribute temp_classAtt = null;
1440    Classifier temp_classifier = null;
1441    Instances temp_trainHeader = null;
1442     
1443    if (o != null) { 
1444      for (int i = 0; i < o.size(); i++) {
1445        Object temp = o.elementAt(i);
1446        if (temp instanceof Classifier) {
1447          temp_classifier = (Classifier)temp;
1448        } else if (temp instanceof Instances) { // training header
1449          temp_trainHeader = (Instances)temp;
1450        } else if (temp instanceof VisualizePanel) { // normal errors
1451          temp_vp = (VisualizePanel)temp;
1452        } else if (temp instanceof String) { // graphable output
1453          temp_grph = (String)temp;
1454        } else if (temp instanceof FastVector) { // predictions
1455          temp_preds = (FastVector)temp;
1456        } else if (temp instanceof Attribute) { // class attribute
1457          temp_classAtt = (Attribute)temp;
1458        }
1459      }
1460    }
1461
1462    final VisualizePanel vp = temp_vp;
1463    final String grph = temp_grph;
1464    final FastVector preds = temp_preds;
1465    final Attribute classAtt = temp_classAtt;
1466    final Classifier classifier = temp_classifier;
1467    final Instances trainHeader = temp_trainHeader;
1468   
1469    JMenuItem saveModel = new JMenuItem("Save model");
1470    if (classifier != null) {
1471      saveModel.addActionListener(new ActionListener() {
1472          public void actionPerformed(ActionEvent e) {
1473            saveClassifier(selectedName, classifier, trainHeader);
1474          }
1475        });
1476    } else {
1477      saveModel.setEnabled(false);
1478    }
1479    resultListMenu.add(saveModel);
1480
1481    JMenuItem reEvaluate =
1482      new JMenuItem("Re-evaluate model on current test set");
1483    if (classifier != null && m_TestLoader != null) {
1484      reEvaluate.addActionListener(new ActionListener() {
1485          public void actionPerformed(ActionEvent e) {
1486            reevaluateModel(selectedName, classifier, trainHeader);
1487          }
1488        });
1489    } else {
1490      reEvaluate.setEnabled(false);
1491    }
1492    resultListMenu.add(reEvaluate);
1493   
1494    resultListMenu.addSeparator();
1495   
1496    JMenuItem visErrors = new JMenuItem("Visualize classifier errors");
1497    if (vp != null) {
1498      if ((vp.getXIndex() == 0) && (vp.getYIndex() == 1)) {
1499        try {
1500          vp.setXIndex(vp.getInstances().classIndex());  // class
1501          vp.setYIndex(vp.getInstances().classIndex() - 1);  // predicted class
1502        }
1503        catch (Exception e) {
1504          // ignored
1505        }
1506      }
1507      visErrors.addActionListener(new ActionListener() {
1508          public void actionPerformed(ActionEvent e) {
1509            visualizeClassifierErrors(vp);
1510          }
1511        });
1512    } else {
1513      visErrors.setEnabled(false);
1514    }
1515    resultListMenu.add(visErrors);
1516
1517    JMenuItem visGrph = new JMenuItem("Visualize tree");
1518    if (grph != null) {
1519        if(((Drawable)temp_classifier).graphType()==Drawable.TREE) {
1520            visGrph.addActionListener(new ActionListener() {
1521                    public void actionPerformed(ActionEvent e) {
1522                        String title;
1523                        if (vp != null) title = vp.getName();
1524                        else title = selectedName;
1525                        visualizeTree(grph, title);
1526                    }
1527                });
1528        }
1529        else if(((Drawable)temp_classifier).graphType()==Drawable.BayesNet) {
1530            visGrph.setText("Visualize graph");
1531            visGrph.addActionListener(new ActionListener() {
1532                    public void actionPerformed(ActionEvent e) {
1533                        Thread th = new Thread() {
1534                                public void run() {
1535                                visualizeBayesNet(grph, selectedName);
1536                                }
1537                            };
1538                        th.start();
1539                    }
1540                });
1541        }
1542        else
1543            visGrph.setEnabled(false);
1544    } else {
1545      visGrph.setEnabled(false);
1546    }
1547    resultListMenu.add(visGrph);
1548
1549    JMenuItem visMargin = new JMenuItem("Visualize margin curve");
1550    if ((preds != null) && (classAtt != null) && (classAtt.isNominal())) {
1551      visMargin.addActionListener(new ActionListener() {
1552          public void actionPerformed(ActionEvent e) {
1553            try {
1554              MarginCurve tc = new MarginCurve();
1555              Instances result = tc.getCurve(preds);
1556              VisualizePanel vmc = new VisualizePanel();
1557              vmc.setName(result.relationName());
1558              vmc.setLog(m_Log);
1559              PlotData2D tempd = new PlotData2D(result);
1560              tempd.setPlotName(result.relationName());
1561              tempd.addInstanceNumberAttribute();
1562              vmc.addPlot(tempd);
1563              visualizeClassifierErrors(vmc);
1564            } catch (Exception ex) {
1565              ex.printStackTrace();
1566            }
1567          }
1568        });
1569    } else {
1570      visMargin.setEnabled(false);
1571    }
1572    resultListMenu.add(visMargin);
1573
1574    JMenu visThreshold = new JMenu("Visualize threshold curve");
1575    if ((preds != null) && (classAtt != null) && (classAtt.isNominal())) {
1576      for (int i = 0; i < classAtt.numValues(); i++) {
1577        JMenuItem clv = new JMenuItem(classAtt.value(i));
1578        final int classValue = i;
1579        clv.addActionListener(new ActionListener() {
1580            public void actionPerformed(ActionEvent e) {
1581              try {
1582                ThresholdCurve tc = new ThresholdCurve();
1583                Instances result = tc.getCurve(preds, classValue);
1584                //VisualizePanel vmc = new VisualizePanel();
1585                ThresholdVisualizePanel vmc = new ThresholdVisualizePanel();
1586                vmc.setROCString("(Area under ROC = " + 
1587                                 Utils.doubleToString(ThresholdCurve.getROCArea(result), 4) + ")");
1588                vmc.setLog(m_Log);
1589                vmc.setName(result.relationName()+". (Class value "+
1590                            classAtt.value(classValue)+")");
1591                PlotData2D tempd = new PlotData2D(result);
1592                tempd.setPlotName(result.relationName());
1593                tempd.addInstanceNumberAttribute();
1594                // specify which points are connected
1595                boolean[] cp = new boolean[result.numInstances()];
1596                for (int n = 1; n < cp.length; n++)
1597                  cp[n] = true;
1598                tempd.setConnectPoints(cp);
1599                // add plot
1600                vmc.addPlot(tempd);
1601                visualizeClassifierErrors(vmc);
1602              } catch (Exception ex) {
1603                ex.printStackTrace();
1604              }
1605              }
1606          });
1607          visThreshold.add(clv);
1608      }
1609    } else {
1610      visThreshold.setEnabled(false);
1611    }
1612    resultListMenu.add(visThreshold);
1613   
1614    JMenu visCostBenefit = new JMenu("Cost/Benefit analysis");
1615    if ((preds != null) && (classAtt != null) && (classAtt.isNominal())) {
1616      for (int i = 0; i < classAtt.numValues(); i++) {
1617        JMenuItem clv = new JMenuItem(classAtt.value(i));
1618        final int classValue = i;
1619        clv.addActionListener(new ActionListener() {
1620            public void actionPerformed(ActionEvent e) {
1621              try {
1622                ThresholdCurve tc = new ThresholdCurve();
1623                Instances result = tc.getCurve(preds, classValue);
1624
1625                // Create a dummy class attribute with the chosen
1626                // class value as index 0 (if necessary).
1627                Attribute classAttToUse = classAtt;
1628                if (classValue != 0) {
1629                  FastVector newNames = new FastVector();
1630                  newNames.addElement(classAtt.value(classValue));
1631                  for (int k = 0; k < classAtt.numValues(); k++) {
1632                    if (k != classValue) {
1633                      newNames.addElement(classAtt.value(k));
1634                    }
1635                  }
1636                  classAttToUse = new Attribute(classAtt.name(), newNames);
1637                }
1638               
1639                CostBenefitAnalysis cbAnalysis = new CostBenefitAnalysis();
1640               
1641                PlotData2D tempd = new PlotData2D(result);
1642                tempd.setPlotName(result.relationName());
1643                tempd.m_alwaysDisplayPointsOfThisSize = 10;
1644                // specify which points are connected
1645                boolean[] cp = new boolean[result.numInstances()];
1646                for (int n = 1; n < cp.length; n++)
1647                  cp[n] = true;
1648                tempd.setConnectPoints(cp);
1649               
1650                String windowTitle = "";
1651                if (classifier != null) {
1652                  String cname = classifier.getClass().getName();
1653                  if (cname.startsWith("weka.classifiers.")) {
1654                    windowTitle = "" + cname.substring("weka.classifiers.".length()) + " ";
1655                  }
1656                }
1657                windowTitle += " (class = " + classAttToUse.value(0) + ")";               
1658               
1659                // add plot
1660                cbAnalysis.setCurveData(tempd, classAttToUse);
1661                visualizeCostBenefitAnalysis(cbAnalysis, windowTitle);
1662              } catch (Exception ex) {
1663                ex.printStackTrace();
1664              }
1665              }
1666          });
1667          visCostBenefit.add(clv);
1668      }
1669    } else {
1670      visCostBenefit.setEnabled(false);
1671    }
1672    resultListMenu.add(visCostBenefit);
1673
1674    JMenu visCost = new JMenu("Visualize cost curve");
1675    if ((preds != null) && (classAtt != null) && (classAtt.isNominal())) {
1676      for (int i = 0; i < classAtt.numValues(); i++) {
1677        JMenuItem clv = new JMenuItem(classAtt.value(i));
1678        final int classValue = i;
1679        clv.addActionListener(new ActionListener() {
1680            public void actionPerformed(ActionEvent e) {
1681              try {
1682                CostCurve cc = new CostCurve();
1683                Instances result = cc.getCurve(preds, classValue);
1684                VisualizePanel vmc = new VisualizePanel();
1685                vmc.setLog(m_Log);
1686                vmc.setName(result.relationName()+". (Class value "+
1687                            classAtt.value(classValue)+")");
1688                PlotData2D tempd = new PlotData2D(result);
1689                tempd.m_displayAllPoints = true;
1690                tempd.setPlotName(result.relationName());
1691                boolean [] connectPoints = 
1692                  new boolean [result.numInstances()];
1693                for (int jj = 1; jj < connectPoints.length; jj+=2) {
1694                  connectPoints[jj] = true;
1695                }
1696                tempd.setConnectPoints(connectPoints);
1697                //                tempd.addInstanceNumberAttribute();
1698                vmc.addPlot(tempd);
1699                visualizeClassifierErrors(vmc);
1700              } catch (Exception ex) {
1701                ex.printStackTrace();
1702              }
1703            }
1704          });
1705        visCost.add(clv);
1706      }
1707    } else {
1708      visCost.setEnabled(false);
1709    }
1710    resultListMenu.add(visCost);
1711   
1712    // visualization plugins
1713    JMenu visPlugins = new JMenu("Plugins");
1714    boolean availablePlugins = false;
1715   
1716    // predictions
1717    Vector pluginsVector = GenericObjectEditor.getClassnames(VisualizePlugin.class.getName());
1718    for (int i = 0; i < pluginsVector.size(); i++) {
1719      String className = (String) (pluginsVector.elementAt(i));
1720      try {
1721        VisualizePlugin plugin = (VisualizePlugin) Class.forName(className).newInstance();
1722        if (plugin == null)
1723          continue;
1724        availablePlugins = true;
1725        JMenuItem pluginMenuItem = plugin.getVisualizeMenuItem(preds, classAtt);
1726        Version version = new Version();
1727        if (pluginMenuItem != null) {
1728          if (version.compareTo(plugin.getMinVersion()) < 0)
1729            pluginMenuItem.setText(pluginMenuItem.getText() + " (weka outdated)");
1730          if (version.compareTo(plugin.getMaxVersion()) >= 0)
1731            pluginMenuItem.setText(pluginMenuItem.getText() + " (plugin outdated)");
1732          visPlugins.add(pluginMenuItem);
1733        }
1734      }
1735      catch (Exception e) {
1736          //e.printStackTrace();
1737      }
1738    }
1739   
1740    // errros
1741    pluginsVector = GenericObjectEditor.getClassnames(ErrorVisualizePlugin.class.getName());
1742    for (int i = 0; i < pluginsVector.size(); i++) {
1743      String className = (String) (pluginsVector.elementAt(i));
1744      try {
1745        ErrorVisualizePlugin plugin = (ErrorVisualizePlugin) Class.forName(className).newInstance();
1746        if (plugin == null)
1747          continue;
1748        availablePlugins = true;
1749        JMenuItem pluginMenuItem = plugin.getVisualizeMenuItem(vp.getInstances());
1750        Version version = new Version();
1751        if (pluginMenuItem != null) {
1752          if (version.compareTo(plugin.getMinVersion()) < 0)
1753            pluginMenuItem.setText(pluginMenuItem.getText() + " (weka outdated)");
1754          if (version.compareTo(plugin.getMaxVersion()) >= 0)
1755            pluginMenuItem.setText(pluginMenuItem.getText() + " (plugin outdated)");
1756          visPlugins.add(pluginMenuItem);
1757        }
1758      }
1759      catch (Exception e) {
1760          //e.printStackTrace();
1761      }
1762    }
1763   
1764    // graphs+trees
1765    if (grph != null) {
1766      // trees
1767      if (((Drawable) temp_classifier).graphType() == Drawable.TREE) {
1768        pluginsVector = GenericObjectEditor.getClassnames(TreeVisualizePlugin.class.getName());
1769        for (int i = 0; i < pluginsVector.size(); i++) {
1770          String className = (String) (pluginsVector.elementAt(i));
1771          try {
1772            TreeVisualizePlugin plugin = (TreeVisualizePlugin) Class.forName(className).newInstance();
1773            if (plugin == null)
1774              continue;
1775            availablePlugins = true;
1776            JMenuItem pluginMenuItem = plugin.getVisualizeMenuItem(grph, selectedName);
1777            Version version = new Version();
1778            if (pluginMenuItem != null) {
1779              if (version.compareTo(plugin.getMinVersion()) < 0)
1780                pluginMenuItem.setText(pluginMenuItem.getText() + " (weka outdated)");
1781              if (version.compareTo(plugin.getMaxVersion()) >= 0)
1782                pluginMenuItem.setText(pluginMenuItem.getText() + " (plugin outdated)");
1783              visPlugins.add(pluginMenuItem);
1784            }
1785          }
1786          catch (Exception e) {
1787            //e.printStackTrace();
1788          }
1789        }
1790      }
1791      // graphs
1792      else {
1793        pluginsVector = GenericObjectEditor.getClassnames(GraphVisualizePlugin.class.getName());
1794        for (int i = 0; i < pluginsVector.size(); i++) {
1795          String className = (String) (pluginsVector.elementAt(i));
1796          try {
1797            GraphVisualizePlugin plugin = (GraphVisualizePlugin) Class.forName(className).newInstance();
1798            if (plugin == null)
1799              continue;
1800            availablePlugins = true;
1801            JMenuItem pluginMenuItem = plugin.getVisualizeMenuItem(grph, selectedName);
1802            Version version = new Version();
1803            if (pluginMenuItem != null) {
1804              if (version.compareTo(plugin.getMinVersion()) < 0)
1805                pluginMenuItem.setText(pluginMenuItem.getText() + " (weka outdated)");
1806              if (version.compareTo(plugin.getMaxVersion()) >= 0)
1807                pluginMenuItem.setText(pluginMenuItem.getText() + " (plugin outdated)");
1808              visPlugins.add(pluginMenuItem);
1809            }
1810          }
1811          catch (Exception e) {
1812            //e.printStackTrace();
1813          }
1814        }
1815      }
1816    }
1817
1818    if (availablePlugins)
1819      resultListMenu.add(visPlugins);
1820
1821    resultListMenu.show(m_History.getList(), x, y);
1822  }
1823
1824  /**
1825   * Pops up a TreeVisualizer for the classifier from the currently
1826   * selected item in the results list
1827   * @param dottyString the description of the tree in dotty format
1828   * @param treeName the title to assign to the display
1829   */
1830  protected void visualizeTree(String dottyString, String treeName) {
1831    final javax.swing.JFrame jf = 
1832      new javax.swing.JFrame("Weka Classifier Tree Visualizer: "+treeName);
1833    jf.setSize(500,400);
1834    jf.getContentPane().setLayout(new BorderLayout());
1835    TreeVisualizer tv = new TreeVisualizer(null,
1836                                           dottyString,
1837                                           new PlaceNode2());
1838    jf.getContentPane().add(tv, BorderLayout.CENTER);
1839    jf.addWindowListener(new java.awt.event.WindowAdapter() {
1840        public void windowClosing(java.awt.event.WindowEvent e) {
1841          jf.dispose();
1842        }
1843      });
1844   
1845    jf.setVisible(true);
1846    tv.fitToScreen();
1847  }
1848
1849  /**
1850   * Pops up a GraphVisualizer for the BayesNet classifier from the currently
1851   * selected item in the results list
1852   *
1853   * @param XMLBIF the description of the graph in XMLBIF ver. 0.3
1854   * @param graphName the name of the graph
1855   */
1856  protected void visualizeBayesNet(String XMLBIF, String graphName) {
1857    final javax.swing.JFrame jf = 
1858      new javax.swing.JFrame("Weka Classifier Graph Visualizer: "+graphName);
1859    jf.setSize(500,400);
1860    jf.getContentPane().setLayout(new BorderLayout());
1861    GraphVisualizer gv = new GraphVisualizer();
1862    try { gv.readBIF(XMLBIF);
1863    }
1864    catch(BIFFormatException be) { System.err.println("unable to visualize BayesNet"); be.printStackTrace(); }
1865    gv.layoutGraph();
1866
1867    jf.getContentPane().add(gv, BorderLayout.CENTER);
1868    jf.addWindowListener(new java.awt.event.WindowAdapter() {
1869        public void windowClosing(java.awt.event.WindowEvent e) {
1870          jf.dispose();
1871        }
1872      });
1873   
1874    jf.setVisible(true);
1875  }
1876 
1877  /**
1878   * Pops up the Cost/Benefit analysis panel.
1879   *
1880   * @param cb the CostBenefitAnalysis panel to pop up
1881   */
1882  protected void visualizeCostBenefitAnalysis(CostBenefitAnalysis cb, 
1883      String classifierAndRelationName) {
1884    if (cb != null) {
1885      String windowTitle = "Weka Classifier: Cost/Benefit Analysis ";
1886      if (classifierAndRelationName != null) {
1887        windowTitle += "- " + classifierAndRelationName;
1888      }
1889      final javax.swing.JFrame jf = 
1890        new javax.swing.JFrame(windowTitle);
1891        jf.setSize(1000,600);
1892        jf.getContentPane().setLayout(new BorderLayout());
1893
1894        jf.getContentPane().add(cb, BorderLayout.CENTER);
1895        jf.addWindowListener(new java.awt.event.WindowAdapter() {
1896          public void windowClosing(java.awt.event.WindowEvent e) {
1897            jf.dispose();
1898          }
1899        });
1900
1901    jf.setVisible(true);
1902    }
1903  }
1904
1905
1906  /**
1907   * Pops up a VisualizePanel for visualizing the data and errors for
1908   * the classifier from the currently selected item in the results list
1909   * @param sp the VisualizePanel to pop up.
1910   */
1911  protected void visualizeClassifierErrors(VisualizePanel sp) {
1912   
1913    if (sp != null) {
1914      String plotName = sp.getName(); 
1915        final javax.swing.JFrame jf = 
1916        new javax.swing.JFrame("Weka Classifier Visualize: "+plotName);
1917        jf.setSize(600,400);
1918        jf.getContentPane().setLayout(new BorderLayout());
1919
1920        jf.getContentPane().add(sp, BorderLayout.CENTER);
1921        jf.addWindowListener(new java.awt.event.WindowAdapter() {
1922          public void windowClosing(java.awt.event.WindowEvent e) {
1923            jf.dispose();
1924          }
1925        });
1926
1927    jf.setVisible(true);
1928    }
1929  }
1930
1931  /**
1932   * Save the currently selected classifier output to a file.
1933   * @param name the name of the buffer to save
1934   */
1935  protected void saveBuffer(String name) {
1936    StringBuffer sb = m_History.getNamedBuffer(name);
1937    if (sb != null) {
1938      if (m_SaveOut.save(sb)) {
1939        m_Log.logMessage("Save successful.");
1940      }
1941    }
1942  }
1943 
1944
1945  /**
1946   * Stops the currently running classifier (if any).
1947   */
1948  protected void stopClassifier() {
1949
1950    if (m_RunThread != null) {
1951      m_RunThread.interrupt();
1952     
1953      // This is deprecated (and theoretically the interrupt should do).
1954      m_RunThread.stop();
1955    }
1956  }
1957
1958  /**
1959   * Saves the currently selected classifier
1960   *
1961   * @param name the name of the run
1962   * @param classifier the classifier to save
1963   * @param trainHeader the header of the training instances
1964   */
1965  protected void saveClassifier(String name, Classifier classifier,
1966                                Instances trainHeader) {
1967
1968    File sFile = null;
1969    boolean saveOK = true;
1970 
1971    int returnVal = m_FileChooser.showSaveDialog(this);
1972    if (returnVal == JFileChooser.APPROVE_OPTION) {
1973      sFile = m_FileChooser.getSelectedFile();
1974      if (!sFile.getName().toLowerCase().endsWith(MODEL_FILE_EXTENSION)) {
1975        sFile = new File(sFile.getParent(), sFile.getName() 
1976                         + MODEL_FILE_EXTENSION);
1977      }
1978      m_Log.statusMessage("Saving model to file...");
1979     
1980      try {
1981        OutputStream os = new FileOutputStream(sFile);
1982        if (sFile.getName().endsWith(".gz")) {
1983          os = new GZIPOutputStream(os);
1984        }
1985        ObjectOutputStream objectOutputStream = new ObjectOutputStream(os);
1986        objectOutputStream.writeObject(classifier);
1987        if (trainHeader != null) objectOutputStream.writeObject(trainHeader);
1988        objectOutputStream.flush();
1989        objectOutputStream.close();
1990      } catch (Exception e) {
1991       
1992        JOptionPane.showMessageDialog(null, e, "Save Failed",
1993                                      JOptionPane.ERROR_MESSAGE);
1994        saveOK = false;
1995      }
1996      if (saveOK)
1997        m_Log.logMessage("Saved model (" + name
1998                         + ") to file '" + sFile.getName() + "'");
1999      m_Log.statusMessage("OK");
2000    }
2001  }
2002
2003  /**
2004   * Loads a classifier
2005   */
2006  protected void loadClassifier() {
2007
2008    int returnVal = m_FileChooser.showOpenDialog(this);
2009    if (returnVal == JFileChooser.APPROVE_OPTION) {
2010      File selected = m_FileChooser.getSelectedFile();
2011      Classifier classifier = null;
2012      Instances trainHeader = null;
2013
2014      m_Log.statusMessage("Loading model from file...");
2015
2016      try {
2017        InputStream is = new FileInputStream(selected);
2018        if (selected.getName().endsWith(PMML_FILE_EXTENSION)) {
2019          PMMLModel model = PMMLFactory.getPMMLModel(is, m_Log);
2020          if (model instanceof PMMLClassifier) {
2021            classifier = (PMMLClassifier)model;
2022            /*trainHeader =
2023              ((PMMLClassifier)classifier).getMiningSchema().getMiningSchemaAsInstances(); */
2024          } else {
2025            throw new Exception("PMML model is not a classification/regression model!");
2026          }
2027        } else {
2028        if (selected.getName().endsWith(".gz")) {
2029          is = new GZIPInputStream(is);
2030        }
2031        ObjectInputStream objectInputStream = new ObjectInputStream(is);
2032        classifier = (Classifier) objectInputStream.readObject();
2033        try { // see if we can load the header
2034          trainHeader = (Instances) objectInputStream.readObject();
2035        } catch (Exception e) {} // don't fuss if we can't
2036        objectInputStream.close();
2037        }
2038      } catch (Exception e) {
2039       
2040        JOptionPane.showMessageDialog(null, e, "Load Failed",
2041                                      JOptionPane.ERROR_MESSAGE);
2042      } 
2043
2044      m_Log.statusMessage("OK");
2045     
2046      if (classifier != null) {
2047        m_Log.logMessage("Loaded model from file '" + selected.getName()+ "'");
2048        String name = (new SimpleDateFormat("HH:mm:ss - ")).format(new Date());
2049        String cname = classifier.getClass().getName();
2050        if (cname.startsWith("weka.classifiers."))
2051          cname = cname.substring("weka.classifiers.".length());
2052        name += cname + " from file '" + selected.getName() + "'";
2053        StringBuffer outBuff = new StringBuffer();
2054
2055        outBuff.append("=== Model information ===\n\n");
2056        outBuff.append("Filename:     " + selected.getName() + "\n");
2057        outBuff.append("Scheme:       " + classifier.getClass().getName());
2058        if (classifier instanceof OptionHandler) {
2059          String [] o = ((OptionHandler) classifier).getOptions();
2060          outBuff.append(" " + Utils.joinOptions(o));
2061        }
2062        outBuff.append("\n");
2063        if (trainHeader != null) {
2064          outBuff.append("Relation:     " + trainHeader.relationName() + '\n');
2065          outBuff.append("Attributes:   " + trainHeader.numAttributes() + '\n');
2066          if (trainHeader.numAttributes() < 100) {
2067            for (int i = 0; i < trainHeader.numAttributes(); i++) {
2068              outBuff.append("              " + trainHeader.attribute(i).name()
2069                             + '\n');
2070            }
2071          } else {
2072            outBuff.append("              [list of attributes omitted]\n");
2073          }
2074        } else {
2075          outBuff.append("\nTraining data unknown\n");
2076        } 
2077
2078        outBuff.append("\n=== Classifier model ===\n\n");
2079        outBuff.append(classifier.toString() + "\n");
2080       
2081        m_History.addResult(name, outBuff);
2082        m_History.setSingle(name);
2083        FastVector vv = new FastVector();
2084        vv.addElement(classifier);
2085        if (trainHeader != null) vv.addElement(trainHeader);
2086        // allow visualization of graphable classifiers
2087        String grph = null;
2088        if (classifier instanceof Drawable) {
2089          try {
2090            grph = ((Drawable)classifier).graph();
2091          } catch (Exception ex) {
2092          }
2093        }
2094        if (grph != null) vv.addElement(grph);
2095       
2096        m_History.addObject(name, vv);
2097      }
2098    }
2099  }
2100 
2101  /**
2102   * Re-evaluates the named classifier with the current test set. Unpredictable
2103   * things will happen if the data set is not compatible with the classifier.
2104   *
2105   * @param name the name of the classifier entry
2106   * @param classifier the classifier to evaluate
2107   * @param trainHeader the header of the training set
2108   */
2109  protected void reevaluateModel(final String name, 
2110                                 final Classifier classifier, 
2111                                 final Instances trainHeader) {
2112
2113    if (m_RunThread == null) {
2114      synchronized (this) {
2115        m_StartBut.setEnabled(false);
2116        m_StopBut.setEnabled(true);
2117      }
2118      m_RunThread = new Thread() {
2119          public void run() {
2120            // Copy the current state of things
2121            m_Log.statusMessage("Setting up...");
2122
2123            StringBuffer outBuff = m_History.getNamedBuffer(name);
2124            DataSource source = null;
2125            Instances userTestStructure = null;
2126            ClassifierErrorsPlotInstances plotInstances = null;
2127
2128            CostMatrix costMatrix = null;
2129            if (m_EvalWRTCostsBut.isSelected()) {
2130              costMatrix = new CostMatrix((CostMatrix) m_CostMatrixEditor
2131                                          .getValue());
2132            }   
2133            boolean outputConfusion = m_OutputConfusionBut.isSelected();
2134            boolean outputPerClass = m_OutputPerClassBut.isSelected();
2135            boolean outputSummary = true;
2136            boolean outputEntropy = m_OutputEntropyBut.isSelected();
2137            boolean saveVis = m_StorePredictionsBut.isSelected();
2138            boolean outputPredictionsText = (m_ClassificationOutputEditor.getValue().getClass() != Null.class);
2139            String grph = null;   
2140            Evaluation eval = null;
2141
2142            try {
2143
2144              boolean incrementalLoader = (m_TestLoader instanceof IncrementalConverter);
2145              if (m_TestLoader != null && m_TestLoader.getStructure() != null) {
2146                m_TestLoader.reset();
2147                source = new DataSource(m_TestLoader);
2148                userTestStructure = source.getStructure();
2149              }
2150              // Check the test instance compatibility
2151              if (source == null) {
2152                throw new Exception("No user test set has been specified");
2153              }
2154              if (trainHeader != null) {
2155                if (trainHeader.classIndex() > 
2156                    userTestStructure.numAttributes()-1)
2157                  throw new Exception("Train and test set are not compatible");
2158                userTestStructure.setClassIndex(trainHeader.classIndex());
2159                if (!trainHeader.equalHeaders(userTestStructure)) {
2160                  throw new Exception("Train and test set are not compatible:\n" + trainHeader.equalHeadersMsg(userTestStructure));
2161                }
2162              } else {
2163                if (classifier instanceof PMMLClassifier) {
2164                  // set the class based on information in the mining schema
2165                  Instances miningSchemaStructure = 
2166                    ((PMMLClassifier)classifier).getMiningSchema().getMiningSchemaAsInstances();
2167                  String className = miningSchemaStructure.classAttribute().name();
2168                  Attribute classMatch = userTestStructure.attribute(className);
2169                  if (classMatch == null) {
2170                    throw new Exception("Can't find a match for the PMML target field " 
2171                        + className + " in the "
2172                        + "test instances!");
2173                  }
2174                  userTestStructure.setClass(classMatch);
2175                } else {
2176                  userTestStructure.
2177                    setClassIndex(userTestStructure.numAttributes()-1);
2178                }
2179              }
2180              if (m_Log instanceof TaskLogger) {
2181                ((TaskLogger)m_Log).taskStarted();
2182              }
2183              m_Log.statusMessage("Evaluating on test data...");
2184              m_Log.logMessage("Re-evaluating classifier (" + name
2185                               + ") on test set");
2186              eval = new Evaluation(userTestStructure, costMatrix);
2187              eval.useNoPriors();
2188     
2189              // set up the structure of the plottable instances for
2190              // visualization if selected
2191              if (saveVis) {
2192                plotInstances = new ClassifierErrorsPlotInstances();
2193                plotInstances.setInstances(userTestStructure);
2194                plotInstances.setClassifier(classifier);
2195                plotInstances.setClassIndex(userTestStructure.classIndex());
2196                plotInstances.setUp();
2197              }
2198     
2199              outBuff.append("\n=== Re-evaluation on test set ===\n\n");
2200              outBuff.append("User supplied test set\n"); 
2201              outBuff.append("Relation:     " 
2202                             + userTestStructure.relationName() + '\n');
2203              if (incrementalLoader)
2204                outBuff.append("Instances:     unknown (yet). Reading incrementally\n");
2205              else
2206                outBuff.append("Instances:    " + source.getDataSet().numInstances() + "\n");
2207              outBuff.append("Attributes:   " 
2208                  + userTestStructure.numAttributes() 
2209                  + "\n\n");
2210              if (trainHeader == null)
2211                outBuff.append("NOTE - if test set is not compatible then results are "
2212                               + "unpredictable\n\n");
2213
2214              AbstractOutput classificationOutput = null;
2215              if (outputPredictionsText) {
2216                classificationOutput = (AbstractOutput) m_ClassificationOutputEditor.getValue();
2217                classificationOutput.setHeader(userTestStructure);
2218                classificationOutput.setBuffer(outBuff);
2219                classificationOutput.setAttributes("");
2220                classificationOutput.setOutputDistribution(false);
2221                classificationOutput.printHeader();
2222              }
2223
2224              Instance instance;
2225              int jj = 0;
2226              while (source.hasMoreElements(userTestStructure)) {
2227                instance = source.nextElement(userTestStructure);
2228                plotInstances.process(instance, classifier, eval);
2229                if (outputPredictionsText) {
2230                  classificationOutput.printClassification(classifier, instance, jj);
2231                }
2232                if ((++jj % 100) == 0) {
2233                  m_Log.statusMessage("Evaluating on test data. Processed "
2234                      +jj+" instances...");
2235                }
2236              }
2237
2238              if (outputPredictionsText)
2239                classificationOutput.printFooter();
2240              if (outputPredictionsText && classificationOutput.generatesOutput()) {
2241                outBuff.append("\n");
2242              } 
2243     
2244              if (outputSummary) {
2245                outBuff.append(eval.toSummaryString(outputEntropy) + "\n");
2246              }
2247     
2248              if (userTestStructure.classAttribute().isNominal()) {
2249       
2250                if (outputPerClass) {
2251                  outBuff.append(eval.toClassDetailsString() + "\n");
2252                }
2253       
2254                if (outputConfusion) {
2255                  outBuff.append(eval.toMatrixString() + "\n");
2256                }
2257              }
2258     
2259              m_History.updateResult(name);
2260              m_Log.logMessage("Finished re-evaluation");
2261              m_Log.statusMessage("OK");
2262            } catch (Exception ex) {
2263              ex.printStackTrace();
2264              m_Log.logMessage(ex.getMessage());
2265              m_Log.statusMessage("See error log");
2266
2267              ex.printStackTrace();
2268              m_Log.logMessage(ex.getMessage());
2269              JOptionPane.showMessageDialog(ClassifierPanel.this,
2270                                            "Problem evaluationg classifier:\n"
2271                                            + ex.getMessage(),
2272                                            "Evaluate classifier",
2273                                            JOptionPane.ERROR_MESSAGE);
2274              m_Log.statusMessage("Problem evaluating classifier");
2275            } finally {
2276              try {
2277                if (classifier instanceof PMMLClassifier) {
2278                  // signal the end of the scoring run so
2279                  // that the initialized state can be reset
2280                  // (forces the field mapping to be recomputed
2281                  // for the next scoring run).
2282                  ((PMMLClassifier)classifier).done();
2283                }
2284               
2285                if (plotInstances != null && plotInstances.getPlotInstances().numInstances() > 0) {
2286                  m_CurrentVis = new VisualizePanel();
2287                  m_CurrentVis.setName(name + " (" + userTestStructure.relationName() + ")");
2288                  m_CurrentVis.setLog(m_Log);
2289                  m_CurrentVis.addPlot(plotInstances.getPlotData(name));
2290                  m_CurrentVis.setColourIndex(plotInstances.getPlotInstances().classIndex()+1);
2291                  plotInstances.cleanUp();
2292         
2293                  if (classifier instanceof Drawable) {
2294                    try {
2295                      grph = ((Drawable)classifier).graph();
2296                    } catch (Exception ex) {
2297                    }
2298                  }
2299
2300                  if (saveVis) {
2301                    FastVector vv = new FastVector();
2302                    vv.addElement(classifier);
2303                    if (trainHeader != null) vv.addElement(trainHeader);
2304                    vv.addElement(m_CurrentVis);
2305                    if (grph != null) {
2306                      vv.addElement(grph);
2307                    }
2308                    if ((eval != null) && (eval.predictions() != null)) {
2309                      vv.addElement(eval.predictions());
2310                      vv.addElement(userTestStructure.classAttribute());
2311                    }
2312                    m_History.addObject(name, vv);
2313                  } else {
2314                    FastVector vv = new FastVector();
2315                    vv.addElement(classifier);
2316                    if (trainHeader != null) vv.addElement(trainHeader);
2317                    m_History.addObject(name, vv);
2318                  }
2319                }
2320              } catch (Exception ex) {
2321                ex.printStackTrace();
2322              }
2323              if (isInterrupted()) {
2324                m_Log.logMessage("Interrupted reevaluate model");
2325                m_Log.statusMessage("Interrupted");
2326              }
2327
2328              synchronized (this) {
2329                m_StartBut.setEnabled(true);
2330                m_StopBut.setEnabled(false);
2331                m_RunThread = null;
2332              }
2333
2334              if (m_Log instanceof TaskLogger) {
2335                ((TaskLogger)m_Log).taskFinished();
2336              }
2337            }
2338          }
2339        };
2340
2341      m_RunThread.setPriority(Thread.MIN_PRIORITY);
2342      m_RunThread.start();
2343    }
2344  }
2345 
2346  /**
2347   * updates the capabilities filter of the GOE
2348   *
2349   * @param filter      the new filter to use
2350   */
2351  protected void updateCapabilitiesFilter(Capabilities filter) {
2352    Instances           tempInst;
2353    Capabilities        filterClass;
2354
2355    if (filter == null) {
2356      m_ClassifierEditor.setCapabilitiesFilter(new Capabilities(null));
2357      return;
2358    }
2359   
2360    if (!ExplorerDefaults.getInitGenericObjectEditorFilter())
2361      tempInst = new Instances(m_Instances, 0);
2362    else
2363      tempInst = new Instances(m_Instances);
2364    tempInst.setClassIndex(m_ClassCombo.getSelectedIndex());
2365
2366    try {
2367      filterClass = Capabilities.forInstances(tempInst);
2368    }
2369    catch (Exception e) {
2370      filterClass = new Capabilities(null);
2371    }
2372   
2373    // set new filter
2374    m_ClassifierEditor.setCapabilitiesFilter(filterClass);
2375   
2376    // Check capabilities
2377    m_StartBut.setEnabled(true);
2378    Capabilities currentFilter = m_ClassifierEditor.getCapabilitiesFilter();
2379    Classifier classifier = (Classifier) m_ClassifierEditor.getValue();
2380    Capabilities currentSchemeCapabilities =  null;
2381    if (classifier != null && currentFilter != null && 
2382        (classifier instanceof CapabilitiesHandler)) {
2383      currentSchemeCapabilities = ((CapabilitiesHandler)classifier).getCapabilities();
2384     
2385      if (!currentSchemeCapabilities.supportsMaybe(currentFilter) &&
2386          !currentSchemeCapabilities.supports(currentFilter)) {
2387        m_StartBut.setEnabled(false);
2388      }
2389    }
2390  }
2391 
2392  /**
2393   * method gets called in case of a change event
2394   *
2395   * @param e           the associated change event
2396   */
2397  public void capabilitiesFilterChanged(CapabilitiesFilterChangeEvent e) {
2398    if (e.getFilter() == null)
2399      updateCapabilitiesFilter(null);
2400    else
2401      updateCapabilitiesFilter((Capabilities) e.getFilter().clone());
2402  }
2403
2404  /**
2405   * Sets the Explorer to use as parent frame (used for sending notifications
2406   * about changes in the data)
2407   *
2408   * @param parent      the parent frame
2409   */
2410  public void setExplorer(Explorer parent) {
2411    m_Explorer = parent;
2412  }
2413 
2414  /**
2415   * returns the parent Explorer frame
2416   *
2417   * @return            the parent
2418   */
2419  public Explorer getExplorer() {
2420    return m_Explorer;
2421  }
2422 
2423  /**
2424   * Returns the title for the tab in the Explorer
2425   *
2426   * @return            the title of this tab
2427   */
2428  public String getTabTitle() {
2429    return "Classify";
2430  }
2431 
2432  /**
2433   * Returns the tooltip for the tab in the Explorer
2434   *
2435   * @return            the tooltip of this tab
2436   */
2437  public String getTabTitleToolTip() {
2438    return "Classify instances";
2439  }
2440 
2441  /**
2442   * Tests out the classifier panel from the command line.
2443   *
2444   * @param args may optionally contain the name of a dataset to load.
2445   */
2446  public static void main(String [] args) {
2447
2448    try {
2449      final javax.swing.JFrame jf =
2450        new javax.swing.JFrame("Weka Explorer: Classifier");
2451      jf.getContentPane().setLayout(new BorderLayout());
2452      final ClassifierPanel sp = new ClassifierPanel();
2453      jf.getContentPane().add(sp, BorderLayout.CENTER);
2454      weka.gui.LogPanel lp = new weka.gui.LogPanel();
2455      sp.setLog(lp);
2456      jf.getContentPane().add(lp, BorderLayout.SOUTH);
2457      jf.addWindowListener(new java.awt.event.WindowAdapter() {
2458        public void windowClosing(java.awt.event.WindowEvent e) {
2459          jf.dispose();
2460          System.exit(0);
2461        }
2462      });
2463      jf.pack();
2464      jf.setSize(800, 600);
2465      jf.setVisible(true);
2466      if (args.length == 1) {
2467        System.err.println("Loading instances from " + args[0]);
2468        java.io.Reader r = new java.io.BufferedReader(
2469                           new java.io.FileReader(args[0]));
2470        Instances i = new Instances(r);
2471        sp.setInstances(i);
2472      }
2473    } catch (Exception ex) {
2474      ex.printStackTrace();
2475      System.err.println(ex.getMessage());
2476    }
2477  }
2478}
Note: See TracBrowser for help on using the repository browser.