weka.gui.visualize.VisualizePanel Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of weka-dev Show documentation
Show all versions of weka-dev Show documentation
The Waikato Environment for Knowledge Analysis (WEKA), a machine
learning workbench. This version represents the developer version, the
"bleeding edge" of development, you could say. New functionality gets added
to this version.
/*
* 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 3 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, see .
*/
/*
* VisualizePanel.java
* Copyright (C) 1999-2012 University of Waikato, Hamilton, New Zealand
*
*/
package weka.gui.visualize;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.InputEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Random;
import javax.swing.BorderFactory;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.SwingConstants;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.filechooser.FileFilter;
import weka.core.Attribute;
import weka.core.Instance;
import weka.core.Instances;
import weka.gui.ExtensionFileFilter;
import weka.gui.Logger;
/**
* This panel allows the user to visualize a dataset (and if provided) a
* classifier's/clusterer's predictions in two dimensions.
*
* If the user selects a nominal attribute as the colouring attribute then each
* point is drawn in a colour that corresponds to the discrete value of that
* attribute for the instance. If the user selects a numeric attribute to colour
* on, then the points are coloured using a spectrum ranging from blue to red
* (low values to high).
*
* When a classifier's predictions are supplied they are plotted in one of two
* ways (depending on whether the class is nominal or numeric).
* For nominal class: an error made by a classifier is plotted as a square in
* the colour corresponding to the class it predicted.
* For numeric class: predictions are plotted as varying sized x's, where the
* size of the x is related to the magnitude of the error.
*
* @author Mark Hall ([email protected])
* @author Malcolm Ware ([email protected])
* @version $Revision: 10222 $
*/
public class VisualizePanel extends PrintablePanel {
/** for serialization */
private static final long serialVersionUID = 240108358588153943L;
/** Inner class to handle plotting */
protected class PlotPanel extends PrintablePanel implements Plot2DCompanion {
/** for serialization */
private static final long serialVersionUID = -4823674171136494204L;
/** The actual generic plotting panel */
protected Plot2D m_plot2D = new Plot2D();
/** The instances from the master plot */
protected Instances m_plotInstances = null;
/** The master plot */
protected PlotData2D m_originalPlot = null;
/**
* Indexes of the attributes to go on the x and y axis and the attribute to
* use for colouring and the current shape for drawing
*/
protected int m_xIndex = 0;
protected int m_yIndex = 0;
protected int m_cIndex = 0;
protected int m_sIndex = 0;
/** the offsets of the axes once label metrics are calculated */
/*
* private int m_XaxisStart=0; NOT USED private int m_YaxisStart=0; private
* int m_XaxisEnd=0; private int m_YaxisEnd=0;
*/
/** True if the user is currently dragging a box. */
private boolean m_createShape;
/** contains all the shapes that have been drawn for these attribs */
private ArrayList> m_shapes;
/** contains the points of the shape currently being drawn. */
private ArrayList m_shapePoints;
/** contains the position of the mouse (used for rubberbanding). */
private final Dimension m_newMousePos;
/** Constructor */
public PlotPanel() {
this.setBackground(m_plot2D.getBackground());
this.setLayout(new BorderLayout());
this.add(m_plot2D, BorderLayout.CENTER);
m_plot2D.setPlotCompanion(this);
m_createShape = false;
m_shapes = null;// //
m_shapePoints = null;
m_newMousePos = new Dimension();
this.addMouseListener(new MouseAdapter() {
// /////
@Override
public void mousePressed(MouseEvent e) {
if ((e.getModifiers() & MouseEvent.BUTTON1_MASK) == MouseEvent.BUTTON1_MASK) {
//
if (m_sIndex == 0) {
// do nothing it will get dealt to in the clicked method
} else if (m_sIndex == 1) {
m_createShape = true;
m_shapePoints = new ArrayList(5);
m_shapePoints.add(new Double(m_sIndex));
m_shapePoints.add(new Double(e.getX()));
m_shapePoints.add(new Double(e.getY()));
m_shapePoints.add(new Double(e.getX()));
m_shapePoints.add(new Double(e.getY()));
// Graphics g = PlotPanel.this.getGraphics();
Graphics g = m_plot2D.getGraphics();
g.setColor(Color.black);
g.setXORMode(Color.white);
g.drawRect(m_shapePoints.get(1).intValue(), m_shapePoints.get(2)
.intValue(), m_shapePoints.get(3).intValue()
- m_shapePoints.get(1).intValue(), m_shapePoints.get(4)
.intValue() - m_shapePoints.get(2).intValue());
g.dispose();
}
// System.out.println("clicked");
}
// System.out.println("clicked");
}
// ////
@Override
public void mouseClicked(MouseEvent e) {
if ((m_sIndex == 2 || m_sIndex == 3)
&& (m_createShape || (e.getModifiers() & MouseEvent.BUTTON1_MASK) == MouseEvent.BUTTON1_MASK)) {
if (m_createShape) {
// then it has been started already.
Graphics g = m_plot2D.getGraphics();
g.setColor(Color.black);
g.setXORMode(Color.white);
if ((e.getModifiers() & MouseEvent.BUTTON1_MASK) == MouseEvent.BUTTON1_MASK
&& !e.isAltDown()) {
m_shapePoints.add(new Double(
m_plot2D.convertToAttribX(e.getX())));
m_shapePoints.add(new Double(
m_plot2D.convertToAttribY(e.getY())));
m_newMousePos.width = e.getX();
m_newMousePos.height = e.getY();
g.drawLine(
(int) Math.ceil(m_plot2D.convertToPanelX(m_shapePoints.get(
m_shapePoints.size() - 2).doubleValue())),
(int) Math.ceil(m_plot2D.convertToPanelY(m_shapePoints.get(
m_shapePoints.size() - 1).doubleValue())),
m_newMousePos.width, m_newMousePos.height);
} else if (m_sIndex == 3) {
// then extend the lines to infinity
// (100000 or so should be enough).
// the area is selected by where the user right clicks
// the mouse button
m_createShape = false;
if (m_shapePoints.size() >= 5) {
double cx = Math.ceil(m_plot2D.convertToPanelX(m_shapePoints
.get(m_shapePoints.size() - 4).doubleValue()));
double cx2 = Math.ceil(m_plot2D.convertToPanelX(m_shapePoints
.get(m_shapePoints.size() - 2).doubleValue())) - cx;
cx2 *= 50000;
double cy = Math.ceil(m_plot2D.convertToPanelY(m_shapePoints
.get(m_shapePoints.size() - 3).doubleValue()));
double cy2 = Math.ceil(m_plot2D.convertToPanelY(m_shapePoints
.get(m_shapePoints.size() - 1).doubleValue())) - cy;
cy2 *= 50000;
double cxa = Math.ceil(m_plot2D.convertToPanelX(m_shapePoints
.get(3).doubleValue()));
double cxa2 = Math.ceil(m_plot2D
.convertToPanelX(m_shapePoints.get(1).doubleValue())) - cxa;
cxa2 *= 50000;
double cya = Math.ceil(m_plot2D.convertToPanelY(m_shapePoints
.get(4).doubleValue()));
double cya2 = Math.ceil(m_plot2D
.convertToPanelY(m_shapePoints.get(2).doubleValue())) - cya;
cya2 *= 50000;
m_shapePoints.set(1,
new Double(m_plot2D.convertToAttribX(cxa2 + cxa)));
m_shapePoints.set(m_shapePoints.size() - 1, new Double(
m_plot2D.convertToAttribY(cy2 + cy)));
m_shapePoints.set(m_shapePoints.size() - 2, new Double(
m_plot2D.convertToAttribX(cx2 + cx)));
m_shapePoints.set(2,
new Double(m_plot2D.convertToAttribY(cya2 + cya)));
// determine how infinity line should be built
cy = Double.POSITIVE_INFINITY;
cy2 = Double.NEGATIVE_INFINITY;
if (m_shapePoints.get(1).doubleValue() > m_shapePoints.get(3)
.doubleValue()) {
if (m_shapePoints.get(2).doubleValue() == m_shapePoints
.get(4).doubleValue()) {
cy = m_shapePoints.get(2).doubleValue();
}
}
if (m_shapePoints.get(m_shapePoints.size() - 2).doubleValue() > m_shapePoints
.get(m_shapePoints.size() - 4).doubleValue()) {
if (m_shapePoints.get(m_shapePoints.size() - 3)
.doubleValue() == m_shapePoints.get(
m_shapePoints.size() - 1).doubleValue()) {
cy2 = m_shapePoints.get(m_shapePoints.size() - 1)
.doubleValue();
}
}
m_shapePoints.add(new Double(cy));
m_shapePoints.add(new Double(cy2));
if (!inPolyline(m_shapePoints,
m_plot2D.convertToAttribX(e.getX()),
m_plot2D.convertToAttribY(e.getY()))) {
Double tmp = m_shapePoints.get(m_shapePoints.size() - 2);
m_shapePoints.set(m_shapePoints.size() - 2,
m_shapePoints.get(m_shapePoints.size() - 1));
m_shapePoints.set(m_shapePoints.size() - 1, tmp);
}
if (m_shapes == null) {
m_shapes = new ArrayList>(4);
}
m_shapes.add(m_shapePoints);
m_submit.setText("Submit");
m_submit.setActionCommand("Submit");
m_submit.setEnabled(true);
}
m_shapePoints = null;
PlotPanel.this.repaint();
} else {
// then close the shape
m_createShape = false;
if (m_shapePoints.size() >= 7) {
m_shapePoints.add(m_shapePoints.get(1));
m_shapePoints.add(m_shapePoints.get(2));
if (m_shapes == null) {
m_shapes = new ArrayList>(4);
}
m_shapes.add(m_shapePoints);
m_submit.setText("Submit");
m_submit.setActionCommand("Submit");
m_submit.setEnabled(true);
}
m_shapePoints = null;
PlotPanel.this.repaint();
}
g.dispose();
// repaint();
} else if ((e.getModifiers() & MouseEvent.BUTTON1_MASK) == MouseEvent.BUTTON1_MASK) {
// then this is the first point
m_createShape = true;
m_shapePoints = new ArrayList(17);
m_shapePoints.add(new Double(m_sIndex));
m_shapePoints.add(new Double(m_plot2D.convertToAttribX(e.getX()))); // the
// new
// point
m_shapePoints.add(new Double(m_plot2D.convertToAttribY(e.getY())));
m_newMousePos.width = e.getX(); // the temp mouse point
m_newMousePos.height = e.getY();
Graphics g = m_plot2D.getGraphics();
g.setColor(Color.black);
g.setXORMode(Color.white);
g.drawLine((int) Math.ceil(m_plot2D.convertToPanelX(m_shapePoints
.get(1).doubleValue())), (int) Math.ceil(m_plot2D
.convertToPanelY(m_shapePoints.get(2).doubleValue())),
m_newMousePos.width, m_newMousePos.height);
g.dispose();
}
} else {
if ((e.getModifiers() & InputEvent.BUTTON1_MASK) == InputEvent.BUTTON1_MASK) {
m_plot2D.searchPoints(e.getX(), e.getY(), false);
} else {
m_plot2D.searchPoints(e.getX(), e.getY(), true);
}
}
}
// ///////
@Override
public void mouseReleased(MouseEvent e) {
if (m_createShape) {
if (m_shapePoints.get(0).intValue() == 1) {
m_createShape = false;
Graphics g = m_plot2D.getGraphics();
g.setColor(Color.black);
g.setXORMode(Color.white);
g.drawRect(m_shapePoints.get(1).intValue(), m_shapePoints.get(2)
.intValue(), m_shapePoints.get(3).intValue()
- m_shapePoints.get(1).intValue(), m_shapePoints.get(4)
.intValue() - m_shapePoints.get(2).intValue());
g.dispose();
if (checkPoints(m_shapePoints.get(1).doubleValue(), m_shapePoints
.get(2).doubleValue())
&& checkPoints(m_shapePoints.get(3).doubleValue(),
m_shapePoints.get(4).doubleValue())) {
// then the points all land on the screen
// now do special check for the rectangle
if (m_shapePoints.get(1).doubleValue() < m_shapePoints.get(3)
.doubleValue()
&& m_shapePoints.get(2).doubleValue() < m_shapePoints.get(4)
.doubleValue()) {
// then the rectangle is valid
if (m_shapes == null) {
m_shapes = new ArrayList>(2);
}
m_shapePoints.set(
1,
new Double(m_plot2D.convertToAttribX(m_shapePoints.get(1)
.doubleValue())));
m_shapePoints.set(
2,
new Double(m_plot2D.convertToAttribY(m_shapePoints.get(2)
.doubleValue())));
m_shapePoints.set(
3,
new Double(m_plot2D.convertToAttribX(m_shapePoints.get(3)
.doubleValue())));
m_shapePoints.set(
4,
new Double(m_plot2D.convertToAttribY(m_shapePoints.get(4)
.doubleValue())));
m_shapes.add(m_shapePoints);
m_submit.setText("Submit");
m_submit.setActionCommand("Submit");
m_submit.setEnabled(true);
PlotPanel.this.repaint();
}
}
m_shapePoints = null;
}
}
}
});
this.addMouseMotionListener(new MouseMotionAdapter() {
@Override
public void mouseDragged(MouseEvent e) {
// check if the user is dragging a box
if (m_createShape) {
if (m_shapePoints.get(0).intValue() == 1) {
Graphics g = m_plot2D.getGraphics();
g.setColor(Color.black);
g.setXORMode(Color.white);
g.drawRect(m_shapePoints.get(1).intValue(), m_shapePoints.get(2)
.intValue(), m_shapePoints.get(3).intValue()
- m_shapePoints.get(1).intValue(), m_shapePoints.get(4)
.intValue() - m_shapePoints.get(2).intValue());
m_shapePoints.set(3, new Double(e.getX()));
m_shapePoints.set(4, new Double(e.getY()));
g.drawRect(m_shapePoints.get(1).intValue(), m_shapePoints.get(2)
.intValue(), m_shapePoints.get(3).intValue()
- m_shapePoints.get(1).intValue(), m_shapePoints.get(4)
.intValue() - m_shapePoints.get(2).intValue());
g.dispose();
}
}
}
@Override
public void mouseMoved(MouseEvent e) {
if (m_createShape) {
if (m_shapePoints.get(0).intValue() == 2
|| m_shapePoints.get(0).intValue() == 3) {
Graphics g = m_plot2D.getGraphics();
g.setColor(Color.black);
g.setXORMode(Color.white);
g.drawLine(
(int) Math.ceil(m_plot2D.convertToPanelX(m_shapePoints.get(
m_shapePoints.size() - 2).doubleValue())),
(int) Math.ceil(m_plot2D.convertToPanelY(m_shapePoints.get(
m_shapePoints.size() - 1).doubleValue())),
m_newMousePos.width, m_newMousePos.height);
m_newMousePos.width = e.getX();
m_newMousePos.height = e.getY();
g.drawLine(
(int) Math.ceil(m_plot2D.convertToPanelX(m_shapePoints.get(
m_shapePoints.size() - 2).doubleValue())),
(int) Math.ceil(m_plot2D.convertToPanelY(m_shapePoints.get(
m_shapePoints.size() - 1).doubleValue())),
m_newMousePos.width, m_newMousePos.height);
g.dispose();
}
}
}
});
m_submit.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (e.getActionCommand().equals("Submit")) {
if (m_splitListener != null && m_shapes != null) {
// then send the split to the listener
Instances sub_set1 = new Instances(
m_plot2D.getMasterPlot().m_plotInstances, 500);
Instances sub_set2 = new Instances(
m_plot2D.getMasterPlot().m_plotInstances, 500);
if (m_plot2D.getMasterPlot().m_plotInstances != null) {
for (int noa = 0; noa < m_plot2D.getMasterPlot().m_plotInstances
.numInstances(); noa++) {
if (!m_plot2D.getMasterPlot().m_plotInstances.instance(noa)
.isMissing(m_xIndex)
&& !m_plot2D.getMasterPlot().m_plotInstances.instance(noa)
.isMissing(m_yIndex)) {
if (inSplit(m_plot2D.getMasterPlot().m_plotInstances
.instance(noa))) {
sub_set1.add(m_plot2D.getMasterPlot().m_plotInstances
.instance(noa));
} else {
sub_set2.add(m_plot2D.getMasterPlot().m_plotInstances
.instance(noa));
}
}
}
ArrayList> tmp = m_shapes;
cancelShapes();
m_splitListener.userDataEvent(new VisualizePanelEvent(tmp,
sub_set1, sub_set2, m_xIndex, m_yIndex));
}
} else if (m_shapes != null
&& m_plot2D.getMasterPlot().m_plotInstances != null) {
Instances sub_set1 = new Instances(
m_plot2D.getMasterPlot().m_plotInstances, 500);
int count = 0;
for (int noa = 0; noa < m_plot2D.getMasterPlot().m_plotInstances
.numInstances(); noa++) {
if (inSplit(m_plot2D.getMasterPlot().m_plotInstances
.instance(noa))) {
sub_set1.add(m_plot2D.getMasterPlot().m_plotInstances
.instance(noa));
count++;
}
}
int[] nSizes = null;
int[] nTypes = null;
int x = m_xIndex;
int y = m_yIndex;
if (m_originalPlot == null) {
// this sets these instances as the instances
// to go back to.
m_originalPlot = m_plot2D.getMasterPlot();
}
if (count > 0) {
nTypes = new int[count];
nSizes = new int[count];
count = 0;
for (int noa = 0; noa < m_plot2D.getMasterPlot().m_plotInstances
.numInstances(); noa++) {
if (inSplit(m_plot2D.getMasterPlot().m_plotInstances
.instance(noa))) {
nTypes[count] = m_plot2D.getMasterPlot().m_shapeType[noa];
nSizes[count] = m_plot2D.getMasterPlot().m_shapeSize[noa];
count++;
}
}
}
cancelShapes();
PlotData2D newPlot = new PlotData2D(sub_set1);
try {
newPlot.setShapeSize(nSizes);
newPlot.setShapeType(nTypes);
m_plot2D.removeAllPlots();
VisualizePanel.this.addPlot(newPlot);
} catch (Exception ex) {
System.err.println(ex);
ex.printStackTrace();
}
try {
VisualizePanel.this.setXIndex(x);
VisualizePanel.this.setYIndex(y);
} catch (Exception er) {
System.out.println("Error : " + er);
// System.out.println("Part of user input so had to" +
// " catch here");
}
}
} else if (e.getActionCommand().equals("Reset")) {
int x = m_xIndex;
int y = m_yIndex;
m_plot2D.removeAllPlots();
try {
VisualizePanel.this.addPlot(m_originalPlot);
} catch (Exception ex) {
System.err.println(ex);
ex.printStackTrace();
}
try {
VisualizePanel.this.setXIndex(x);
VisualizePanel.this.setYIndex(y);
} catch (Exception er) {
System.out.println("Error : " + er);
}
}
}
});
m_cancel.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
cancelShapes();
PlotPanel.this.repaint();
}
});
// //////////
}
/**
* Removes all the plots.
*/
public void removeAllPlots() {
m_plot2D.removeAllPlots();
m_legendPanel.setPlotList(m_plot2D.getPlots());
}
/**
* @return The FastVector containing all the shapes.
*/
public ArrayList> getShapes() {
return m_shapes;
}
/**
* Sets the list of shapes to empty and also cancels the current shape being
* drawn (if applicable).
*/
public void cancelShapes() {
if (m_splitListener == null) {
m_submit.setText("Reset");
m_submit.setActionCommand("Reset");
if (m_originalPlot == null
|| m_originalPlot.m_plotInstances == m_plotInstances) {
m_submit.setEnabled(false);
} else {
m_submit.setEnabled(true);
}
} else {
m_submit.setEnabled(false);
}
m_createShape = false;
m_shapePoints = null;
m_shapes = null;
this.repaint();
}
/**
* This can be used to set the shapes that should appear.
*
* @param v The list of shapes.
*/
public void setShapes(ArrayList> v) {
// note that this method should be fine for doubles,
// but anything else that uses something other than doubles
// (or uneditable objects) could have unsafe copies.
if (v != null) {
ArrayList temp;
m_shapes = new ArrayList>(v.size());
for (int noa = 0; noa < v.size(); noa++) {
temp = new ArrayList(v.get(noa).size());
m_shapes.add(temp);
for (int nob = 0; nob < v.get(noa).size(); nob++) {
temp.add(v.get(noa).get(nob));
}
}
} else {
m_shapes = null;
}
this.repaint();
}
/**
* This will check the values of the screen points passed and make sure that
* they land on the screen
*
* @param x1 The x coord.
* @param y1 The y coord.
* @return true if the point would land on the screen
*/
private boolean checkPoints(double x1, double y1) {
if (x1 < 0 || x1 > this.getSize().width || y1 < 0
|| y1 > this.getSize().height) {
return false;
}
return true;
}
/**
* This will check if an instance is inside or outside of the current
* shapes.
*
* @param i The instance to check.
* @return True if 'i' falls inside the shapes, false otherwise.
*/
public boolean inSplit(Instance i) {
// this will check if the instance lies inside the shapes or not
if (m_shapes != null) {
ArrayList stmp;
double x1, y1, x2, y2;
for (int noa = 0; noa < m_shapes.size(); noa++) {
stmp = m_shapes.get(noa);
if (stmp.get(0).intValue() == 1) {
// then rectangle
x1 = stmp.get(1).doubleValue();
y1 = stmp.get(2).doubleValue();
x2 = stmp.get(3).doubleValue();
y2 = stmp.get(4).doubleValue();
if (i.value(m_xIndex) >= x1 && i.value(m_xIndex) <= x2
&& i.value(m_yIndex) <= y1 && i.value(m_yIndex) >= y2) {
// then is inside split so return true;
return true;
}
} else if (stmp.get(0).intValue() == 2) {
// then polygon
if (inPoly(stmp, i.value(m_xIndex), i.value(m_yIndex))) {
return true;
}
} else if (stmp.get(0).intValue() == 3) {
// then polyline
if (inPolyline(stmp, i.value(m_xIndex), i.value(m_yIndex))) {
return true;
}
}
}
}
return false;
}
/**
* Checks to see if the coordinate passed is inside the ployline passed,
* Note that this is done using attribute values and not there respective
* screen values.
*
* @param ob The polyline.
* @param x The x coord.
* @param y The y coord.
* @return True if it falls inside the polyline, false otherwise.
*/
private boolean inPolyline(ArrayList ob, double x, double y) {
// this works similar to the inPoly below except that
// the first and last lines are treated as extending infinite in one
// direction and
// then infinitly in the x dirction their is a line that will
// normaly be infinite but
// can be finite in one or both directions
int countx = 0;
double vecx, vecy;
double change;
double x1, y1, x2, y2;
for (int noa = 1; noa < ob.size() - 4; noa += 2) {
y1 = ob.get(noa + 1).doubleValue();
y2 = ob.get(noa + 3).doubleValue();
x1 = ob.get(noa).doubleValue();
x2 = ob.get(noa + 2).doubleValue();
// System.err.println(y1 + " " + y2 + " " + x1 + " " + x2);
vecy = y2 - y1;
vecx = x2 - x1;
if (noa == 1 && noa == ob.size() - 6) {
// then do special test first and last edge
if (vecy != 0) {
change = (y - y1) / vecy;
if (vecx * change + x1 >= x) {
// then intersection
countx++;
}
}
} else if (noa == 1) {
if ((y < y2 && vecy > 0) || (y > y2 && vecy < 0)) {
// now just determine intersection or not
change = (y - y1) / vecy;
if (vecx * change + x1 >= x) {
// then intersection on horiz
countx++;
}
}
} else if (noa == ob.size() - 6) {
// then do special test on last edge
if ((y <= y1 && vecy < 0) || (y >= y1 && vecy > 0)) {
change = (y - y1) / vecy;
if (vecx * change + x1 >= x) {
countx++;
}
}
} else if ((y1 <= y && y < y2) || (y2 < y && y <= y1)) {
// then continue tests.
if (vecy == 0) {
// then lines are parallel stop tests in
// ofcourse it should never make it this far
} else {
change = (y - y1) / vecy;
if (vecx * change + x1 >= x) {
// then intersects on horiz
countx++;
}
}
}
}
// now check for intersection with the infinity line
y1 = ob.get(ob.size() - 2).doubleValue();
y2 = ob.get(ob.size() - 1).doubleValue();
if (y1 > y2) {
// then normal line
if (y1 >= y && y > y2) {
countx++;
}
} else {
// then the line segment is inverted
if (y1 >= y || y > y2) {
countx++;
}
}
if ((countx % 2) == 1) {
return true;
} else {
return false;
}
}
/**
* This checks to see if The coordinate passed is inside the polygon that
* was passed.
*
* @param ob The polygon.
* @param x The x coord.
* @param y The y coord.
* @return True if the coordinate is in the polygon, false otherwise.
*/
private boolean inPoly(ArrayList ob, double x, double y) {
// brief on how this works
// it draws a line horizontally from the point to the right (infinitly)
// it then sees how many lines of the polygon intersect this,
// if it is even then the point is
// outside the polygon if it's odd then it's inside the polygon
int count = 0;
double vecx, vecy;
double change;
double x1, y1, x2, y2;
for (int noa = 1; noa < ob.size() - 2; noa += 2) {
y1 = ob.get(noa + 1).doubleValue();
y2 = ob.get(noa + 3).doubleValue();
if ((y1 <= y && y < y2) || (y2 < y && y <= y1)) {
// then continue tests.
vecy = y2 - y1;
if (vecy == 0) {
// then lines are parallel stop tests for this line
} else {
x1 = ob.get(noa).doubleValue();
x2 = ob.get(noa + 2).doubleValue();
vecx = x2 - x1;
change = (y - y1) / vecy;
if (vecx * change + x1 >= x) {
// then add to count as an intersected line
count++;
}
}
}
}
if ((count % 2) == 1) {
// then lies inside polygon
// System.out.println("in");
return true;
} else {
// System.out.println("out");
return false;
}
// System.out.println("WHAT?!?!?!?!!?!??!?!");
// return false;
}
/**
* Set level of jitter and repaint the plot using the new jitter value
*
* @param j the level of jitter
*/
public void setJitter(int j) {
m_plot2D.setJitter(j);
}
/**
* Set the index of the attribute to go on the x axis
*
* @param x the index of the attribute to use on the x axis
*/
public void setXindex(int x) {
// this just ensures that the shapes get disposed of
// if the attribs change
if (x != m_xIndex) {
cancelShapes();
}
m_xIndex = x;
m_plot2D.setXindex(x);
if (m_showAttBars) {
m_attrib.setX(x);
}
// this.repaint();
}
/**
* Set the index of the attribute to go on the y axis
*
* @param y the index of the attribute to use on the y axis
*/
public void setYindex(int y) {
// this just ensures that the shapes get disposed of
// if the attribs change
if (y != m_yIndex) {
cancelShapes();
}
m_yIndex = y;
m_plot2D.setYindex(y);
if (m_showAttBars) {
m_attrib.setY(y);
}
// this.repaint();
}
/**
* Set the index of the attribute to use for colouring
*
* @param c the index of the attribute to use for colouring
*/
public void setCindex(int c) {
m_cIndex = c;
m_plot2D.setCindex(c);
if (m_showAttBars) {
m_attrib.setCindex(c, m_plot2D.getMaxC(), m_plot2D.getMinC());
}
m_classPanel.setCindex(c);
this.repaint();
}
/**
* Set the index of the attribute to use for the shape.
*
* @param s the index of the attribute to use for the shape
*/
public void setSindex(int s) {
if (s != m_sIndex) {
m_shapePoints = null;
m_createShape = false;
}
m_sIndex = s;
this.repaint();
}
/**
* Clears all existing plots and sets a new master plot
*
* @param newPlot the new master plot
* @exception Exception if plot could not be added
*/
public void setMasterPlot(PlotData2D newPlot) throws Exception {
m_plot2D.removeAllPlots();
this.addPlot(newPlot);
}
/**
* Adds a plot. If there are no plots so far this plot becomes the master
* plot and, if it has a custom colour defined then the class panel is
* removed.
*
* @param newPlot the plot to add.
* @exception Exception if plot could not be added
*/
public void addPlot(PlotData2D newPlot) throws Exception {
if (m_plot2D.getPlots().size() == 0) {
m_plot2D.addPlot(newPlot);
if (m_plotSurround.getComponentCount() > 1
&& m_plotSurround.getComponent(1) == m_attrib && m_showAttBars) {
try {
m_attrib.setInstances(newPlot.m_plotInstances);
m_attrib.setCindex(0);
m_attrib.setX(0);
m_attrib.setY(0);
} catch (Exception ex) {
// more attributes than the panel can handle?
// Due to hard coded constraints in GridBagLayout
m_plotSurround.remove(m_attrib);
System.err.println("Warning : data contains more attributes "
+ "than can be displayed as attribute bars.");
if (m_Log != null) {
m_Log.logMessage("Warning : data contains more attributes "
+ "than can be displayed as attribute bars.");
}
}
} else if (m_showAttBars) {
try {
m_attrib.setInstances(newPlot.m_plotInstances);
m_attrib.setCindex(0);
m_attrib.setX(0);
m_attrib.setY(0);
GridBagConstraints constraints = new GridBagConstraints();
constraints.fill = GridBagConstraints.BOTH;
constraints.insets = new Insets(0, 0, 0, 0);
constraints.gridx = 4;
constraints.gridy = 0;
constraints.weightx = 1;
constraints.gridwidth = 1;
constraints.gridheight = 1;
constraints.weighty = 5;
m_plotSurround.add(m_attrib, constraints);
} catch (Exception ex) {
System.err.println("Warning : data contains more attributes "
+ "than can be displayed as attribute bars.");
if (m_Log != null) {
m_Log.logMessage("Warning : data contains more attributes "
+ "than can be displayed as attribute bars.");
}
}
}
m_classPanel.setInstances(newPlot.m_plotInstances);
plotReset(newPlot.m_plotInstances, newPlot.getCindex());
if (newPlot.m_useCustomColour && m_showClassPanel) {
VisualizePanel.this.remove(m_classSurround);
switchToLegend();
m_legendPanel.setPlotList(m_plot2D.getPlots());
m_ColourCombo.setEnabled(false);
}
} else {
if (!newPlot.m_useCustomColour && m_showClassPanel) {
VisualizePanel.this.add(m_classSurround, BorderLayout.SOUTH);
m_ColourCombo.setEnabled(true);
}
if (m_plot2D.getPlots().size() == 1) {
switchToLegend();
}
m_plot2D.addPlot(newPlot);
m_legendPanel.setPlotList(m_plot2D.getPlots());
}
}
/**
* Remove the attibute panel and replace it with the legend panel
*/
protected void switchToLegend() {
if (m_plotSurround.getComponentCount() > 1
&& m_plotSurround.getComponent(1) == m_attrib) {
m_plotSurround.remove(m_attrib);
}
if (m_plotSurround.getComponentCount() > 1
&& m_plotSurround.getComponent(1) == m_legendPanel) {
return;
}
GridBagConstraints constraints = new GridBagConstraints();
constraints.fill = GridBagConstraints.BOTH;
constraints.insets = new Insets(0, 0, 0, 0);
constraints.gridx = 4;
constraints.gridy = 0;
constraints.weightx = 1;
constraints.gridwidth = 1;
constraints.gridheight = 1;
constraints.weighty = 5;
m_plotSurround.add(m_legendPanel, constraints);
setSindex(0);
m_ShapeCombo.setEnabled(false);
}
protected void switchToBars() {
if (m_plotSurround.getComponentCount() > 1
&& m_plotSurround.getComponent(1) == m_legendPanel) {
m_plotSurround.remove(m_legendPanel);
}
if (m_plotSurround.getComponentCount() > 1
&& m_plotSurround.getComponent(1) == m_attrib) {
return;
}
if (m_showAttBars) {
try {
m_attrib.setInstances(m_plot2D.getMasterPlot().m_plotInstances);
m_attrib.setCindex(0);
m_attrib.setX(0);
m_attrib.setY(0);
GridBagConstraints constraints = new GridBagConstraints();
constraints.fill = GridBagConstraints.BOTH;
constraints.insets = new Insets(0, 0, 0, 0);
constraints.gridx = 4;
constraints.gridy = 0;
constraints.weightx = 1;
constraints.gridwidth = 1;
constraints.gridheight = 1;
constraints.weighty = 5;
m_plotSurround.add(m_attrib, constraints);
} catch (Exception ex) {
System.err.println("Warning : data contains more attributes "
+ "than can be displayed as attribute bars.");
if (m_Log != null) {
m_Log.logMessage("Warning : data contains more attributes "
+ "than can be displayed as attribute bars.");
}
}
}
}
/**
* Reset the visualize panel's buttons and the plot panels instances
*
* @param inst the data
* @param cIndex the color index
*/
private void plotReset(Instances inst, int cIndex) {
if (m_splitListener == null) {
m_submit.setText("Reset");
m_submit.setActionCommand("Reset");
// if (m_origInstances == null || m_origInstances == inst) {
if (m_originalPlot == null || m_originalPlot.m_plotInstances == inst) {
m_submit.setEnabled(false);
} else {
m_submit.setEnabled(true);
}
} else {
m_submit.setEnabled(false);
}
m_plotInstances = inst;
if (m_splitListener != null) {
m_plotInstances.randomize(new Random());
}
m_xIndex = 0;
m_yIndex = 0;
m_cIndex = cIndex;
cancelShapes();
}
/**
* Set a list of colours to use for plotting points
*
* @param cols a list of java.awt.Colors
*/
public void setColours(ArrayList cols) {
m_plot2D.setColours(cols);
m_colorList = cols;
}
/**
* This will draw the shapes created onto the panel. For best visual, this
* should be the first thing to be drawn (and it currently is).
*
* @param gx The graphics context.
*/
private void drawShapes(Graphics gx) {
// FastVector tmp = m_plot.getShapes();
if (m_shapes != null) {
ArrayList stmp;
int x1, y1, x2, y2;
for (int noa = 0; noa < m_shapes.size(); noa++) {
stmp = m_shapes.get(noa);
if (stmp.get(0).intValue() == 1) {
// then rectangle
x1 = (int) m_plot2D.convertToPanelX(stmp.get(1).doubleValue());
y1 = (int) m_plot2D.convertToPanelY(stmp.get(2).doubleValue());
x2 = (int) m_plot2D.convertToPanelX(stmp.get(3).doubleValue());
y2 = (int) m_plot2D.convertToPanelY(stmp.get(4).doubleValue());
gx.setColor(Color.gray);
gx.fillRect(x1, y1, x2 - x1, y2 - y1);
gx.setColor(Color.black);
gx.drawRect(x1, y1, x2 - x1, y2 - y1);
} else if (stmp.get(0).intValue() == 2) {
// then polygon
int[] ar1, ar2;
ar1 = getXCoords(stmp);
ar2 = getYCoords(stmp);
gx.setColor(Color.gray);
gx.fillPolygon(ar1, ar2, (stmp.size() - 1) / 2);
gx.setColor(Color.black);
gx.drawPolyline(ar1, ar2, (stmp.size() - 1) / 2);
} else if (stmp.get(0).intValue() == 3) {
// then polyline
int[] ar1, ar2;
ArrayList tmp = makePolygon(stmp);
ar1 = getXCoords(tmp);
ar2 = getYCoords(tmp);
gx.setColor(Color.gray);
gx.fillPolygon(ar1, ar2, (tmp.size() - 1) / 2);
gx.setColor(Color.black);
gx.drawPolyline(ar1, ar2, (tmp.size() - 1) / 2);
}
}
}
if (m_shapePoints != null) {
// then the current image needs to be refreshed
if (m_shapePoints.get(0).intValue() == 2
|| m_shapePoints.get(0).intValue() == 3) {
gx.setColor(Color.black);
gx.setXORMode(Color.white);
int[] ar1, ar2;
ar1 = getXCoords(m_shapePoints);
ar2 = getYCoords(m_shapePoints);
gx.drawPolyline(ar1, ar2, (m_shapePoints.size() - 1) / 2);
m_newMousePos.width = (int) Math.ceil(m_plot2D
.convertToPanelX(m_shapePoints.get(m_shapePoints.size() - 2)
.doubleValue()));
m_newMousePos.height = (int) Math.ceil(m_plot2D
.convertToPanelY(m_shapePoints.get(m_shapePoints.size() - 1)
.doubleValue()));
gx.drawLine(
(int) Math.ceil(m_plot2D.convertToPanelX(m_shapePoints.get(
m_shapePoints.size() - 2).doubleValue())),
(int) Math.ceil(m_plot2D.convertToPanelY(m_shapePoints.get(
m_shapePoints.size() - 1).doubleValue())), m_newMousePos.width,
m_newMousePos.height);
gx.setPaintMode();
}
}
}
/**
* This is called for polylines to see where there two lines that extend to
* infinity cut the border of the view.
*
* @param x1 an x point along the line
* @param y1 the accompanying y point.
* @param x2 The x coord of the end point of the line.
* @param y2 The y coord of the end point of the line.
* @param x 0 or the width of the border line if it has one.
* @param y 0 or the height of the border line if it has one.
* @param offset The offset for the border line (either for x or y dependant
* on which one doesn't change).
* @return double array that contains the coordinate for the point that the
* polyline cuts the border (which ever side that may be).
*/
private double[] lineIntersect(double x1, double y1, double x2, double y2,
double x, double y, double offset) {
// the first 4 params are thestart and end points of a line
// the next param is either 0 for no change in x or change in x,
// the next param is the same for y
// the final 1 is the offset for either x or y (which ever has no change)
double xval;
double yval;
double xn = -100, yn = -100;
double change;
if (x == 0) {
if ((x1 <= offset && offset < x2) || (x1 >= offset && offset > x2)) {
// then continue
xval = x1 - x2;
change = (offset - x2) / xval;
yn = (y1 - y2) * change + y2;
if (0 <= yn && yn <= y) {
// then good
xn = offset;
} else {
// no intersect
xn = -100;
}
}
} else if (y == 0) {
if ((y1 <= offset && offset < y2) || (y1 >= offset && offset > y2)) {
// the continue
yval = (y1 - y2);
change = (offset - y2) / yval;
xn = (x1 - x2) * change + x2;
if (0 <= xn && xn <= x) {
// then good
yn = offset;
} else {
xn = -100;
}
}
}
double[] ret = new double[2];
ret[0] = xn;
ret[1] = yn;
return ret;
}
/**
* This will convert a polyline to a polygon for drawing purposes So that I
* can simply use the polygon drawing function.
*
* @param v The polyline to convert.
* @return A FastVector containing the polygon.
*/
private ArrayList makePolygon(ArrayList v) {
ArrayList building = new ArrayList(v.size() + 10);
double x1, y1, x2, y2;
int edge1 = 0, edge2 = 0;
for (int noa = 0; noa < v.size() - 2; noa++) {
building.add(new Double(v.get(noa).doubleValue()));
}
// now clip the lines
double[] new_coords;
// note lineIntersect , expects the values to have been converted to
// screen coords
// note the first point passed is the one that gets shifted.
x1 = m_plot2D.convertToPanelX(v.get(1).doubleValue());
y1 = m_plot2D.convertToPanelY(v.get(2).doubleValue());
x2 = m_plot2D.convertToPanelX(v.get(3).doubleValue());
y2 = m_plot2D.convertToPanelY(v.get(4).doubleValue());
if (x1 < 0) {
// test left
new_coords = lineIntersect(x1, y1, x2, y2, 0, this.getHeight(), 0);
edge1 = 0;
if (new_coords[0] < 0) {
// then not left
if (y1 < 0) {
// test top
new_coords = lineIntersect(x1, y1, x2, y2, this.getWidth(), 0, 0);
edge1 = 1;
} else {
// test bottom
new_coords = lineIntersect(x1, y1, x2, y2, this.getWidth(), 0,
this.getHeight());
edge1 = 3;
}
}
} else if (x1 > this.getWidth()) {
// test right
new_coords = lineIntersect(x1, y1, x2, y2, 0, this.getHeight(),
this.getWidth());
edge1 = 2;
if (new_coords[0] < 0) {
// then not right
if (y1 < 0) {
// test top
new_coords = lineIntersect(x1, y1, x2, y2, this.getWidth(), 0, 0);
edge1 = 1;
} else {
// test bottom
new_coords = lineIntersect(x1, y1, x2, y2, this.getWidth(), 0,
this.getHeight());
edge1 = 3;
}
}
} else if (y1 < 0) {
// test top
new_coords = lineIntersect(x1, y1, x2, y2, this.getWidth(), 0, 0);
edge1 = 1;
} else {
// test bottom
new_coords = lineIntersect(x1, y1, x2, y2, this.getWidth(), 0,
this.getHeight());
edge1 = 3;
}
building.set(1, new Double(m_plot2D.convertToAttribX(new_coords[0])));
building.set(2, new Double(m_plot2D.convertToAttribY(new_coords[1])));
x1 = m_plot2D.convertToPanelX(v.get(v.size() - 4).doubleValue());
y1 = m_plot2D.convertToPanelY(v.get(v.size() - 3).doubleValue());
x2 = m_plot2D.convertToPanelX(v.get(v.size() - 6).doubleValue());
y2 = m_plot2D.convertToPanelY(v.get(v.size() - 5).doubleValue());
if (x1 < 0) {
// test left
new_coords = lineIntersect(x1, y1, x2, y2, 0, this.getHeight(), 0);
edge2 = 0;
if (new_coords[0] < 0) {
// then not left
if (y1 < 0) {
// test top
new_coords = lineIntersect(x1, y1, x2, y2, this.getWidth(), 0, 0);
edge2 = 1;
} else {
// test bottom
new_coords = lineIntersect(x1, y1, x2, y2, this.getWidth(), 0,
this.getHeight());
edge2 = 3;
}
}
} else if (x1 > this.getWidth()) {
// test right
new_coords = lineIntersect(x1, y1, x2, y2, 0, this.getHeight(),
this.getWidth());
edge2 = 2;
if (new_coords[0] < 0) {
// then not right
if (y1 < 0) {
// test top
new_coords = lineIntersect(x1, y1, x2, y2, this.getWidth(), 0, 0);
edge2 = 1;
} else {
// test bottom
new_coords = lineIntersect(x1, y1, x2, y2, this.getWidth(), 0,
this.getHeight());
edge2 = 3;
}
}
} else if (y1 < 0) {
// test top
new_coords = lineIntersect(x1, y1, x2, y2, this.getWidth(), 0, 0);
edge2 = 1;
} else {
// test bottom
new_coords = lineIntersect(x1, y1, x2, y2, this.getWidth(), 0,
this.getHeight());
edge2 = 3;
}
building.set(building.size() - 2,
new Double(m_plot2D.convertToAttribX(new_coords[0])));
building.set(building.size() - 1,
new Double(m_plot2D.convertToAttribY(new_coords[1])));
// trust me this complicated piece of code will
// determine what points on the boundary of the view to add to the polygon
int xp, yp;
xp = this.getWidth() * ((edge2 & 1) ^ ((edge2 & 2) / 2));
yp = this.getHeight() * ((edge2 & 2) / 2);
// System.out.println(((-1 + 4) % 4) + " hoi");
if (inPolyline(v, m_plot2D.convertToAttribX(xp),
m_plot2D.convertToAttribY(yp))) {
// then add points in a clockwise direction
building.add(new Double(m_plot2D.convertToAttribX(xp)));
building.add(new Double(m_plot2D.convertToAttribY(yp)));
for (int noa = (edge2 + 1) % 4; noa != edge1; noa = (noa + 1) % 4) {
xp = this.getWidth() * ((noa & 1) ^ ((noa & 2) / 2));
yp = this.getHeight() * ((noa & 2) / 2);
building.add(new Double(m_plot2D.convertToAttribX(xp)));
building.add(new Double(m_plot2D.convertToAttribY(yp)));
}
} else {
xp = this.getWidth() * ((edge2 & 2) / 2);
yp = this.getHeight() * (1 & ~((edge2 & 1) ^ ((edge2 & 2) / 2)));
if (inPolyline(v, m_plot2D.convertToAttribX(xp),
m_plot2D.convertToAttribY(yp))) {
// then add points in anticlockwise direction
building.add(new Double(m_plot2D.convertToAttribX(xp)));
building.add(new Double(m_plot2D.convertToAttribY(yp)));
for (int noa = (edge2 + 3) % 4; noa != edge1; noa = (noa + 3) % 4) {
xp = this.getWidth() * ((noa & 2) / 2);
yp = this.getHeight() * (1 & ~((noa & 1) ^ ((noa & 2) / 2)));
building.add(new Double(m_plot2D.convertToAttribX(xp)));
building.add(new Double(m_plot2D.convertToAttribY(yp)));
}
}
}
return building;
}
/**
* This will extract from a polygon shape its x coodrdinates so that an
* awt.Polygon can be created.
*
* @param v The polygon shape.
* @return an int array containing the screen x coords for the polygon.
*/
private int[] getXCoords(ArrayList v) {
int cach = (v.size() - 1) / 2;
int[] ar = new int[cach];
for (int noa = 0; noa < cach; noa++) {
ar[noa] = (int) m_plot2D.convertToPanelX(v.get(noa * 2 + 1)
.doubleValue());
}
return ar;
}
/**
* This will extract from a polygon shape its y coordinates so that an
* awt.Polygon can be created.
*
* @param v The polygon shape.
* @return an int array containing the screen y coords for the polygon.
*/
private int[] getYCoords(ArrayList v) {
int cach = (v.size() - 1) / 2;
int[] ar = new int[cach];
for (int noa = 0; noa < cach; noa++) {
ar[noa] = (int) m_plot2D.convertToPanelY(v.get(noa * 2 + 2)
.doubleValue());
}
return ar;
}
/**
* Renders the polygons if necessary
*
* @param gx the graphics context
*/
@Override
public void prePlot(Graphics gx) {
super.paintComponent(gx);
if (m_plotInstances != null) {
drawShapes(gx); // will be in paintComponent of ShapePlot2D
}
}
}
/** default colours for colouring discrete class */
protected Color[] m_DefaultColors = { Color.blue, Color.red, Color.green,
Color.cyan, Color.pink, new Color(255, 0, 255), Color.orange,
new Color(255, 0, 0), new Color(0, 255, 0), Color.white };
/** Lets the user select the attribute for the x axis */
protected JComboBox m_XCombo = new JComboBox();
/** Lets the user select the attribute for the y axis */
protected JComboBox m_YCombo = new JComboBox();
/** Lets the user select the attribute to use for colouring */
protected JComboBox m_ColourCombo = new JComboBox();
/**
* Lets the user select the shape they want to create for instance selection.
*/
protected JComboBox m_ShapeCombo = new JComboBox();
/** Button for the user to enter the splits. */
protected JButton m_submit = new JButton("Submit");
/** Button for the user to remove all splits. */
protected JButton m_cancel = new JButton("Clear");
/** Button for the user to open the visualized set of instances */
protected JButton m_openBut = new JButton("Open");
/** Button for the user to save the visualized set of instances */
protected JButton m_saveBut = new JButton("Save");
/** Stop the combos from growing out of control */
private final Dimension COMBO_SIZE = new Dimension(250,
m_saveBut.getPreferredSize().height);
/** file chooser for saving instances */
protected JFileChooser m_FileChooser = new JFileChooser(new File(
System.getProperty("user.dir")));
/** Filter to ensure only arff files are selected */
protected FileFilter m_ArffFilter = new ExtensionFileFilter(
Instances.FILE_EXTENSION, "Arff data files");
/** Label for the jitter slider */
protected JLabel m_JitterLab = new JLabel("Jitter", SwingConstants.RIGHT);
/** The jitter slider */
protected JSlider m_Jitter = new JSlider(0, 50, 0);
/** The panel that displays the plot */
protected PlotPanel m_plot = new PlotPanel();
/**
* The panel that displays the attributes , using color to represent another
* attribute.
*/
protected AttributePanel m_attrib = new AttributePanel(
m_plot.m_plot2D.getBackground());
/** The panel that displays legend info if there is more than one plot */
protected LegendPanel m_legendPanel = new LegendPanel();
/** Panel that surrounds the plot panel with a titled border */
protected JPanel m_plotSurround = new JPanel();
/** Panel that surrounds the class panel with a titled border */
protected JPanel m_classSurround = new JPanel();
/**
* An optional listener that we will inform when ComboBox selections change
*/
protected ActionListener listener = null;
/**
* An optional listener that we will inform when the user creates a split to
* seperate instances.
*/
protected VisualizePanelListener m_splitListener = null;
/**
* The name of the plot (not currently displayed, but can be used in the
* containing Frame or Panel)
*/
protected String m_plotName = "";
/** The panel that displays the legend for the colouring attribute */
protected ClassPanel m_classPanel = new ClassPanel(
m_plot.m_plot2D.getBackground());
/** The list of the colors used */
protected ArrayList m_colorList;
/**
* These hold the names of preferred columns to visualize on---if the user has
* defined them in the Visualize.props file
*/
protected String m_preferredXDimension = null;
protected String m_preferredYDimension = null;
protected String m_preferredColourDimension = null;
/** Show the attribute bar panel */
protected boolean m_showAttBars = true;
/** Show the class panel **/
protected boolean m_showClassPanel = true;
/** the logger */
protected Logger m_Log;
/**
* Sets the Logger to receive informational messages
*
* @param newLog the Logger that will now get info messages
*/
public void setLog(Logger newLog) {
m_Log = newLog;
}
/**
* Set whether the attribute bars should be shown or not. If turned off via
* this method then any setting in the properties file (if exists) is ignored.
*
* @param sab false if attribute bars are not to be displayed.
*/
public void setShowAttBars(boolean sab) {
if (!sab && m_showAttBars) {
m_plotSurround.remove(m_attrib);
} else if (sab && !m_showAttBars) {
GridBagConstraints constraints = new GridBagConstraints();
constraints.insets = new Insets(0, 0, 0, 0);
constraints.gridx = 4;
constraints.gridy = 0;
constraints.weightx = 1;
constraints.gridwidth = 1;
constraints.gridheight = 1;
constraints.weighty = 5;
m_plotSurround.add(m_attrib, constraints);
}
m_showAttBars = sab;
repaint();
}
/**
* Gets whether or not attribute bars are being displayed.
*
* @return true if attribute bars are being displayed.
*/
public boolean getShowAttBars() {
return m_showAttBars;
}
/**
* Set whether the class panel should be shown or not.
*
* @param scp false if class panel is not to be displayed
*/
public void setShowClassPanel(boolean scp) {
if (!scp && m_showClassPanel) {
remove(m_classSurround);
} else if (scp && !m_showClassPanel) {
add(m_classSurround, BorderLayout.SOUTH);
}
m_showClassPanel = scp;
repaint();
}
/**
* Gets whether or not the class panel is being displayed.
*
* @return true if the class panel is being displayed.
*/
public boolean getShowClassPanel() {
return m_showClassPanel;
}
/**
* This constructor allows a VisualizePanelListener to be set.
*
* @param ls the listener to use
*/
public VisualizePanel(VisualizePanelListener ls) {
this();
m_splitListener = ls;
}
/**
* Set the properties for the VisualizePanel
*
* @param relationName the name of the relation, can be null
*/
private void setProperties(String relationName) {
if (VisualizeUtils.VISUALIZE_PROPERTIES != null) {
String thisClass = this.getClass().getName();
if (relationName == null) {
String showAttBars = thisClass + ".displayAttributeBars";
String val = VisualizeUtils.VISUALIZE_PROPERTIES
.getProperty(showAttBars);
if (val == null) {
// System.err.println("Displaying attribute bars ");
// m_showAttBars = true;
} else {
// only check if this hasn't been turned off programatically
if (m_showAttBars) {
if (val.compareTo("true") == 0 || val.compareTo("on") == 0) {
// System.err.println("Displaying attribute bars ");
m_showAttBars = true;
} else {
m_showAttBars = false;
}
}
}
} else {
/*
* System.err.println("Looking for preferred visualization dimensions for "
* +relationName);
*/
String xcolKey = thisClass + "." + relationName + ".XDimension";
String ycolKey = thisClass + "." + relationName + ".YDimension";
String ccolKey = thisClass + "." + relationName + ".ColourDimension";
m_preferredXDimension = VisualizeUtils.VISUALIZE_PROPERTIES
.getProperty(xcolKey);
/*
* if (m_preferredXDimension == null) {
* System.err.println("No preferred X dimension found in "
* +VisualizeUtils.PROPERTY_FILE +" for "+xcolKey); } else {
* System.err.println("Setting preferred X dimension to "
* +m_preferredXDimension); }
*/
m_preferredYDimension = VisualizeUtils.VISUALIZE_PROPERTIES
.getProperty(ycolKey);
/*
* if (m_preferredYDimension == null) {
* System.err.println("No preferred Y dimension found in "
* +VisualizeUtils.PROPERTY_FILE +" for "+ycolKey); } else {
* System.err.println("Setting preferred dimension Y to "
* +m_preferredYDimension); }
*/
m_preferredColourDimension = VisualizeUtils.VISUALIZE_PROPERTIES
.getProperty(ccolKey);
/*
* if (m_preferredColourDimension == null) {
* System.err.println("No preferred Colour dimension found in "
* +VisualizeUtils.PROPERTY_FILE +" for "+ycolKey); } else {
* System.err.println("Setting preferred Colour dimension to "
* +m_preferredColourDimension); }
*/
}
}
}
/**
* Constructor
*/
public VisualizePanel() {
super();
setProperties(null);
m_FileChooser.setFileFilter(m_ArffFilter);
m_FileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
m_XCombo.setToolTipText("Select the attribute for the x axis");
m_YCombo.setToolTipText("Select the attribute for the y axis");
m_ColourCombo.setToolTipText("Select the attribute to colour on");
m_ShapeCombo.setToolTipText("Select the shape to use for data selection");
m_XCombo.setPreferredSize(COMBO_SIZE);
m_YCombo.setPreferredSize(COMBO_SIZE);
m_ColourCombo.setPreferredSize(COMBO_SIZE);
m_ShapeCombo.setPreferredSize(COMBO_SIZE);
m_XCombo.setMaximumSize(COMBO_SIZE);
m_YCombo.setMaximumSize(COMBO_SIZE);
m_ColourCombo.setMaximumSize(COMBO_SIZE);
m_ShapeCombo.setMaximumSize(COMBO_SIZE);
m_XCombo.setMinimumSize(COMBO_SIZE);
m_YCombo.setMinimumSize(COMBO_SIZE);
m_ColourCombo.setMinimumSize(COMBO_SIZE);
m_ShapeCombo.setMinimumSize(COMBO_SIZE);
// ////////
m_XCombo.setEnabled(false);
m_YCombo.setEnabled(false);
m_ColourCombo.setEnabled(false);
m_ShapeCombo.setEnabled(false);
// tell the class panel and the legend panel that we want to know when
// colours change
m_classPanel.addRepaintNotify(this);
m_legendPanel.addRepaintNotify(this);
// Check the default colours against the background colour of the
// plot panel. If any are equal to the background colour then
// change them (so they are visible :-)
for (int i = 0; i < m_DefaultColors.length; i++) {
Color c = m_DefaultColors[i];
if (c.equals(m_plot.m_plot2D.getBackground())) {
int red = c.getRed();
int blue = c.getBlue();
int green = c.getGreen();
red += (red < 128) ? (255 - red) / 2 : -(red / 2);
blue += (blue < 128) ? (blue - red) / 2 : -(blue / 2);
green += (green < 128) ? (255 - green) / 2 : -(green / 2);
m_DefaultColors[i] = new Color(red, green, blue);
}
}
m_classPanel.setDefaultColourList(m_DefaultColors);
m_attrib.setDefaultColourList(m_DefaultColors);
m_colorList = new ArrayList(10);
for (int noa = m_colorList.size(); noa < 10; noa++) {
Color pc = m_DefaultColors[noa % 10];
int ija = noa / 10;
ija *= 2;
for (int j = 0; j < ija; j++) {
pc = pc.darker();
}
m_colorList.add(pc);
}
m_plot.setColours(m_colorList);
m_classPanel.setColours(m_colorList);
m_attrib.setColours(m_colorList);
m_attrib.addAttributePanelListener(new AttributePanelListener() {
@Override
public void attributeSelectionChange(AttributePanelEvent e) {
if (e.m_xChange) {
m_XCombo.setSelectedIndex(e.m_indexVal);
} else {
m_YCombo.setSelectedIndex(e.m_indexVal);
}
}
});
m_XCombo.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
int selected = m_XCombo.getSelectedIndex();
if (selected < 0) {
selected = 0;
}
m_plot.setXindex(selected);
// try sending on the event if anyone is listening
if (listener != null) {
listener.actionPerformed(e);
}
}
});
m_YCombo.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
int selected = m_YCombo.getSelectedIndex();
if (selected < 0) {
selected = 0;
}
m_plot.setYindex(selected);
// try sending on the event if anyone is listening
if (listener != null) {
listener.actionPerformed(e);
}
}
});
m_ColourCombo.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
int selected = m_ColourCombo.getSelectedIndex();
if (selected < 0) {
selected = 0;
}
m_plot.setCindex(selected);
if (listener != null) {
listener.actionPerformed(e);
}
}
});
// /////
m_ShapeCombo.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
int selected = m_ShapeCombo.getSelectedIndex();
if (selected < 0) {
selected = 0;
}
m_plot.setSindex(selected);
// try sending on the event if anyone is listening
if (listener != null) {
listener.actionPerformed(e);
}
}
});
// /////////////////////////////////////
m_Jitter.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
m_plot.setJitter(m_Jitter.getValue());
}
});
m_openBut.setToolTipText("Loads previously saved instances from a file");
m_openBut.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
openVisibleInstances();
}
});
m_saveBut.setEnabled(false);
m_saveBut.setToolTipText("Save the visible instances to a file");
m_saveBut.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
saveVisibleInstances();
}
});
JPanel combos = new JPanel();
GridBagLayout gb = new GridBagLayout();
GridBagConstraints constraints = new GridBagConstraints();
m_XCombo.setLightWeightPopupEnabled(false);
m_YCombo.setLightWeightPopupEnabled(false);
m_ColourCombo.setLightWeightPopupEnabled(false);
m_ShapeCombo.setLightWeightPopupEnabled(false);
combos.setBorder(BorderFactory.createEmptyBorder(10, 5, 10, 5));
combos.setLayout(gb);
constraints.gridx = 0;
constraints.gridy = 0;
constraints.weightx = 5;
constraints.fill = GridBagConstraints.HORIZONTAL;
constraints.gridwidth = 2;
constraints.gridheight = 1;
constraints.insets = new Insets(0, 2, 0, 2);
combos.add(m_XCombo, constraints);
constraints.gridx = 2;
constraints.gridy = 0;
constraints.weightx = 5;
constraints.gridwidth = 2;
constraints.gridheight = 1;
combos.add(m_YCombo, constraints);
constraints.gridx = 0;
constraints.gridy = 1;
constraints.weightx = 5;
constraints.gridwidth = 2;
constraints.gridheight = 1;
combos.add(m_ColourCombo, constraints);
//
constraints.gridx = 2;
constraints.gridy = 1;
constraints.weightx = 5;
constraints.gridwidth = 2;
constraints.gridheight = 1;
combos.add(m_ShapeCombo, constraints);
JPanel mbts = new JPanel();
mbts.setLayout(new GridLayout(1, 4));
mbts.add(m_submit);
mbts.add(m_cancel);
mbts.add(m_openBut);
mbts.add(m_saveBut);
constraints.gridx = 0;
constraints.gridy = 2;
constraints.weightx = 5;
constraints.gridwidth = 2;
constraints.gridheight = 1;
combos.add(mbts, constraints);
// //////////////////////////////
constraints.gridx = 2;
constraints.gridy = 2;
constraints.weightx = 5;
constraints.gridwidth = 1;
constraints.gridheight = 1;
constraints.insets = new Insets(10, 0, 0, 5);
combos.add(m_JitterLab, constraints);
constraints.gridx = 3;
constraints.gridy = 2;
constraints.weightx = 5;
constraints.insets = new Insets(10, 0, 0, 0);
combos.add(m_Jitter, constraints);
m_classSurround = new JPanel();
m_classSurround.setBorder(BorderFactory.createTitledBorder("Class colour"));
m_classSurround.setLayout(new BorderLayout());
m_classPanel.setBorder(BorderFactory.createEmptyBorder(15, 10, 10, 10));
m_classSurround.add(m_classPanel, BorderLayout.CENTER);
GridBagLayout gb2 = new GridBagLayout();
m_plotSurround.setBorder(BorderFactory.createTitledBorder("Plot"));
m_plotSurround.setLayout(gb2);
constraints.fill = GridBagConstraints.BOTH;
constraints.insets = new Insets(0, 0, 0, 10);
constraints.gridx = 0;
constraints.gridy = 0;
constraints.weightx = 3;
constraints.gridwidth = 4;
constraints.gridheight = 1;
constraints.weighty = 5;
m_plotSurround.add(m_plot, constraints);
if (m_showAttBars) {
constraints.insets = new Insets(0, 0, 0, 0);
constraints.gridx = 4;
constraints.gridy = 0;
constraints.weightx = 1;
constraints.gridwidth = 1;
constraints.gridheight = 1;
constraints.weighty = 5;
m_plotSurround.add(m_attrib, constraints);
}
setLayout(new BorderLayout());
add(combos, BorderLayout.NORTH);
add(m_plotSurround, BorderLayout.CENTER);
add(m_classSurround, BorderLayout.SOUTH);
String[] SNames = new String[4];
SNames[0] = "Select Instance";
SNames[1] = "Rectangle";
SNames[2] = "Polygon";
SNames[3] = "Polyline";
m_ShapeCombo.setModel(new DefaultComboBoxModel(SNames));
m_ShapeCombo.setEnabled(true);
}
/**
* displays the previously saved instances
*
* @param insts the instances to display
* @throws Exception if display is not possible
*/
protected void openVisibleInstances(Instances insts) throws Exception {
PlotData2D tempd = new PlotData2D(insts);
tempd.setPlotName(insts.relationName());
tempd.addInstanceNumberAttribute();
m_plot.m_plot2D.removeAllPlots();
addPlot(tempd);
// modify title
Component parent = getParent();
while (parent != null) {
if (parent instanceof JFrame) {
((JFrame) parent).setTitle("Weka Classifier Visualize: "
+ insts.relationName() + " (display only)");
break;
} else {
parent = parent.getParent();
}
}
}
/**
* Loads previously saved instances from a file
*/
protected void openVisibleInstances() {
try {
int returnVal = m_FileChooser.showOpenDialog(this);
if (returnVal == JFileChooser.APPROVE_OPTION) {
File sFile = m_FileChooser.getSelectedFile();
if (!sFile.getName().toLowerCase().endsWith(Instances.FILE_EXTENSION)) {
sFile = new File(sFile.getParent(), sFile.getName()
+ Instances.FILE_EXTENSION);
}
File selected = sFile;
Instances insts = new Instances(new BufferedReader(new FileReader(
selected)));
openVisibleInstances(insts);
}
} catch (Exception ex) {
ex.printStackTrace();
m_plot.m_plot2D.removeAllPlots();
JOptionPane.showMessageDialog(this, ex.getMessage(),
"Error loading file...", JOptionPane.ERROR_MESSAGE);
}
}
/**
* Save the currently visible set of instances to a file
*/
private void saveVisibleInstances() {
ArrayList plots = m_plot.m_plot2D.getPlots();
if (plots != null) {
PlotData2D master = plots.get(0);
Instances saveInsts = new Instances(master.getPlotInstances());
for (int i = 1; i < plots.size(); i++) {
PlotData2D temp = plots.get(i);
Instances addInsts = temp.getPlotInstances();
for (int j = 0; j < addInsts.numInstances(); j++) {
saveInsts.add(addInsts.instance(j));
}
}
try {
int returnVal = m_FileChooser.showSaveDialog(this);
if (returnVal == JFileChooser.APPROVE_OPTION) {
File sFile = m_FileChooser.getSelectedFile();
if (!sFile.getName().toLowerCase().endsWith(Instances.FILE_EXTENSION)) {
sFile = new File(sFile.getParent(), sFile.getName()
+ Instances.FILE_EXTENSION);
}
File selected = sFile;
Writer w = new BufferedWriter(new FileWriter(selected));
w.write(saveInsts.toString());
w.close();
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
/**
* Sets the index used for colouring. If this method is called then the
* supplied index is used and the combo box for selecting colouring attribute
* is disabled.
*
* @param index the index of the attribute to use for colouring
*/
public void setColourIndex(int index) {
if (index >= 0) {
m_ColourCombo.setSelectedIndex(index);
} else {
m_ColourCombo.setSelectedIndex(0);
}
m_ColourCombo.setEnabled(false);
}
/**
* Set the index of the attribute for the x axis
*
* @param index the index for the x axis
* @exception Exception if index is out of range.
*/
public void setXIndex(int index) throws Exception {
if (index >= 0 && index < m_XCombo.getItemCount()) {
m_XCombo.setSelectedIndex(index);
} else {
throw new Exception("x index is out of range!");
}
}
/**
* Get the index of the attribute on the x axis
*
* @return the index of the attribute on the x axis
*/
public int getXIndex() {
return m_XCombo.getSelectedIndex();
}
/**
* Set the index of the attribute for the y axis
*
* @param index the index for the y axis
* @exception Exception if index is out of range.
*/
public void setYIndex(int index) throws Exception {
if (index >= 0 && index < m_YCombo.getItemCount()) {
m_YCombo.setSelectedIndex(index);
} else {
throw new Exception("y index is out of range!");
}
}
/**
* Get the index of the attribute on the y axis
*
* @return the index of the attribute on the x axis
*/
public int getYIndex() {
return m_YCombo.getSelectedIndex();
}
/**
* Get the index of the attribute selected for coloring
*
* @return the index of the attribute on the x axis
*/
public int getCIndex() {
return m_ColourCombo.getSelectedIndex();
}
/**
* Get the index of the shape selected for creating splits.
*
* @return The index of the shape.
*/
public int getSIndex() {
return m_ShapeCombo.getSelectedIndex();
}
/**
* Set the shape for creating splits.
*
* @param index The index of the shape.
* @exception Exception if index is out of range.
*/
public void setSIndex(int index) throws Exception {
if (index >= 0 && index < m_ShapeCombo.getItemCount()) {
m_ShapeCombo.setSelectedIndex(index);
} else {
throw new Exception("s index is out of range!");
}
}
/**
* Add a listener for this visualize panel
*
* @param act an ActionListener
*/
public void addActionListener(ActionListener act) {
listener = act;
}
/**
* Set a name for this plot
*
* @param plotName the name for the plot
*/
@Override
public void setName(String plotName) {
m_plotName = plotName;
}
/**
* Returns the name associated with this plot. "" is returned if no name is
* set.
*
* @return the name of the plot
*/
@Override
public String getName() {
return m_plotName;
}
/**
* Get the master plot's instances
*
* @return the master plot's instances
*/
public Instances getInstances() {
return m_plot.m_plotInstances;
}
/**
* Sets the Colors in use for a different attrib if it is not a nominal attrib
* and or does not have more possible values then this will do nothing.
* otherwise it will add default colors to see that there is a color for the
* attrib to begin with.
*
* @param a The index of the attribute to color.
* @param i The instances object that contains the attribute.
*/
protected void newColorAttribute(int a, Instances i) {
if (i.attribute(a).isNominal()) {
for (int noa = m_colorList.size(); noa < i.attribute(a).numValues(); noa++) {
Color pc = m_DefaultColors[noa % 10];
int ija = noa / 10;
ija *= 2;
for (int j = 0; j < ija; j++) {
pc = pc.brighter();
}
m_colorList.add(pc);
}
m_plot.setColours(m_colorList);
m_attrib.setColours(m_colorList);
m_classPanel.setColours(m_colorList);
}
}
/**
* This will set the shapes for the instances.
*
* @param l A list of the shapes, providing that the objects in the lists are
* non editable the data will be kept intact.
*/
public void setShapes(ArrayList> l) {
m_plot.setShapes(l);
}
/**
* Tells the panel to use a new set of instances.
*
* @param inst a set of Instances
*/
public void setInstances(Instances inst) {
if (inst.numAttributes() > 0 && inst.numInstances() > 0) {
newColorAttribute(inst.numAttributes() - 1, inst);
}
PlotData2D temp = new PlotData2D(inst);
temp.setPlotName(inst.relationName());
try {
setMasterPlot(temp);
} catch (Exception ex) {
System.err.println(ex);
ex.printStackTrace();
}
}
/**
* initializes the comboboxes based on the data
*
* @param inst the data to base the combobox-setup on
*/
public void setUpComboBoxes(Instances inst) {
setProperties(inst.relationName());
int prefX = -1;
int prefY = -1;
if (inst.numAttributes() > 1) {
prefY = 1;
}
int prefC = -1;
String[] XNames = new String[inst.numAttributes()];
String[] YNames = new String[inst.numAttributes()];
String[] CNames = new String[inst.numAttributes()];
for (int i = 0; i < XNames.length; i++) {
String type = " (" + Attribute.typeToStringShort(inst.attribute(i)) + ")";
XNames[i] = "X: " + inst.attribute(i).name() + type;
YNames[i] = "Y: " + inst.attribute(i).name() + type;
CNames[i] = "Colour: " + inst.attribute(i).name() + type;
if (m_preferredXDimension != null) {
if (m_preferredXDimension.compareTo(inst.attribute(i).name()) == 0) {
prefX = i;
// System.err.println("Found preferred X dimension");
}
}
if (m_preferredYDimension != null) {
if (m_preferredYDimension.compareTo(inst.attribute(i).name()) == 0) {
prefY = i;
// System.err.println("Found preferred Y dimension");
}
}
if (m_preferredColourDimension != null) {
if (m_preferredColourDimension.compareTo(inst.attribute(i).name()) == 0) {
prefC = i;
// System.err.println("Found preferred Colour dimension");
}
}
}
m_XCombo.setModel(new DefaultComboBoxModel(XNames));
m_YCombo.setModel(new DefaultComboBoxModel(YNames));
m_ColourCombo.setModel(new DefaultComboBoxModel(CNames));
// m_ShapeCombo.setModel(new DefaultComboBoxModel(SNames));
// m_ShapeCombo.setEnabled(true);
m_XCombo.setEnabled(true);
m_YCombo.setEnabled(true);
if (m_splitListener == null) {
m_ColourCombo.setEnabled(true);
m_ColourCombo.setSelectedIndex(inst.numAttributes() - 1);
}
m_plotSurround.setBorder((BorderFactory.createTitledBorder("Plot: "
+ inst.relationName())));
try {
if (prefX != -1) {
setXIndex(prefX);
}
if (prefY != -1) {
setYIndex(prefY);
}
if (prefC != -1) {
m_ColourCombo.setSelectedIndex(prefC);
}
} catch (Exception ex) {
System.err.println("Problem setting preferred Visualization dimensions");
}
}
/**
* Removes all the plots.
*/
public void removeAllPlots() {
m_plot.removeAllPlots();
}
/**
* Set the master plot for the visualize panel
*
* @param newPlot the new master plot
* @exception Exception if the master plot could not be set
*/
public void setMasterPlot(PlotData2D newPlot) throws Exception {
m_plot.setMasterPlot(newPlot);
setUpComboBoxes(newPlot.m_plotInstances);
m_saveBut.setEnabled(true);
repaint();
}
/**
* Set a new plot to the visualize panel
*
* @param newPlot the new plot to add
* @exception Exception if the plot could not be added
*/
public void addPlot(PlotData2D newPlot) throws Exception {
m_plot.addPlot(newPlot);
if (m_plot.m_plot2D.getMasterPlot() != null) {
setUpComboBoxes(newPlot.m_plotInstances);
}
m_saveBut.setEnabled(true);
repaint();
}
/**
* Returns the underlying plot panel.
*
* @return the plot panel
*/
public PlotPanel getPlotPanel() {
return m_plot;
}
/**
* Main method for testing this class
*
* @param args the commandline parameters
*/
public static void main(String[] args) {
try {
if (args.length < 1) {
System.err.println("Usage : weka.gui.visualize.VisualizePanel "
+ " [ ...]");
System.exit(1);
}
weka.core.logging.Logger.log(weka.core.logging.Logger.Level.INFO,
"Logging started");
final javax.swing.JFrame jf = new javax.swing.JFrame(
"Weka Explorer: Visualize");
jf.setSize(500, 400);
jf.getContentPane().setLayout(new BorderLayout());
final VisualizePanel sp = new VisualizePanel();
jf.getContentPane().add(sp, BorderLayout.CENTER);
jf.addWindowListener(new java.awt.event.WindowAdapter() {
@Override
public void windowClosing(java.awt.event.WindowEvent e) {
jf.dispose();
System.exit(0);
}
});
jf.setVisible(true);
if (args.length >= 1) {
for (int j = 0; j < args.length; j++) {
System.err.println("Loading instances from " + args[j]);
java.io.Reader r = new java.io.BufferedReader(new java.io.FileReader(
args[j]));
Instances i = new Instances(r);
i.setClassIndex(i.numAttributes() - 1);
PlotData2D pd1 = new PlotData2D(i);
if (j == 0) {
pd1.setPlotName("Master plot");
sp.setMasterPlot(pd1);
} else {
pd1.setPlotName("Plot " + (j + 1));
pd1.m_useCustomColour = true;
pd1.m_customColour = (j % 2 == 0) ? Color.red : Color.blue;
sp.addPlot(pd1);
}
}
}
} catch (Exception ex) {
ex.printStackTrace();
System.err.println(ex.getMessage());
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy