/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
* ResultsPanel.java
* Copyright (C) 1999 Len Trigg
* Modified by Prem Melville
*
*/
package weka.gui.experiment;
import java.util.*;
import weka.gui.ExtensionFileFilter;
import weka.gui.ListSelectorDialog;
import weka.gui.ResultHistoryPanel;
import weka.gui.SaveBuffer;
import weka.experiment.Experiment;
import weka.experiment.InstancesResultListener;
import weka.experiment.DatabaseResultListener;
import weka.experiment.PairedTTester;
import weka.experiment.InstanceQuery;
import weka.core.Utils;
import weka.core.Attribute;
import weka.core.Instances;
import weka.core.Range;
import weka.core.Instance;
//=============== BEGIN EDIT mbilenko ===============
import java.io.PrintWriter;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
//=============== END EDIT mbilenko ===============
import java.io.Reader;
import java.io.FileReader;
import java.io.BufferedReader;
import java.io.File;
import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.Font;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JPanel;
import javax.swing.JLabel;
import javax.swing.JFrame;
import javax.swing.JButton;
import javax.swing.JTextArea;
import javax.swing.BorderFactory;
import javax.swing.JScrollPane;
import javax.swing.SwingConstants;
import javax.swing.filechooser.FileFilter;
import javax.swing.JFileChooser;
import javax.swing.JComboBox;
import javax.swing.JTextField;
import javax.swing.DefaultComboBoxModel;
import javax.swing.DefaultListModel;
import javax.swing.JList;
import javax.swing.ListSelectionModel;
import javax.swing.JOptionPane;
import javax.swing.JCheckBox;
import java.awt.GridBagLayout;
import java.awt.GridBagConstraints;
import java.awt.Insets;
import java.util.Date;
import java.text.SimpleDateFormat;
import java.awt.Dimension;
import javax.swing.SwingUtilities;
/**
* This panel controls simple analysis of experimental results.
*
* @author Len Trigg (trigg@cs.waikato.ac.nz)
* @version $Revision: 1.12 $
*/
public class ResultsPanel extends JPanel {
/** Message shown when no experimental results have been loaded */
protected static final String NO_SOURCE = "No source";
/** Click to load results from a file */
protected JButton m_FromFileBut = new JButton("File...");
/** Click to load results from a database */
protected JButton m_FromDBaseBut = new JButton("Database...");
/** Click to get results from the destination given in the experiment */
protected JButton m_FromExpBut = new JButton("Experiment");
/** Displays a message about the current result set */
protected JLabel m_FromLab = new JLabel(NO_SOURCE);
/**
* This is needed to get around a bug in Swing <= 1.1 -- Once everyone
* is using Swing 1.1.1 or higher just remove this variable and use the
* no-arg constructor to DefaultComboBoxModel
*/
private static String [] FOR_JFC_1_1_DCBM_BUG = {""};
/** The model embedded in m_DatasetCombo */
protected DefaultComboBoxModel m_DatasetModel =
new DefaultComboBoxModel(FOR_JFC_1_1_DCBM_BUG);
/** The model embedded in m_RunCombo */
protected DefaultComboBoxModel m_RunModel =
new DefaultComboBoxModel(FOR_JFC_1_1_DCBM_BUG);
/** The model embedded in m_CompareCombo */
protected DefaultComboBoxModel m_CompareModel =
new DefaultComboBoxModel(FOR_JFC_1_1_DCBM_BUG);
/** The model embedded in m_TestsList */
protected DefaultListModel m_TestsModel = new DefaultListModel();
/** Displays the currently selected column names for the scheme & options */
protected JLabel m_DatasetKeyLabel = new JLabel("Row key fields",
SwingConstants.RIGHT);
/** Click to edit the columns used to determine the scheme */
protected JButton m_DatasetKeyBut = new JButton("Select keys...");
/** Stores the list of attributes for selecting the scheme columns */
protected DefaultListModel m_DatasetKeyModel = new DefaultListModel();
/** Displays the list of selected columns determining the scheme */
protected JList m_DatasetKeyList = new JList(m_DatasetKeyModel);
/** Lets the user select which column contains the run number */
protected JComboBox m_RunCombo = new JComboBox(m_RunModel);
/** Displays the currently selected column names for the scheme & options */
protected JLabel m_ResultKeyLabel = new JLabel("Column key fields",
SwingConstants.RIGHT);
/** Click to edit the columns used to determine the scheme */
protected JButton m_ResultKeyBut = new JButton("Select keys...");
/** Stores the list of attributes for selecting the scheme columns */
protected DefaultListModel m_ResultKeyModel = new DefaultListModel();
/** Displays the list of selected columns determining the scheme */
protected JList m_ResultKeyList = new JList(m_ResultKeyModel);
/** Lets the user select which scheme to base comparisons against */
protected JButton m_TestsButton = new JButton("Select base...");
/** Holds the list of schemes to base the test against */
protected JList m_TestsList = new JList(m_TestsModel);
/** Lets the user select which performance measure to analyze */
protected JComboBox m_CompareCombo = new JComboBox(m_CompareModel);
/** Lets the user edit the test significance */
protected JTextField m_SigTex = new JTextField("0.05");
/** Lets the user select whether standard deviations are to be output
or not */
protected JCheckBox m_ShowStdDevs =
new JCheckBox("");
/** Click to start the test */
protected JButton m_PerformBut = new JButton("Perform test");
/** Click to save test output to a file */
protected JButton m_SaveOutBut = new JButton("Save output");
//=============== BEGIN EDIT mbilenko ===============
/** Click to launch gnuplot */
protected JButton m_PlotBut = new JButton("Plot");
//=============== END EDIT mbilenko ===============
//=============== BEGIN EDIT melville ===============
/** Lets the user specify the precision of results desired */
protected JTextField m_PrecTex = new JTextField("2");
//To remember index of error for computing error reductions
protected int m_ErrorCompareCol;
//=============== END EDIT melville ===============
/** The buffer saving object for saving output */
SaveBuffer m_SaveOut = new SaveBuffer(null, this);
/** Displays the output of tests */
protected JTextArea m_OutText = new JTextArea();
/** A panel controlling results viewing */
protected ResultHistoryPanel m_History = new ResultHistoryPanel(m_OutText);
/** Filter to ensure only arff files are selected for result files */
protected FileFilter m_ArffFilter =
new ExtensionFileFilter(Instances.FILE_EXTENSION, "Arff data files");
/** The file chooser for selecting result files */
protected JFileChooser m_FileChooser = new JFileChooser(new File(System.getProperty("user.dir")));
/** The PairedTTester object */
protected PairedTTester m_TTester = new PairedTTester();
/** The instances we're extracting results from */
protected Instances m_Instances;
/** Does any database querying for us */
protected InstanceQuery m_InstanceQuery;
/** A thread to load results instances from a file or database */
protected Thread m_LoadThread;
/** An experiment (used for identifying a result source) -- optional */
protected Experiment m_Exp;
/** An actionlisteners that updates ttest settings */
protected ActionListener m_ConfigureListener = new ActionListener() {
public void actionPerformed(ActionEvent e) {
m_TTester.setRunColumn(m_RunCombo.getSelectedIndex());
setTTester();
}
};
private Dimension COMBO_SIZE = new Dimension(150, m_ResultKeyBut
.getPreferredSize().height);
/**
* Creates the results panel with no initial experiment.
*/
public ResultsPanel() {
// Create/Configure/Connect components
m_FileChooser.setFileFilter(m_ArffFilter);
m_FileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
m_FromExpBut.setEnabled(false);
m_FromExpBut.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (m_LoadThread == null) {
m_LoadThread = new Thread() {
public void run() {
setInstancesFromExp(m_Exp);
m_LoadThread = null;
}
};
m_LoadThread.start();
}
}
});
m_FromDBaseBut.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (m_LoadThread == null) {
m_LoadThread = new Thread() {
public void run() {
setInstancesFromDBaseQuery();
m_LoadThread = null;
}
};
m_LoadThread.start();
}
}
});
m_FromFileBut.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
int returnVal = m_FileChooser.showOpenDialog(ResultsPanel.this);
if (returnVal == JFileChooser.APPROVE_OPTION) {
final File selected = m_FileChooser.getSelectedFile();
if (m_LoadThread == null) {
m_LoadThread = new Thread() {
public void run() {
setInstancesFromFile(selected);
m_LoadThread = null;
}
};
m_LoadThread.start();
}
}
}
});
setComboSizes();
m_DatasetKeyBut.setEnabled(false);
m_DatasetKeyBut.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
setDatasetKeyFromDialog();
}
});
m_DatasetKeyList.setSelectionMode(ListSelectionModel
.MULTIPLE_INTERVAL_SELECTION);
m_RunCombo.setEnabled(false);
m_RunCombo.addActionListener(m_ConfigureListener);
m_ResultKeyBut.setEnabled(false);
m_ResultKeyBut.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
setResultKeyFromDialog();
}
});
m_ResultKeyList.setSelectionMode(ListSelectionModel
.MULTIPLE_INTERVAL_SELECTION);
m_CompareCombo.setEnabled(false);
m_SigTex.setEnabled(false);
m_PrecTex.setEnabled(false);
//=============== BEGIN EDIT melville ===============
m_TestsButton.setEnabled(false);
//=============== END EDIT melville ===============
m_TestsButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
setTestBaseFromDialog();
}
});
m_PerformBut.setEnabled(false);
m_PerformBut.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
performTest();
m_SaveOutBut.setEnabled(true);
//=============== BEGIN EDIT mbilenko ===============
m_PlotBut.setEnabled(true);
//=============== END EDIT mbilenko ===============
}
});
m_SaveOutBut.setEnabled(false);
m_SaveOutBut.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
saveBuffer();
}
});
//=============== BEGIN EDIT mbilenko ===============
m_PlotBut.setEnabled(false);
m_PlotBut.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
plotOutput();
}
});
//=============== END EDIT mbilenko ===============
m_OutText.setFont(new Font("Monospaced", Font.PLAIN, 12));
m_OutText.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
m_OutText.setEditable(false);
m_History.setBorder(BorderFactory.createTitledBorder("Result list"));
// Set up the GUI layout
JPanel p1 = new JPanel();
p1.setBorder(BorderFactory.createTitledBorder("Source"));
JPanel p2 = new JPanel();
GridBagLayout gb = new GridBagLayout();
GridBagConstraints constraints = new GridBagConstraints();
p2.setBorder(BorderFactory.createEmptyBorder(5, 5, 10, 5));
// p2.setLayout(new GridLayout(1, 3));
p2.setLayout(gb);
constraints.gridx=0;constraints.gridy=0;constraints.weightx=5;
constraints.fill = GridBagConstraints.HORIZONTAL;
constraints.gridwidth=1;constraints.gridheight=1;
constraints.insets = new Insets(0,2,0,2);
p2.add(m_FromFileBut,constraints);
constraints.gridx=1;constraints.gridy=0;constraints.weightx=5;
constraints.gridwidth=1;constraints.gridheight=1;
p2.add(m_FromDBaseBut,constraints);
constraints.gridx=2;constraints.gridy=0;constraints.weightx=5;
constraints.gridwidth=1;constraints.gridheight=1;
p2.add(m_FromExpBut,constraints);
p1.setLayout(new BorderLayout());
p1.add(m_FromLab, BorderLayout.CENTER);
p1.add(p2, BorderLayout.EAST);
JPanel p3 = new JPanel();
p3.setBorder(BorderFactory.createTitledBorder("Configure test"));
GridBagLayout gbL = new GridBagLayout();
p3.setLayout(gbL);
GridBagConstraints gbC = new GridBagConstraints();
gbC.anchor = GridBagConstraints.EAST;
gbC.gridy = 0; gbC.gridx = 0;
gbC.insets = new Insets(2, 10, 2, 10);
gbL.setConstraints(m_DatasetKeyLabel,gbC);
p3.add(m_DatasetKeyLabel);
gbC = new GridBagConstraints();
gbC.gridy = 0; gbC.gridx = 1; gbC.weightx = 100;
gbC.insets = new Insets(5,0,5,0);
gbL.setConstraints(m_DatasetKeyBut, gbC);
p3.add(m_DatasetKeyBut);
JLabel lab = new JLabel("Run field", SwingConstants.RIGHT);
gbC = new GridBagConstraints();
gbC.anchor = GridBagConstraints.EAST;
gbC.gridy = 1; gbC.gridx = 0;
gbC.insets = new Insets(2, 10, 2, 10);
gbL.setConstraints(lab, gbC);
p3.add(lab);
gbC = new GridBagConstraints();
gbC.gridy = 1; gbC.gridx = 1; gbC.weightx = 100;
gbC.insets = new Insets(5,0,5,0);
gbL.setConstraints(m_RunCombo, gbC);
p3.add(m_RunCombo);
gbC = new GridBagConstraints();
gbC.anchor = GridBagConstraints.EAST;
gbC.gridy = 2; gbC.gridx = 0;
gbC.insets = new Insets(2, 10, 2, 10);
gbL.setConstraints(m_ResultKeyLabel, gbC);
p3.add(m_ResultKeyLabel);
gbC = new GridBagConstraints();
gbC.gridy = 2; gbC.gridx = 1; gbC.weightx = 100;
gbC.insets = new Insets(5,0,5,0);
gbL.setConstraints(m_ResultKeyBut, gbC);
p3.add(m_ResultKeyBut);
lab = new JLabel("Comparison field", SwingConstants.RIGHT);
gbC = new GridBagConstraints();
gbC.anchor = GridBagConstraints.EAST;
gbC.gridy = 3; gbC.gridx = 0;
gbC.insets = new Insets(2, 10, 2, 10);
gbL.setConstraints(lab, gbC);
p3.add(lab);
gbC = new GridBagConstraints();
gbC.gridy = 3; gbC.gridx = 1; gbC.weightx = 100;
gbC.insets = new Insets(5,0,5,0);
gbL.setConstraints(m_CompareCombo, gbC);
p3.add(m_CompareCombo);
lab = new JLabel("Significance", SwingConstants.RIGHT);
gbC = new GridBagConstraints();
gbC.anchor = GridBagConstraints.EAST;
gbC.gridy = 4; gbC.gridx = 0;
gbC.insets = new Insets(2, 10, 2, 10);
gbL.setConstraints(lab, gbC);
p3.add(lab);
gbC = new GridBagConstraints();
gbC.gridy = 4; gbC.gridx = 1; gbC.weightx = 100;
gbL.setConstraints(m_SigTex, gbC);
p3.add(m_SigTex);
lab = new JLabel("Test base", SwingConstants.RIGHT);
gbC = new GridBagConstraints();
gbC.anchor = GridBagConstraints.EAST;
gbC.gridy = 5; gbC.gridx = 0;
gbC.insets = new Insets(2, 10, 2, 10);
gbL.setConstraints(lab, gbC);
p3.add(lab);
gbC = new GridBagConstraints();
gbC.fill = GridBagConstraints.HORIZONTAL;
gbC.gridy = 5; gbC.gridx = 1; gbC.weightx = 100;
gbC.insets = new Insets(5,0,5,0);
gbL.setConstraints(m_TestsButton, gbC);
p3.add(m_TestsButton);
//=============== BEGIN EDIT melville ===============
lab = new JLabel("Significant digits", SwingConstants.RIGHT);
gbC = new GridBagConstraints();
gbC.anchor = GridBagConstraints.EAST;
gbC.gridy = 6; gbC.gridx = 0;
gbC.insets = new Insets(2, 10, 2, 10);
gbL.setConstraints(lab, gbC);
p3.add(lab);
gbC = new GridBagConstraints();
gbC.gridy = 6; gbC.gridx = 1; gbC.weightx = 100;
gbL.setConstraints(m_PrecTex, gbC);
p3.add(m_PrecTex);
//=============== END EDIT melville ===============
lab = new JLabel("Show std. deviations", SwingConstants.RIGHT);
gbC = new GridBagConstraints();
gbC.anchor = GridBagConstraints.EAST;
gbC.gridy = 7; gbC.gridx = 0;
gbC.insets = new Insets(2, 10, 2, 10);
gbL.setConstraints(lab, gbC);
p3.add(lab);
gbC = new GridBagConstraints();
gbC.anchor = GridBagConstraints.WEST;
gbC.gridy = 7; gbC.gridx = 1; gbC.weightx = 100;
gbC.insets = new Insets(5,0,5,0);
gbL.setConstraints(m_ShowStdDevs, gbC);
p3.add(m_ShowStdDevs);
JPanel output = new JPanel();
output.setLayout(new BorderLayout());
output.setBorder(BorderFactory.createTitledBorder("Test output"));
output.add(new JScrollPane(m_OutText), BorderLayout.CENTER);
JPanel mondo = new JPanel();
gbL = new GridBagLayout();
mondo.setLayout(gbL);
gbC = new GridBagConstraints();
// gbC.anchor = GridBagConstraints.WEST;
// gbC.fill = GridBagConstraints.HORIZONTAL;
gbC.gridy = 0; gbC.gridx = 0;
gbL.setConstraints(p3, gbC);
mondo.add(p3);
JPanel bts = new JPanel();
bts.setLayout(new GridLayout(1,2,5,5));
bts.add(m_PerformBut);
bts.add(m_SaveOutBut);
//=============== BEGIN EDIT mbilenko ===============
bts.add(m_PlotBut);
//=============== END EDIT mbilenko ===============
gbC = new GridBagConstraints();
gbC.anchor = GridBagConstraints.NORTH;
gbC.fill = GridBagConstraints.HORIZONTAL;
gbC.gridy = 1; gbC.gridx = 0;
gbC.insets = new Insets(5,5,5,5);
gbL.setConstraints(bts, gbC);
mondo.add(bts);
gbC = new GridBagConstraints();
//gbC.anchor = GridBagConstraints.NORTH;
gbC.fill = GridBagConstraints.BOTH;
gbC.gridy = 2; gbC.gridx = 0; gbC.weightx = 0;
gbL.setConstraints(m_History, gbC);
mondo.add(m_History);
gbC = new GridBagConstraints();
gbC.fill = GridBagConstraints.BOTH;
gbC.gridy = 0; gbC.gridx = 1;
gbC.gridheight = 3;
gbC.weightx = 100; gbC.weighty = 100;
gbL.setConstraints(output, gbC);
mondo.add(output);
setLayout(new BorderLayout());
add(p1, BorderLayout.NORTH);
add(mondo , BorderLayout.CENTER);
}
/**
* Sets the combo-boxes to a fixed size so they don't take up too much room
* that would be better devoted to the test output box
*/
protected void setComboSizes() {
m_DatasetKeyBut.setPreferredSize(COMBO_SIZE);
m_RunCombo.setPreferredSize(COMBO_SIZE);
m_ResultKeyBut.setPreferredSize(COMBO_SIZE);
m_CompareCombo.setPreferredSize(COMBO_SIZE);
m_SigTex.setPreferredSize(COMBO_SIZE);
m_DatasetKeyBut.setMaximumSize(COMBO_SIZE);
m_RunCombo.setMaximumSize(COMBO_SIZE);
m_ResultKeyBut.setMaximumSize(COMBO_SIZE);
m_CompareCombo.setMaximumSize(COMBO_SIZE);
m_SigTex.setMaximumSize(COMBO_SIZE);
m_DatasetKeyBut.setMinimumSize(COMBO_SIZE);
m_RunCombo.setMinimumSize(COMBO_SIZE);
m_ResultKeyBut.setMinimumSize(COMBO_SIZE);
m_CompareCombo.setMinimumSize(COMBO_SIZE);
m_SigTex.setMinimumSize(COMBO_SIZE);
//=============== BEGIN EDIT melville ===============
m_PrecTex.setPreferredSize(COMBO_SIZE);
m_PrecTex.setMaximumSize(COMBO_SIZE);
m_PrecTex.setMinimumSize(COMBO_SIZE);
//=============== END EDIT melville ===============
}
/**
* Tells the panel to use a new experiment.
*
* @param exp a value of type 'Experiment'
*/
public void setExperiment(Experiment exp) {
m_Exp = exp;
setFromExpEnabled();
}
/**
* Updates whether the current experiment is of a type that we can
* determine the results destination.
*/
protected void setFromExpEnabled() {
if ((m_Exp.getResultListener() instanceof InstancesResultListener)
|| (m_Exp.getResultListener() instanceof DatabaseResultListener)) {
m_FromExpBut.setEnabled(true);
} else {
m_FromExpBut.setEnabled(false);
}
}
/**
* Queries the user enough to make a database query to retrieve experiment
* results.
*/
protected void setInstancesFromDBaseQuery() {
try {
if (m_InstanceQuery == null) {
m_InstanceQuery = new InstanceQuery();
}
String dbaseURL = m_InstanceQuery.getDatabaseURL();
dbaseURL = (String) JOptionPane.showInputDialog(this,
"Enter the database URL",
"Query Database",
JOptionPane.PLAIN_MESSAGE,
null,
null,
dbaseURL);
if (dbaseURL == null) {
m_FromLab.setText("Cancelled");
return;
}
m_InstanceQuery.setDatabaseURL(dbaseURL);
m_InstanceQuery.connectToDatabase();
if (!m_InstanceQuery.experimentIndexExists()) {
m_FromLab.setText("No experiment index");
return;
}
m_FromLab.setText("Getting experiment index");
Instances index = m_InstanceQuery.retrieveInstances("SELECT * FROM "
+ InstanceQuery.EXP_INDEX_TABLE);
if (index.numInstances() == 0) {
m_FromLab.setText("No experiments available");
return;
}
m_FromLab.setText("Got experiment index");
DefaultListModel lm = new DefaultListModel();
for (int i = 0; i < index.numInstances(); i++) {
lm.addElement(index.instance(i).toString());
}
JList jl = new JList(lm);
ListSelectorDialog jd = new ListSelectorDialog(null, jl);
int result = jd.showDialog();
if (result != ListSelectorDialog.APPROVE_OPTION) {
m_FromLab.setText("Cancelled");
return;
}
Instance selInst = index.instance(jl.getSelectedIndex());
Attribute tableAttr = index.attribute(InstanceQuery.EXP_RESULT_COL);
String table = InstanceQuery.EXP_RESULT_PREFIX
+ selInst.toString(tableAttr);
setInstancesFromDatabaseTable(table);
} catch (Exception ex) {
m_FromLab.setText("Problem reading database");
}
}
/**
* Examines the supplied experiment to determine the results destination
* and attempts to load the results.
*
* @param exp a value of type 'Experiment'
*/
protected void setInstancesFromExp(Experiment exp) {
if (exp.getResultListener() instanceof InstancesResultListener) {
File resultFile = ((InstancesResultListener) exp.getResultListener())
.getOutputFile();
if ((resultFile == null) || (resultFile.getName().equals("-"))) {
m_FromLab.setText("No result file");
} else {
setInstancesFromFile(resultFile);
}
} else if (exp.getResultListener() instanceof DatabaseResultListener) {
String dbaseURL = ((DatabaseResultListener) exp.getResultListener())
.getDatabaseURL();
try {
if (m_InstanceQuery == null) {
m_InstanceQuery = new InstanceQuery();
}
m_InstanceQuery.setDatabaseURL(dbaseURL);
m_InstanceQuery.connectToDatabase();
String tableName = m_InstanceQuery
.getResultsTableName(exp.getResultProducer());
setInstancesFromDatabaseTable(tableName);
} catch (Exception ex) {
m_FromLab.setText("Problem reading database");
}
} else {
m_FromLab.setText("Can't get results from experiment");
}
}
/**
* Queries a database to load results from the specified table name. The
* database connection must have already made by m_InstanceQuery.
*
* @param tableName the name of the table containing results to retrieve.
*/
protected void setInstancesFromDatabaseTable(String tableName) {
try {
m_FromLab.setText("Reading from database, please wait...");
final Instances i = m_InstanceQuery.retrieveInstances("SELECT * FROM "
+ tableName);
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
setInstances(i);
}
});
m_InstanceQuery.disconnectFromDatabase();
} catch (Exception ex) {
m_FromLab.setText(ex.getMessage());
}
}
/**
* Loads results from a set of instances contained in the supplied
* file.
*
* @param f a value of type 'File'
*/
protected void setInstancesFromFile(File f) {
try {
m_FromLab.setText("Reading from file...");
Reader r = new BufferedReader(new FileReader(f));
setInstances(new Instances(r));
} catch (Exception ex) {
ex.printStackTrace();
m_FromLab.setText(ex.getMessage());
}
}
/**
* Sets up the panel with a new set of instances, attempting
* to guess the correct settings for various columns.
*
* @param newInstances the new set of results.
*/
public void setInstances(Instances newInstances) {
m_Instances = newInstances;
m_TTester.setInstances(m_Instances);
m_FromLab.setText("Got " + m_Instances.numInstances() + " results");
// Temporarily remove the configuration listener
m_RunCombo.removeActionListener(m_ConfigureListener);
// Do other stuff
m_DatasetKeyModel.removeAllElements();
m_RunModel.removeAllElements();
m_ResultKeyModel.removeAllElements();
m_CompareModel.removeAllElements();
int datasetCol = -1;
int runCol = -1;
String selectedList = "";
String selectedListDataset = "";
//=============== BEGIN EDIT melville ===============
boolean noise = false;//keep track of whether noise levels eval is required
boolean learning = false;//keep track of whether learning curve eval is required
boolean fraction = false;//keep track of whether fractions of datasets are provided for learning
//the key on which to base the learning curves (either total instances or fraction)
int learning_key = -1;
boolean classificationTask = false;//used to determine if regression measures should be selected
//=============== END EDIT melville ===============
for (int i = 0; i < m_Instances.numAttributes(); i++) {
String name = m_Instances.attribute(i).name();
m_DatasetKeyModel.addElement(name);
m_RunModel.addElement(name);
m_ResultKeyModel.addElement(name);
m_CompareModel.addElement(name);
//=============== BEGIN EDIT melville ===============
//If learning curves were generated then treat each
//dataset + pt combination as a different dataset
if(name.toLowerCase().equals("key_noise_levels")){
//noise overrides learning curves - but treat noise levels
//like pts on learning curve
learning_key = i;
learning = true;
noise = true;
//fraction = true;
}else if(name.toLowerCase().equals("key_fraction_instances") && !noise){
//fraction overrides total_instances
learning_key = i;
learning = true;
fraction = true;
}else if(name.toLowerCase().equals("key_total_instances") && !learning){
learning_key = i;
learning = true;
}else
//=============== END EDIT melville ===============
if (name.toLowerCase().equals("key_dataset")) {
m_DatasetKeyList.addSelectionInterval(i, i);
selectedListDataset += "," + (i + 1);
} else if ((runCol == -1)
&& (name.toLowerCase().equals("key_run"))) {
m_RunCombo.setSelectedIndex(i);
runCol = i;
} else if (name.toLowerCase().equals("key_scheme") ||
name.toLowerCase().equals("key_scheme_options") ||
name.toLowerCase().equals("key_scheme_version_id")) {
m_ResultKeyList.addSelectionInterval(i, i);
selectedList += "," + (i + 1);
//=============== BEGIN EDIT mbilenko ===============
// automatic selection of the correct measure for clustering experiments
} else if (name.toLowerCase().indexOf("pairwise_f_measure") != -1) {
m_CompareCombo.setSelectedIndex(i);
m_ErrorCompareCol = i;
}
// automatic selection of the correct measure for deduping experiments
else if (name.toLowerCase().equals("precision")) {
m_CompareCombo.setSelectedIndex(i);
//=============== END EDIT mbilenko ===============
}else if (name.toLowerCase().indexOf("percent_correct") != -1) {
m_CompareCombo.setSelectedIndex(i);
classificationTask=true;
}else if (!classificationTask && (name.toLowerCase().indexOf("root_mean_squared_error") != -1)) {
// automatic selection of the correct measure for regression experiments
m_CompareCombo.setSelectedIndex(i);
}else if (name.toLowerCase().indexOf("percent_incorrect") != -1) {
m_ErrorCompareCol = i;
//remember index of error for computing error reductions
}
}
//=============== BEGIN EDIT melville ===============
if(learning){
m_DatasetKeyList.addSelectionInterval(learning_key, learning_key);
selectedListDataset += "," + (learning_key + 1);
m_CompareModel.addElement("%Error_reduction");
m_CompareModel.addElement("Top_20%_%Error_reduction");
}
//=============== END EDIT melville ===============
if (runCol == -1) {
runCol = 0;
}
m_DatasetKeyBut.setEnabled(true);
m_RunCombo.setEnabled(true);
m_ResultKeyBut.setEnabled(true);
m_CompareCombo.setEnabled(true);
// Reconnect the configuration listener
m_RunCombo.addActionListener(m_ConfigureListener);
// Set up the TTester with the new data
m_TTester.setRunColumn(runCol);
Range generatorRange = new Range();
if (selectedList.length() != 0) {
try {
generatorRange.setRanges(selectedList);
} catch (Exception ex) {
ex.printStackTrace();
System.err.println(ex.getMessage());
}
}
m_TTester.setResultsetKeyColumns(generatorRange);
generatorRange = new Range();
if (selectedListDataset.length() != 0) {
try {
generatorRange.setRanges(selectedListDataset);
} catch (Exception ex) {
ex.printStackTrace();
System.err.println(ex.getMessage());
}
}
m_TTester.setDatasetKeyColumns(generatorRange);
//=============== BEGIN EDIT melville ===============
m_TTester.setLearningCurve(learning);
m_TTester.setFraction(fraction);
if(learning){//get points on the learning curve
Attribute attr;
if(noise){//override fraction
attr = m_Instances.attribute("Key_Noise_levels");
}else if(fraction){
attr = m_Instances.attribute("Key_Fraction_instances");
}else {
attr = m_Instances.attribute("Key_Total_instances");
}
double []pts = new double [attr.numValues()];
for(int k=0; k<attr.numValues(); k++){
pts[k] = Double.parseDouble(attr.value(k));
}
//sort points
Arrays.sort(pts);
m_TTester.setPoints(pts);
}
//=============== END EDIT melville ===============
m_SigTex.setEnabled(true);
m_PrecTex.setEnabled(true);
setTTester();
}
/**
* Updates the test chooser with possible tests
*/
protected void setTTester() {
String name = (new SimpleDateFormat("HH:mm:ss - "))
.format(new Date())
+ "Available resultsets";
StringBuffer outBuff = new StringBuffer();
outBuff.append("Available resultsets\n"
+ m_TTester.resultsetKey() + "\n\n");
m_History.addResult(name, outBuff);
m_History.setSingle(name);
m_TestsModel.removeAllElements();
for (int i = 0; i < m_TTester.getNumResultsets(); i++) {
String tname = m_TTester.getResultsetName(i);
/* if (tname.length() > 20) {
tname = tname.substring(0, 20);
} */
m_TestsModel.addElement(tname);
}
m_TestsModel.addElement("Summary");
m_TestsModel.addElement("Ranking");
//================ BEGIN EDIT melville ================
m_TestsModel.addElement("Learning Curve Summary");
//================ END EDIT melville ================
m_TestsList.setSelectedIndex(0);
m_TestsButton.setEnabled(true);
m_PerformBut.setEnabled(true);
}
/**
* Carries out a t-test using the current configuration.
*/
protected void performTest() {
String sigStr = m_SigTex.getText();
if (sigStr.length() != 0) {
m_TTester.setSignificanceLevel((new Double(sigStr)).doubleValue());
} else {
m_TTester.setSignificanceLevel(0.05);
}
String precStr = m_PrecTex.getText();
if (precStr.length() != 0) {
m_TTester.setPrecision((new Integer(precStr)).intValue());
} else {
m_TTester.setPrecision(2);
}
// Carry out the test chosen and biff the results to the output area
m_TTester.setShowStdDevs(m_ShowStdDevs.isSelected());
int compareCol = m_CompareCombo.getSelectedIndex();
int tType = m_TestsList.getSelectedIndex();
//=============== BEGIN EDIT melville ===============
String test_selected = (String) m_TestsList.getSelectedValue();
String name = (new SimpleDateFormat("HH:mm:ss - "))
.format(new Date())
+ (String) m_CompareCombo.getSelectedItem() + " - "
+ test_selected;
StringBuffer outBuff = new StringBuffer();
if(((String) m_CompareCombo.getSelectedItem()).equalsIgnoreCase("%error_reduction"))
outBuff.append(m_TTester.header("Percentage error reduction"));
else if(((String) m_CompareCombo.getSelectedItem()).equalsIgnoreCase("top_20%_%error_reduction"))
outBuff.append(m_TTester.header("Top 20% Percentage error reduction"));
else outBuff.append(m_TTester.header(compareCol));
outBuff.append("\n");
m_History.addResult(name, outBuff);
m_History.setSingle(name);
try {
if (tType < m_TTester.getNumResultsets()) {
if(((String) m_CompareCombo.getSelectedItem()).equalsIgnoreCase("%error_reduction")){
outBuff.append(m_TTester.multiResultsetPercentErrorReduction(tType, m_ErrorCompareCol));
}else if(((String) m_CompareCombo.getSelectedItem()).equalsIgnoreCase("top_20%_%error_reduction")){
outBuff.append(m_TTester.multiResultsetTopNPercentErrorReduction(tType, m_ErrorCompareCol, 0.20));
}else outBuff.append(m_TTester.multiResultsetFull(tType, compareCol));
}
else if (test_selected.equalsIgnoreCase("summary")) {
outBuff.append(m_TTester.multiResultsetSummary(compareCol));
} else if (test_selected.equalsIgnoreCase("ranking")) {
outBuff.append(m_TTester.multiResultsetRanking(compareCol));
}
//================ END EDIT melville ================
outBuff.append("\n");
} catch (Exception ex) {
outBuff.append(ex.getMessage() + "\n");
}
m_History.updateResult(name);
}
public void setResultKeyFromDialog() {
ListSelectorDialog jd = new ListSelectorDialog(null, m_ResultKeyList);
// Open the dialog
int result = jd.showDialog();
// If accepted, update the ttester
if (result == ListSelectorDialog.APPROVE_OPTION) {
int [] selected = m_ResultKeyList.getSelectedIndices();
String selectedList = "";
for (int i = 0; i < selected.length; i++) {
selectedList += "," + (selected[i] + 1);
}
Range generatorRange = new Range();
if (selectedList.length() != 0) {
try {
generatorRange.setRanges(selectedList);
} catch (Exception ex) {
ex.printStackTrace();
System.err.println(ex.getMessage());
}
}
m_TTester.setResultsetKeyColumns(generatorRange);
setTTester();
}
}
public void setDatasetKeyFromDialog() {
ListSelectorDialog jd = new ListSelectorDialog(null, m_DatasetKeyList);
// Open the dialog
int result = jd.showDialog();
//=============== BEGIN EDIT melville ===============
//Check if learning curves should be generated
boolean noise = false;
boolean learning = false;
boolean fraction = false;
int learning_key = -1;
// If accepted, update the ttester
if (result == ListSelectorDialog.APPROVE_OPTION) {
int [] selected = m_DatasetKeyList.getSelectedIndices();
String selectedList = "";
Object [] selected_string = m_DatasetKeyList.getSelectedValues();
for (int i = 0; i < selected.length; i++) {
if(((String)selected_string[i]).toLowerCase().equals("key_noise_levels")){
learning_key = i;
learning = true;
//fraction = true;
noise = true;
}else if(((String)selected_string[i]).toLowerCase().equals("key_fraction_instances")){
learning_key = i;
learning = true;
fraction = true;
}else if(((String)selected_string[i]).toLowerCase().equals("key_total_instances") && !learning){
learning = true;
learning_key = i;
}else
selectedList += "," + (selected[i] + 1);
}
m_TTester.setLearningCurve(learning);
m_TTester.setFraction(fraction);
if(learning){//get points on the learning curve
selectedList += "," + (selected[learning_key] + 1);
Attribute attr;
if(noise){//override fraction
attr = m_Instances.attribute("Key_Noise_levels");
}else if(fraction){
attr = m_Instances.attribute("Key_Fraction_instances");
}else {
attr = m_Instances.attribute("Key_Total_instances");
}
double []pts = new double [attr.numValues()];
for(int k=0; k<attr.numValues(); k++){
pts[k] = Double.parseDouble(attr.value(k));
}
Arrays.sort(pts);
m_TTester.setPoints(pts);
}
//================ END EDIT melville ================
Range generatorRange = new Range();
if (selectedList.length() != 0) {
try {
generatorRange.setRanges(selectedList);
} catch (Exception ex) {
ex.printStackTrace();
System.err.println(ex.getMessage());
}
}
m_TTester.setDatasetKeyColumns(generatorRange);
setTTester();
}
}
public void setTestBaseFromDialog() {
ListSelectorDialog jd = new ListSelectorDialog(null, m_TestsList);
// Open the dialog
jd.showDialog();
}
/**
* Save the currently selected result buffer to a file.
*/
protected void saveBuffer() {
StringBuffer sb = m_History.getSelectedBuffer();
if (sb != null) {
if (m_SaveOut.save(sb)) {
JOptionPane.showMessageDialog(this,
"File saved",
"Results",
JOptionPane.INFORMATION_MESSAGE);
}
} else {
m_SaveOutBut.setEnabled(false);
}
}
//=============== BEGIN EDIT mbilenko ===============
/**
* Plot the currently selected output buffer
*/
protected void plotOutput() {
try {
StringBuffer sb = m_History.getSelectedBuffer();
if (sb != null) {
// dump the output into a temporary file
File tempDirFile = new File("/tmp");
final File bufferFile = File.createTempFile("buffer", "", tempDirFile);
bufferFile.deleteOnExit();
PrintWriter writer = new PrintWriter(new BufferedOutputStream(new FileOutputStream(bufferFile)));
writer.print(sb);
writer.close();
// launch the perl script to process the file
//Process proc = Runtime.getRuntime().exec("perl weka/gui/experiment/plot.pl " + bufferFile.getPath());
Process proc = Runtime.getRuntime().exec("perl /u/ml/software/weka-latest/weka/gui/experiment/plot.pl " + bufferFile.getPath());
proc.waitFor();
// get a list of generated gnuplot scripts
String[] scriptList = tempDirFile.list(new FilenameFilter() {
public boolean accept(File f, String s) { return (s.endsWith(".gplot") && s.startsWith(bufferFile.getName())); }
});
for (int i = 0; i < scriptList.length; i++) {
// launch gnuplot
scriptList[i] = tempDirFile.getPath() + "/" + scriptList[i];
System.out.println(scriptList[i]);
proc = Runtime.getRuntime().exec("gnuplot -persist " + scriptList[i]);
File plotFile = new File(scriptList[i]);
plotFile.deleteOnExit();
File dataFile = new File(scriptList[i].replaceAll(".gplot", ".dat"));
dataFile.deleteOnExit();
}
} else {
m_PlotBut.setEnabled(false);
}
} catch (Exception e) {
System.out.println("Problems plotting: " + e);
e.printStackTrace();
}
}
//=============== END EDIT mbilenko ===============
/**
* Tests out the results panel from the command line.
*
* @param args ignored
*/
public static void main(String [] args) {
try {
final JFrame jf = new JFrame("Weka Experiment: Results Analysis");
jf.getContentPane().setLayout(new BorderLayout());
final ResultsPanel sp = new ResultsPanel();
//sp.setBorder(BorderFactory.createTitledBorder("Setup"));
jf.getContentPane().add(sp, BorderLayout.CENTER);
jf.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
jf.dispose();
System.exit(0);
}
});
jf.pack();
jf.setSize(700, 550);
jf.setVisible(true);
} catch (Exception ex) {
ex.printStackTrace();
System.err.println(ex.getMessage());
}
}
}