AttributeSelectionPanel.java
Upload User: rhdiban
Upload Date: 2013-08-09
Package Size: 15085k
Code Size: 28k
Category:

Windows Develop

Development Platform:

Java

  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.  *    AttributeSelectionPanel.java
  18.  *    Copyright (C) 1999 Mark Hall
  19.  *
  20.  */
  21. package weka.gui.explorer;
  22. import weka.core.Instances;
  23. import weka.core.OptionHandler;
  24. import weka.core.Attribute;
  25. import weka.core.Utils;
  26. import weka.core.Range;
  27. import weka.core.FastVector;
  28. import weka.attributeSelection.ASEvaluation;
  29. import weka.attributeSelection.ASSearch;
  30. import weka.attributeSelection.AttributeTransformer;
  31. import weka.attributeSelection.AttributeSelection;
  32. import weka.filters.Filter;
  33. import weka.gui.Logger;
  34. import weka.gui.TaskLogger;
  35. import weka.gui.SysErrLog;
  36. import weka.gui.GenericObjectEditor;
  37. import weka.gui.PropertyPanel;
  38. import weka.gui.ResultHistoryPanel;
  39. import weka.gui.SetInstancesPanel;
  40. import weka.gui.SaveBuffer;
  41. import weka.gui.FileEditor;
  42. import weka.gui.visualize.VisualizePanel;
  43. import weka.gui.visualize.PlotData2D;
  44. import java.util.Random;
  45. import java.util.Date;
  46. import java.text.SimpleDateFormat;
  47. import java.awt.FlowLayout;
  48. import java.awt.BorderLayout;
  49. import java.awt.GridLayout;
  50. import java.awt.GridBagLayout;
  51. import java.awt.GridBagConstraints;
  52. import java.awt.Insets;
  53. import java.awt.Font;
  54. import java.awt.event.ActionListener;
  55. import java.awt.event.ActionEvent;
  56. import java.awt.event.InputEvent;
  57. import java.awt.event.MouseAdapter;
  58. import java.awt.event.MouseEvent;
  59. import java.beans.PropertyChangeListener;
  60. import java.beans.PropertyChangeEvent;
  61. import java.beans.PropertyChangeSupport;
  62. import java.io.File;
  63. import java.io.FileWriter;
  64. import java.io.Writer;
  65. import java.io.BufferedWriter;
  66. import java.io.PrintWriter;
  67. import javax.swing.JFileChooser;
  68. import javax.swing.JPanel;
  69. import javax.swing.JLabel;
  70. import javax.swing.JButton;
  71. import javax.swing.BorderFactory;
  72. import javax.swing.JTextArea;
  73. import javax.swing.JScrollPane;
  74. import javax.swing.JRadioButton;
  75. import javax.swing.ButtonGroup;
  76. import javax.swing.JOptionPane;
  77. import javax.swing.JComboBox;
  78. import javax.swing.DefaultComboBoxModel;
  79. import javax.swing.JTextField;
  80. import javax.swing.SwingConstants;
  81. import javax.swing.JFrame;
  82. import javax.swing.event.ChangeListener;
  83. import javax.swing.event.ChangeEvent;
  84. import javax.swing.JViewport;
  85. import javax.swing.ListSelectionModel;
  86. import javax.swing.event.ListSelectionEvent;
  87. import javax.swing.event.ListSelectionListener;
  88. import java.awt.Point;
  89. import java.awt.Dimension;
  90. import javax.swing.JPopupMenu;
  91. import javax.swing.JMenu;
  92. import javax.swing.JMenuItem;
  93. /** 
  94.  * This panel allows the user to select and configure an attribute
  95.  * evaluator and a search method, set the
  96.  * attribute of the current dataset to be used as the class, and perform
  97.  * attribute selection using one of two  selection modes (select using all the
  98.  * training data or perform a n-fold cross validation---on each trial
  99.  * selecting features using n-1 folds of the data).
  100.  * The results of attribute selection runs are stored in a results history
  101.  * so that previous results are accessible.
  102.  *
  103.  * @author Mark Hall (mhall@cs.waikato.ac.nz)
  104.  * @version $Revision: 1.24 $
  105.  */
  106. public class AttributeSelectionPanel extends JPanel {
  107.   /** Lets the user configure the attribute evaluator */
  108.   protected GenericObjectEditor m_AttributeEvaluatorEditor =
  109.     new GenericObjectEditor();
  110.   /** Lets the user configure the search method */
  111.   protected GenericObjectEditor m_AttributeSearchEditor = 
  112.     new GenericObjectEditor();
  113.   /** The panel showing the current attribute evaluation method */
  114.   protected PropertyPanel m_AEEPanel = 
  115.     new PropertyPanel(m_AttributeEvaluatorEditor);
  116.   /** The panel showing the current search method */
  117.   protected PropertyPanel m_ASEPanel = 
  118.     new PropertyPanel(m_AttributeSearchEditor);
  119.   
  120.   /** The output area for attribute selection results */
  121.   protected JTextArea m_OutText = new JTextArea(20, 40);
  122.   /** The destination for log/status messages */
  123.   protected Logger m_Log = new SysErrLog();
  124.   /** The buffer saving object for saving output */
  125.   SaveBuffer m_SaveOut = new SaveBuffer(m_Log, this);
  126.   /** A panel controlling results viewing */
  127.   protected ResultHistoryPanel m_History = new ResultHistoryPanel(m_OutText);
  128.   /** Lets the user select the class column */
  129.   protected JComboBox m_ClassCombo = new JComboBox();
  130.   /** Click to set evaluation mode to cross-validation */
  131.   protected JRadioButton m_CVBut = new JRadioButton("Cross-validation");
  132.   /** Click to set test mode to test on training data */
  133.   protected JRadioButton m_TrainBut = 
  134.     new JRadioButton("Use full training set");
  135.   /** Label by where the cv folds are entered */
  136.   protected JLabel m_CVLab = new JLabel("Folds", SwingConstants.RIGHT);
  137.   /** The field where the cv folds are entered */
  138.   protected JTextField m_CVText = new JTextField("10");
  139.   /** Label by where cv random seed is entered */
  140.   protected JLabel m_SeedLab = new JLabel("Seed",SwingConstants.RIGHT);
  141.   /** The field where the seed value is entered */
  142.   protected JTextField m_SeedText = new JTextField("1");
  143.   /**
  144.    * Alters the enabled/disabled status of elements associated with each
  145.    * radio button
  146.    */
  147.   ActionListener m_RadioListener = new ActionListener() {
  148.     public void actionPerformed(ActionEvent e) {
  149.       updateRadioLinks();
  150.     }
  151.   };
  152.   /** Click to start running the attribute selector */
  153.   protected JButton m_StartBut = new JButton("Start");
  154.   /** Click to stop a running classifier */
  155.   protected JButton m_StopBut = new JButton("Stop");
  156.  /** Stop the class combo from taking up to much space */
  157.   private Dimension COMBO_SIZE = new Dimension(150, m_StartBut
  158.        .getPreferredSize().height);
  159.   /** The current visualization object */
  160.   protected VisualizePanel m_CurrentVis = null;
  161.   
  162.   /** The main set of instances we're playing with */
  163.   protected Instances m_Instances;
  164.   /** A thread that attribute selection runs in */
  165.   protected Thread m_RunThread;
  166.   /* Register the property editors we need */
  167.   static {
  168.     java.beans.PropertyEditorManager
  169.       .registerEditor(java.io.File.class,
  170.                       FileEditor.class);
  171.     java.beans.PropertyEditorManager
  172.       .registerEditor(weka.core.SelectedTag.class,
  173.       weka.gui.SelectedTagEditor.class);
  174.     java.beans.PropertyEditorManager
  175.       .registerEditor(weka.filters.Filter.class,
  176.       weka.gui.GenericObjectEditor.class);
  177.     java.beans.PropertyEditorManager
  178.       .registerEditor(weka.classifiers.Classifier [].class,
  179.       weka.gui.GenericArrayEditor.class);
  180.     java.beans.PropertyEditorManager
  181.       .registerEditor(weka.classifiers.DistributionClassifier.class,
  182.       weka.gui.GenericObjectEditor.class);
  183.     java.beans.PropertyEditorManager
  184.       .registerEditor(weka.classifiers.Classifier.class,
  185.       weka.gui.GenericObjectEditor.class);
  186.     java.beans.PropertyEditorManager
  187.       .registerEditor(weka.attributeSelection.ASEvaluation.class,
  188.       weka.gui.GenericObjectEditor.class);
  189.     java.beans.PropertyEditorManager
  190.       .registerEditor(weka.attributeSelection.ASSearch.class,
  191.       weka.gui.GenericObjectEditor.class);
  192.   }
  193.   
  194.   /**
  195.    * Creates the classifier panel
  196.    */
  197.   public AttributeSelectionPanel() {
  198.     // Connect / configure the components
  199.     m_OutText.setEditable(false);
  200.     m_OutText.setFont(new Font("Monospaced", Font.PLAIN, 12));
  201.     m_OutText.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
  202.     m_OutText.addMouseListener(new MouseAdapter() {
  203.       public void mouseClicked(MouseEvent e) {
  204. if ((e.getModifiers() & InputEvent.BUTTON1_MASK)
  205.     != InputEvent.BUTTON1_MASK) {
  206.   m_OutText.selectAll();
  207. }
  208.       }
  209.     });
  210.     m_History.setBorder(BorderFactory.createTitledBorder("Result list (right-click for options)"));
  211.     m_AttributeEvaluatorEditor.setClassType(ASEvaluation.class);
  212.     m_AttributeEvaluatorEditor.setValue(new weka.attributeSelection.
  213. CfsSubsetEval());
  214.     m_AttributeEvaluatorEditor.
  215.       addPropertyChangeListener(new PropertyChangeListener() {
  216.       public void propertyChange(PropertyChangeEvent e) {
  217. updateRadioLinks();
  218. repaint();
  219.       }
  220.     });
  221.     m_AttributeSearchEditor.setClassType(ASSearch.class);
  222.     m_AttributeSearchEditor.setValue(new weka.attributeSelection.BestFirst());
  223.     m_AttributeSearchEditor.
  224.       addPropertyChangeListener(new PropertyChangeListener() {
  225. public void propertyChange(PropertyChangeEvent e) {
  226.   repaint();
  227. }
  228.       });
  229.     m_ClassCombo.setToolTipText("Select the attribute to use as the class");
  230.     m_TrainBut.setToolTipText("select attributes using the full training "
  231.       + "dataset");
  232.     m_CVBut.setToolTipText("Perform a n-fold cross-validation");
  233.     m_StartBut.setToolTipText("Starts attribute selection");
  234.     m_StopBut.setToolTipText("Stops a attribute selection task");
  235.     
  236.     m_ClassCombo.setPreferredSize(COMBO_SIZE);
  237.     m_ClassCombo.setMaximumSize(COMBO_SIZE);
  238.     m_ClassCombo.setMinimumSize(COMBO_SIZE);
  239.     
  240.     m_ClassCombo.setEnabled(false);
  241.     m_TrainBut.setSelected(true);
  242.     updateRadioLinks();
  243.     ButtonGroup bg = new ButtonGroup();
  244.     bg.add(m_TrainBut);
  245.     bg.add(m_CVBut);
  246.     m_TrainBut.addActionListener(m_RadioListener);
  247.     m_CVBut.addActionListener(m_RadioListener);
  248.     m_StartBut.setEnabled(false);
  249.     m_StopBut.setEnabled(false);
  250.     m_StartBut.addActionListener(new ActionListener() {
  251.       public void actionPerformed(ActionEvent e) {
  252. startAttributeSelection();
  253.       }
  254.     });
  255.     m_StopBut.addActionListener(new ActionListener() {
  256.       public void actionPerformed(ActionEvent e) {
  257. stopAttributeSelection();
  258.       }
  259.     });
  260.     
  261.     m_History.setHandleRightClicks(false);
  262.     // see if we can popup a menu for the selected result
  263.     m_History.getList().addMouseListener(new MouseAdapter() {
  264. public void mouseClicked(MouseEvent e) {
  265.   if ((e.getModifiers() & InputEvent.BUTTON1_MASK)
  266.       == InputEvent.BUTTON1_MASK) {
  267.   } else {
  268.     int index = m_History.getList().locationToIndex(e.getPoint());
  269.     if (index != -1) {
  270.       String name = m_History.getNameAtIndex(index);
  271.       visualize(name, e.getX(), e.getY());
  272.     } else {
  273.       visualize(null, e.getX(), e.getY());
  274.     }
  275.   }
  276. }
  277.       });
  278.     // Layout the GUI
  279.     JPanel p1 = new JPanel();
  280.     p1.setBorder(BorderFactory.createCompoundBorder(
  281.  BorderFactory.createTitledBorder("Attribute Evaluator"),
  282.  BorderFactory.createEmptyBorder(0, 5, 5, 5)
  283.  ));
  284.     p1.setLayout(new BorderLayout());
  285.     p1.add(m_AEEPanel, BorderLayout.NORTH);
  286.     JPanel p1_1 = new JPanel();
  287.     p1_1.setBorder(BorderFactory.createCompoundBorder(
  288.  BorderFactory.createTitledBorder("Search Method"),
  289.  BorderFactory.createEmptyBorder(0, 5, 5, 5)
  290.  ));
  291.     p1_1.setLayout(new BorderLayout());
  292.     p1_1.add(m_ASEPanel, BorderLayout.NORTH);
  293.     JPanel p_new = new JPanel();
  294.     p_new.setLayout(new BorderLayout());
  295.     p_new.add(p1, BorderLayout.NORTH);
  296.     p_new.add(p1_1, BorderLayout.CENTER);
  297.     JPanel p2 = new JPanel();
  298.     GridBagLayout gbL = new GridBagLayout();
  299.     p2.setLayout(gbL);
  300.     p2.setBorder(BorderFactory.createCompoundBorder(
  301.  BorderFactory.createTitledBorder("Attribute Selection Mode"),
  302.  BorderFactory.createEmptyBorder(0, 5, 5, 5)
  303.  ));
  304.     GridBagConstraints gbC = new GridBagConstraints();
  305.     gbC.anchor = GridBagConstraints.WEST;
  306.     gbC.gridy = 2;     gbC.gridx = 0;
  307.     gbL.setConstraints(m_TrainBut, gbC);
  308.     p2.add(m_TrainBut);
  309.     gbC = new GridBagConstraints();
  310.     gbC.anchor = GridBagConstraints.WEST;
  311.     gbC.gridy = 4;     gbC.gridx = 0;
  312.     gbL.setConstraints(m_CVBut, gbC);
  313.     p2.add(m_CVBut);
  314.     gbC = new GridBagConstraints();
  315.     gbC.anchor = GridBagConstraints.EAST;
  316.     gbC.fill = GridBagConstraints.HORIZONTAL;
  317.     gbC.gridy = 4;     gbC.gridx = 1;
  318.     gbC.insets = new Insets(2, 10, 2, 10);
  319.     gbL.setConstraints(m_CVLab, gbC);
  320.     p2.add(m_CVLab);
  321.     gbC = new GridBagConstraints();
  322.     gbC.anchor = GridBagConstraints.EAST;
  323.     gbC.fill = GridBagConstraints.HORIZONTAL;
  324.     gbC.gridy = 4;     gbC.gridx = 2;  gbC.weightx = 100;
  325.     gbC.ipadx = 20;
  326.     gbL.setConstraints(m_CVText, gbC);
  327.     p2.add(m_CVText);
  328.     gbC = new GridBagConstraints();
  329.     gbC.anchor = GridBagConstraints.EAST;
  330.     gbC.fill = GridBagConstraints.HORIZONTAL;
  331.     gbC.gridy = 6;     gbC.gridx = 1;
  332.     gbC.insets = new Insets(2, 10, 2, 10);
  333.     gbL.setConstraints(m_SeedLab, gbC);
  334.     p2.add(m_SeedLab);
  335.     gbC = new GridBagConstraints();
  336.     gbC.anchor = GridBagConstraints.EAST;
  337.     gbC.fill = GridBagConstraints.HORIZONTAL;
  338.     gbC.gridy = 6;     gbC.gridx = 2;  gbC.weightx = 100;
  339.     gbC.ipadx = 20;
  340.     gbL.setConstraints(m_SeedText, gbC);
  341.     p2.add(m_SeedText);
  342.     JPanel buttons = new JPanel();
  343.     buttons.setLayout(new GridLayout(2, 2));
  344.     buttons.add(m_ClassCombo);
  345.     m_ClassCombo.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
  346.     JPanel ssButs = new JPanel();
  347.     ssButs.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
  348.     ssButs.setLayout(new GridLayout(1, 2, 5, 5));
  349.     ssButs.add(m_StartBut);
  350.     ssButs.add(m_StopBut);
  351.     buttons.add(ssButs);
  352.     
  353.     JPanel p3 = new JPanel();
  354.     p3.setBorder(BorderFactory.
  355.  createTitledBorder("Attribute selection output"));
  356.     p3.setLayout(new BorderLayout());
  357.     final JScrollPane js = new JScrollPane(m_OutText);
  358.     p3.add(js, BorderLayout.CENTER);
  359.     js.getViewport().addChangeListener(new ChangeListener() {
  360.       private int lastHeight;
  361.       public void stateChanged(ChangeEvent e) {
  362. JViewport vp = (JViewport)e.getSource();
  363. int h = vp.getViewSize().height; 
  364. if (h != lastHeight) { // i.e. an addition not just a user scrolling
  365.   lastHeight = h;
  366.   int x = h - vp.getExtentSize().height;
  367.   vp.setViewPosition(new Point(0, x));
  368. }
  369.       }
  370.     });
  371.     JPanel mondo = new JPanel();
  372.     gbL = new GridBagLayout();
  373.     mondo.setLayout(gbL);
  374.     gbC = new GridBagConstraints();
  375.     gbC.fill = GridBagConstraints.HORIZONTAL;
  376.     gbC.gridy = 0;     gbC.gridx = 0; gbC.weightx = 0;
  377.     gbL.setConstraints(p2, gbC);
  378.     mondo.add(p2);
  379.     gbC = new GridBagConstraints();
  380.     gbC.anchor = GridBagConstraints.NORTH;
  381.     gbC.fill = GridBagConstraints.HORIZONTAL;
  382.     gbC.gridy = 1;     gbC.gridx = 0; gbC.weightx = 0;
  383.     gbL.setConstraints(buttons, gbC);
  384.     mondo.add(buttons);
  385.     gbC = new GridBagConstraints();
  386.     gbC.fill = GridBagConstraints.BOTH;
  387.     gbC.gridy = 2;     gbC.gridx = 0; gbC.weightx = 0; gbC.weighty = 100;
  388.     gbL.setConstraints(m_History, gbC);
  389.     mondo.add(m_History);
  390.     gbC = new GridBagConstraints();
  391.     gbC.fill = GridBagConstraints.BOTH;
  392.     gbC.gridy = 0;     gbC.gridx = 1;
  393.     gbC.gridheight = 3;
  394.     gbC.weightx = 100; gbC.weighty = 100;
  395.     gbL.setConstraints(p3, gbC);
  396.     mondo.add(p3);
  397.     setLayout(new BorderLayout());
  398.     add(p_new, BorderLayout.NORTH);
  399.     add(mondo, BorderLayout.CENTER);
  400.   }
  401.   
  402.   /**
  403.    * Updates the enabled status of the input fields and labels.
  404.    */
  405.   protected void updateRadioLinks() {
  406.     m_CVBut.setEnabled(true);
  407.     m_CVText.setEnabled(m_CVBut.isSelected());
  408.     m_CVLab.setEnabled(m_CVBut.isSelected());
  409.     m_SeedText.setEnabled(m_CVBut.isSelected());
  410.     m_SeedLab.setEnabled(m_CVBut.isSelected());
  411.     
  412.     if (m_AttributeEvaluatorEditor.getValue() 
  413. instanceof AttributeTransformer) {
  414.       m_CVBut.setSelected(false);
  415.       m_CVBut.setEnabled(false);
  416.       m_CVText.setEnabled(false);
  417.       m_CVLab.setEnabled(false);
  418.       m_SeedText.setEnabled(false);
  419.       m_SeedLab.setEnabled(false);
  420.       m_TrainBut.setSelected(true);
  421.     }
  422.   }
  423.   
  424.   /**
  425.    * Sets the Logger to receive informational messages
  426.    *
  427.    * @param newLog the Logger that will now get info messages
  428.    */
  429.   public void setLog(Logger newLog) {
  430.     m_Log = newLog;
  431.   }
  432.   
  433.   /**
  434.    * Tells the panel to use a new set of instances.
  435.    *
  436.    * @param inst a set of Instances
  437.    */
  438.   public void setInstances(Instances inst) {
  439.     
  440.     m_Instances = inst;
  441.     String [] attribNames = new String [m_Instances.numAttributes()];
  442.     for (int i = 0; i < attribNames.length; i++) {
  443.       String type = "";
  444.       switch (m_Instances.attribute(i).type()) {
  445.       case Attribute.NOMINAL:
  446. type = "(Nom) ";
  447. break;
  448.       case Attribute.NUMERIC:
  449. type = "(Num) ";
  450. break;
  451.       case Attribute.STRING:
  452. type = "(Str) ";
  453. break;
  454.       default:
  455. type = "(???) ";
  456.       }
  457.       String attnm = m_Instances.attribute(i).name();
  458.      
  459.       attribNames[i] = type + attnm;
  460.     }
  461.     m_StartBut.setEnabled(m_RunThread == null);
  462.     m_StopBut.setEnabled(m_RunThread != null);
  463.     m_ClassCombo.setModel(new DefaultComboBoxModel(attribNames));
  464.     m_ClassCombo.setSelectedIndex(attribNames.length - 1);
  465.     m_ClassCombo.setEnabled(true);
  466.   }
  467.   
  468.   /**
  469.    * Starts running the currently configured attribute evaluator and
  470.    * search method. This is run in a separate thread, and will only start if
  471.    * there is no attribute selection  already running. The attribute selection
  472.    * output is sent to the results history panel.
  473.    */
  474.   protected void startAttributeSelection() {
  475.     if (m_RunThread == null) {
  476.       m_StartBut.setEnabled(false);
  477.       m_StopBut.setEnabled(true);
  478.       m_RunThread = new Thread() {
  479. public void run() {
  480.   // Copy the current state of things
  481.   m_Log.statusMessage("Setting up...");
  482.   Instances inst = new Instances(m_Instances);
  483.   int testMode = 0;
  484.   int numFolds = 10;
  485.   int seed = 1;
  486.   int classIndex = m_ClassCombo.getSelectedIndex();
  487.   ASEvaluation evaluator = 
  488.      (ASEvaluation) m_AttributeEvaluatorEditor.getValue();
  489.   ASSearch search = (ASSearch) m_AttributeSearchEditor.getValue();
  490.   StringBuffer outBuff = new StringBuffer();
  491.   String name = (new SimpleDateFormat("HH:mm:ss - "))
  492.   .format(new Date());
  493.   String sname = search.getClass().getName();
  494.   if (sname.startsWith("weka.attributeSelection.")) {
  495.     name += sname.substring("weka.attributeSelection.".length());
  496.   } else {
  497.     name += sname;
  498.   }
  499.   String ename = evaluator.getClass().getName();
  500.   if (ename.startsWith("weka.attributeSelection.")) {
  501.     name += (" + "
  502.      +ename.substring("weka.attributeSelection.".length()));
  503.   } else {
  504.     name += (" + "+ename);
  505.   }
  506.   try {
  507.     if (m_CVBut.isSelected()) {
  508.       testMode = 1;
  509.       numFolds = Integer.parseInt(m_CVText.getText());
  510.       seed = Integer.parseInt(m_SeedText.getText());
  511.       if (numFolds <= 1) {
  512. throw new Exception("Number of folds must be greater than 1");
  513.       }
  514.     } 
  515.     inst.setClassIndex(classIndex);
  516.     // Output some header information
  517.     m_Log.logMessage("Started " + ename);
  518.     if (m_Log instanceof TaskLogger) {
  519.       ((TaskLogger)m_Log).taskStarted();
  520.     }
  521.     outBuff.append("=== Run information ===nn");
  522.     outBuff.append("Evaluator:    " + ename);
  523.     if (evaluator instanceof OptionHandler) {
  524.       String [] o = ((OptionHandler) evaluator).getOptions();
  525.       outBuff.append(" " + Utils.joinOptions(o));
  526.     }
  527.     outBuff.append("nSearch:       " + sname);
  528.     if (search instanceof OptionHandler) {
  529.       String [] o = ((OptionHandler) search).getOptions();
  530.       outBuff.append(" " + Utils.joinOptions(o));
  531.     }
  532.     outBuff.append("n");
  533.     outBuff.append("Relation:     " + inst.relationName() + 'n');
  534.     outBuff.append("Instances:    " + inst.numInstances() + 'n');
  535.     outBuff.append("Attributes:   " + inst.numAttributes() + 'n');
  536.     if (inst.numAttributes() < 100) {
  537.       for (int i = 0; i < inst.numAttributes(); i++) {
  538. outBuff.append("              " + inst.attribute(i).name()
  539.        + 'n');
  540.       }
  541.     } else {
  542.       outBuff.append("              [list of attributes omitted]n");
  543.     }
  544.     outBuff.append("Evaluation mode:    ");
  545.     switch (testMode) {
  546.       case 0: // select using all training
  547.       outBuff.append("evaluate on all training datan");
  548.       break;
  549.       case 1: // CV mode
  550.       outBuff.append("" + numFolds + "-fold cross-validationn");
  551.       break;
  552.     }
  553.     outBuff.append("n");
  554.     m_History.addResult(name, outBuff);
  555.     m_History.setSingle(name);
  556.     
  557.     // Do the feature selection and output the results.
  558.     m_Log.statusMessage("Doing feature selection...");
  559.     m_History.updateResult(name);
  560.     
  561.     AttributeSelection eval = new AttributeSelection();
  562.     eval.setEvaluator(evaluator);
  563.     eval.setSearch(search);
  564.     eval.setFolds(numFolds);
  565.     eval.setSeed(seed);
  566.     if (testMode == 1) {
  567.       eval.setXval(true);
  568.     }
  569.          
  570.     switch (testMode) {
  571.       case 0: // select using training
  572.       m_Log.statusMessage("Evaluating on training data...");
  573.       eval.SelectAttributes(inst);
  574.       break;
  575.       case 1: // CV mode
  576.       m_Log.statusMessage("Randomizing instances...");
  577.       inst.randomize(new Random(seed));
  578.       if (inst.attribute(classIndex).isNominal()) {
  579. m_Log.statusMessage("Stratifying instances...");
  580. inst.stratify(numFolds);
  581.       }
  582.       for (int fold = 0; fold < numFolds;fold++) {
  583. m_Log.statusMessage("Creating splits for fold "
  584.     + (fold + 1) + "...");
  585. Instances train = inst.trainCV(numFolds, fold);
  586. m_Log.statusMessage("Selecting attributes using all but fold "
  587.     + (fold + 1) + "...");
  588. eval.selectAttributesCVSplit(train);
  589.       }
  590.       break;
  591.       default:
  592.       throw new Exception("Test mode not implemented");
  593.     }
  594.     if (testMode == 0) {
  595.       outBuff.append(eval.toResultsString());
  596.     } else {
  597.       outBuff.append(eval.CVResultsString());
  598.     }
  599.   
  600.     outBuff.append("n");
  601.     m_History.updateResult(name);
  602.     m_Log.logMessage("Finished " + ename+" "+sname);
  603.     m_Log.statusMessage("OK");
  604.   } catch (Exception ex) {
  605.     m_Log.logMessage(ex.getMessage());
  606.     m_Log.statusMessage("See error log");
  607.   } finally {
  608.     if (evaluator instanceof AttributeTransformer) {
  609.       m_CurrentVis = new VisualizePanel();
  610.       try {
  611. Instances transformed = 
  612.   ((AttributeTransformer)evaluator).transformedData();
  613. PlotData2D tempd = new PlotData2D(transformed);
  614. tempd.setPlotName(name+" ("+transformed.relationName()+")");
  615. tempd.addInstanceNumberAttribute();
  616. m_CurrentVis.setLog(m_Log);
  617. try {
  618.   m_CurrentVis.addPlot(tempd);
  619.   m_CurrentVis.setColourIndex(transformed.classIndex()+1);
  620. } catch (Exception ex) {
  621.   ex.printStackTrace();
  622. }
  623. m_CurrentVis.setName(name+" ("+transformed.relationName()+")");
  624. FastVector vv = new FastVector();
  625. vv.addElement(m_CurrentVis);
  626. m_History.addObject(name, vv);
  627.       } catch (Exception ex) {
  628. System.err.println(ex);
  629. ex.printStackTrace();
  630.       }
  631.     }
  632.     if (isInterrupted()) {
  633.       m_Log.logMessage("Interrupted " + ename+" "+sname);
  634.       m_Log.statusMessage("See error log");
  635.     }
  636.     m_RunThread = null;
  637.     m_StartBut.setEnabled(true);
  638.     m_StopBut.setEnabled(false);
  639.     if (m_Log instanceof TaskLogger) {
  640.       ((TaskLogger)m_Log).taskFinished();
  641.     }
  642.   }
  643. }
  644.       };
  645.       m_RunThread.setPriority(Thread.MIN_PRIORITY);
  646.       m_RunThread.start();
  647.     }
  648.   }
  649.   
  650.   /**
  651.    * Stops the currently running attribute selection (if any).
  652.    */
  653.   protected void stopAttributeSelection() {
  654.     if (m_RunThread != null) {
  655.       m_RunThread.interrupt();
  656.       
  657.       // This is deprecated (and theoretically the interrupt should do).
  658.       m_RunThread.stop();
  659.       
  660.     }
  661.   }
  662.   
  663.   /**
  664.    * Save the named buffer to a file.
  665.    * @param name the name of the buffer to be saved.
  666.    */
  667.   protected void saveBuffer(String name) {
  668.     StringBuffer sb = m_History.getNamedBuffer(name);
  669.     if (sb != null) {
  670.       if (m_SaveOut.save(sb)) {
  671. m_Log.logMessage("Save succesful.");
  672.       }
  673.     }
  674.   }
  675.   /**
  676.    * Popup a visualize panel for viewing transformed data
  677.    * @param sp the VisualizePanel to display
  678.    */
  679.   protected void visualizeTransformedData(VisualizePanel sp) {
  680.     if (sp != null) {
  681.       String plotName = sp.getName();
  682.       final javax.swing.JFrame jf = 
  683. new javax.swing.JFrame("Weka Attribute Selection Visualize: "
  684.        +plotName);
  685.       jf.setSize(500,400);
  686.       jf.getContentPane().setLayout(new BorderLayout());
  687.       jf.getContentPane().add(sp, BorderLayout.CENTER);
  688.       jf.addWindowListener(new java.awt.event.WindowAdapter() {
  689.   public void windowClosing(java.awt.event.WindowEvent e) {
  690.     jf.dispose();
  691.   }
  692. });
  693.       jf.setVisible(true);
  694.     }
  695.   }
  696.   /**
  697.    * Handles constructing a popup menu with visualization options
  698.    * @param name the name of the result history list entry clicked on by
  699.    * the user.
  700.    * @param x the x coordinate for popping up the menu
  701.    * @param y the y coordinate for popping up the menu
  702.    */
  703.   protected void visualize(String name, int x, int y) {
  704.     final String selectedName = name;
  705.     JPopupMenu resultListMenu = new JPopupMenu();
  706.     JMenuItem visMainBuffer = new JMenuItem("View in main window");
  707.     if (selectedName != null) {
  708.       visMainBuffer.addActionListener(new ActionListener() {
  709.   public void actionPerformed(ActionEvent e) {
  710.     m_History.setSingle(selectedName);
  711.   }
  712. });
  713.     } else {
  714.       visMainBuffer.setEnabled(false);
  715.     }
  716.     resultListMenu.add(visMainBuffer);
  717.     JMenuItem visSepBuffer = new JMenuItem("View in separate window");
  718.     if (selectedName != null) {
  719.     visSepBuffer.addActionListener(new ActionListener() {
  720. public void actionPerformed(ActionEvent e) {
  721.   m_History.openFrame(selectedName);
  722. }
  723.       });
  724.     } else {
  725.       visSepBuffer.setEnabled(false);
  726.     }
  727.     resultListMenu.add(visSepBuffer);
  728.     JMenuItem saveOutput = new JMenuItem("Save result buffer");
  729.     if (selectedName != null) {
  730.     saveOutput.addActionListener(new ActionListener() {
  731. public void actionPerformed(ActionEvent e) {
  732.   saveBuffer(selectedName);
  733. }
  734.       });
  735.     } else {
  736.       saveOutput.setEnabled(false);
  737.     }
  738.     resultListMenu.add(saveOutput);
  739.     
  740.     resultListMenu.addSeparator();
  741.     FastVector o = null;
  742.     if (selectedName != null) {
  743.       o = (FastVector)m_History.getNamedObject(selectedName);
  744.     }    
  745.     VisualizePanel temp_vp = null;
  746.      
  747.     if (o != null) {
  748.       for (int i = 0; i < o.size(); i++) {
  749. Object temp = o.elementAt(i);
  750. if (temp instanceof VisualizePanel) {
  751.   temp_vp = (VisualizePanel)temp;
  752.       }
  753.     }
  754.     
  755.     final VisualizePanel vp = temp_vp;
  756.     
  757.     JMenuItem visTrans = new JMenuItem("Visualize transformed data");
  758.     if (vp != null) {
  759.       visTrans.addActionListener(new ActionListener() {
  760.   public void actionPerformed(ActionEvent e) {
  761.     visualizeTransformedData(vp);
  762.   }
  763. });
  764.     } else {
  765.       visTrans.setEnabled(false);
  766.     }
  767.     resultListMenu.add(visTrans);
  768.     
  769.     resultListMenu.show(m_History.getList(), x, y);
  770.   }
  771.   /**
  772.    * Tests out the attribute selection panel from the command line.
  773.    *
  774.    * @param args may optionally contain the name of a dataset to load.
  775.    */
  776.   public static void main(String [] args) {
  777.     try {
  778.       final javax.swing.JFrame jf =
  779. new javax.swing.JFrame("Weka Knowledge Explorer: Select attributes");
  780.       jf.getContentPane().setLayout(new BorderLayout());
  781.       final AttributeSelectionPanel sp = new AttributeSelectionPanel();
  782.       jf.getContentPane().add(sp, BorderLayout.CENTER);
  783.       weka.gui.LogPanel lp = new weka.gui.LogPanel();
  784.       sp.setLog(lp);
  785.       jf.getContentPane().add(lp, BorderLayout.SOUTH);
  786.       jf.addWindowListener(new java.awt.event.WindowAdapter() {
  787. public void windowClosing(java.awt.event.WindowEvent e) {
  788.   jf.dispose();
  789.   System.exit(0);
  790. }
  791.       });
  792.       jf.pack();
  793.       jf.setVisible(true);
  794.       if (args.length == 1) {
  795. System.err.println("Loading instances from " + args[0]);
  796. java.io.Reader r = new java.io.BufferedReader(
  797.    new java.io.FileReader(args[0]));
  798. Instances i = new Instances(r);
  799. sp.setInstances(i);
  800.       }
  801.     } catch (Exception ex) {
  802.       ex.printStackTrace();
  803.       System.err.println(ex.getMessage());
  804.     }
  805.   }
  806. }