weka.gui.visualize.MatrixPanel Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of weka-stable Show documentation
Show all versions of weka-stable Show documentation
The Waikato Environment for Knowledge Analysis (WEKA), a machine
learning workbench. This is the stable version. Apart from bugfixes, this version
does not receive any other updates.
/*
* 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 .
*/
/*
* MatrixPanel.java
* Copyright (C) 2002-2012 University of Waikato, Hamilton, New Zealand
*
*/
package weka.gui.visualize;
import weka.core.Attribute;
import weka.core.Environment;
import weka.core.Instances;
import weka.core.Settings;
import weka.gui.ExtensionFileFilter;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSlider;
import javax.swing.JSplitPane;
import javax.swing.JTextField;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dialog.ModalityType;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Image;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Random;
/**
* This panel displays a plot matrix of the user selected attributes of a given
* data set.
*
* The datapoints are coloured using a discrete colouring set if the user has
* selected a nominal attribute for colouring. If the user has selected a
* numeric attribute then the datapoints are coloured using a colour spectrum
* ranging from blue to red (low values to high). Datapoints missing a class
* value are displayed in black.
*
* @author Ashraf M. Kibriya ([email protected])
* @version $Revision: 12391 $
*/
public class MatrixPanel extends JPanel {
/** for serialization */
private static final long serialVersionUID = -1232642719869188740L;
/** The that panel contains the actual matrix */
private final Plot m_plotsPanel;
/** The panel that displays the legend of the colouring attribute */
protected final ClassPanel m_cp = new ClassPanel();
/**
* The panel that contains all the buttons and tools, i.e. resize, jitter bars
* and sub-sampling buttons etc on the bottom of the panel
*/
protected JPanel optionsPanel;
/** Split pane for splitting the matrix and the buttons and bars */
protected JSplitPane jp;
/**
* The button that updates the display to reflect the changes made by the
* user. E.g. changed attribute set for the matrix
*/
protected JButton m_updateBt = new JButton("Update");
/** The button to display a window to select attributes */
protected JButton m_selAttrib = new JButton("Select Attributes");
/** The dataset for which this panel will display the plot matrix for */
protected Instances m_data = null;
/** The list for selecting the attributes to display the plot matrix */
protected JList m_attribList = new JList();
/** The scroll pane to scrolling the matrix */
protected final JScrollPane m_js = new JScrollPane();
/** The combo box to allow user to select the colouring attribute */
protected JComboBox m_classAttrib = new JComboBox();
/** The slider to adjust the size of the cells in the matrix */
protected JSlider m_plotSize = new JSlider(50, 200, 100);
/** The slider to adjust the size of the datapoints */
protected JSlider m_pointSize = new JSlider(1, 10, 1);
/** The slider to add jitter to the plots */
protected JSlider m_jitter = new JSlider(0, 20, 0);
/** For adding random jitter */
private final Random rnd = new Random();
/** Array containing precalculated jitter values */
private int jitterVals[][];
/** This stores the size of the datapoint */
private int datapointSize = 1;
/** The text area for percentage to resample data */
protected JTextField m_resamplePercent = new JTextField(5);
/** The label for resample percentage */
protected JButton m_resampleBt = new JButton("SubSample % :");
/** Random seed for random subsample */
protected JTextField m_rseed = new JTextField(5);
/** Displays the current size beside the slider bar for cell size */
private final JLabel m_plotSizeLb = new JLabel("PlotSize: [100]");
/** Displays the current size beside the slider bar for point size */
private final JLabel m_pointSizeLb = new JLabel("PointSize: [10]");
/** This array contains the indices of the attributes currently selected */
private int[] m_selectedAttribs;
/** This contains the index of the currently selected colouring attribute */
private int m_classIndex;
/**
* This is a local array cache for all the instance values for faster
* rendering
*/
private int[][] m_points;
/**
* This is an array cache for the colour of each of the instances depending on
* the colouring attribute. If the colouring attribute is nominal then it
* contains the index of the colour in our colour list. Otherwise, for numeric
* colouring attribute, it contains the precalculated red component for each
* instance's colour
*/
private int[] m_pointColors;
/**
* Contains true for each attribute value (only the selected attributes+class
* attribute) that is missing, for each instance. m_missing[i][j] == true if
* m_selectedAttribs[j] is missing in instance i.
* m_missing[i][m_missing[].length-1] == true if class value is missing in
* instance i.
*/
private boolean[][] m_missing;
/**
* This array contains for the classAttribute:
* m_type[0] = [type of attribute, nominal, string or numeric]
* m_type[1] = [number of discrete values of nominal or string attribute
* or same as m_type[0] for numeric attribute]
*/
private int[] m_type;
/** Stores the maximum size for PlotSize label to keep it's size constant */
private final Dimension m_plotLBSizeD;
/** Stores the maximum size for PointSize label to keep it's size constant */
private final Dimension m_pointLBSizeD;
/** Contains discrete colours for colouring for nominal attributes */
private final ArrayList m_colorList = new ArrayList();
/** default colour list */
private static final Color[] m_defaultColors = { Color.blue, Color.red,
Color.cyan, new Color(75, 123, 130), Color.pink, Color.green, Color.orange,
new Color(255, 0, 255), new Color(255, 0, 0), new Color(0, 255, 0),
Color.black };
/** color for the font used in column and row names */
private final Color fontColor = new Color(98, 101, 156);
/** font used in column and row names */
private final java.awt.Font f = new java.awt.Font("Dialog",
java.awt.Font.BOLD, 11);
/** Settings (if available) to pass through to the VisualizePanels */
protected Settings m_settings;
/** For the background of the little plots */
protected Color m_backgroundColor = Color.white;
/**
* ID of the owner (perspective, panel etc.) under which to lookup our
* settings
*/
protected String m_settingsOwnerID;
protected transient Image m_osi = null;
protected boolean[][] m_plottedCells;
protected boolean m_regenerateOSI = true;
protected boolean m_clearOSIPlottedCells;
protected double m_previousPercent = -1;
protected JCheckBox m_fastScroll = new JCheckBox(
"Fast scrolling (uses more memory)");
/**
* Constructor
*/
public MatrixPanel() {
m_rseed.setText("1");
/** Setting up GUI **/
m_selAttrib.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent ae) {
final JDialog jd =
new JDialog((JFrame) MatrixPanel.this.getTopLevelAncestor(),
"Attribute Selection Panel", ModalityType.DOCUMENT_MODAL);
JPanel jp = new JPanel();
JScrollPane js = new JScrollPane(m_attribList);
JButton okBt = new JButton("OK");
JButton cancelBt = new JButton("Cancel");
final int[] savedSelection = m_attribList.getSelectedIndices();
okBt.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
jd.dispose();
}
});
cancelBt.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
m_attribList.setSelectedIndices(savedSelection);
jd.dispose();
}
});
jd.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
m_attribList.setSelectedIndices(savedSelection);
jd.dispose();
}
});
jp.add(okBt);
jp.add(cancelBt);
jd.getContentPane().add(js, BorderLayout.CENTER);
jd.getContentPane().add(jp, BorderLayout.SOUTH);
if (js.getPreferredSize().width < 200) {
jd.setSize(250, 250);
} else {
jd.setSize(js.getPreferredSize().width + 10, 250);
}
jd.setLocation(m_selAttrib.getLocationOnScreen().x,
m_selAttrib.getLocationOnScreen().y - jd.getHeight());
jd.setVisible(true);
}
});
m_updateBt.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
updatePanel();
}
});
m_updateBt.setPreferredSize(m_selAttrib.getPreferredSize());
m_jitter.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent ce) {
if (m_fastScroll.isSelected()) {
m_clearOSIPlottedCells = true;
}
}
});
m_plotSize.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent ce) {
m_plotSizeLb.setText("PlotSize: [" + m_plotSize.getValue() + "]");
m_plotSizeLb.setPreferredSize(m_plotLBSizeD);
m_jitter.setMaximum(m_plotSize.getValue() / 5); // 20% of cell Size
m_regenerateOSI = true;
}
});
m_pointSize.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent ce) {
m_pointSizeLb.setText("PointSize: [" + m_pointSize.getValue() + "]");
m_pointSizeLb.setPreferredSize(m_pointLBSizeD);
datapointSize = m_pointSize.getValue();
if (m_fastScroll.isSelected()) {
m_clearOSIPlottedCells = true;
}
}
});
m_resampleBt.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
JLabel rseedLb = new JLabel("Random Seed: ");
JTextField rseedTxt = m_rseed;
JLabel percentLb = new JLabel("Subsample as");
JLabel percent2Lb = new JLabel("% of input: ");
final JTextField percentTxt = new JTextField(5);
percentTxt.setText(m_resamplePercent.getText());
JButton doneBt = new JButton("Done");
final JDialog jd =
new JDialog((JFrame) MatrixPanel.this.getTopLevelAncestor(),
"Subsample % Panel", ModalityType.DOCUMENT_MODAL) {
private static final long serialVersionUID = -269823533147146296L;
@Override
public void dispose() {
m_resamplePercent.setText(percentTxt.getText());
super.dispose();
}
};
jd.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
doneBt.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent ae) {
jd.dispose();
}
});
GridBagLayout gbl = new GridBagLayout();
GridBagConstraints gbc = new GridBagConstraints();
JPanel p1 = new JPanel(gbl);
gbc.anchor = GridBagConstraints.WEST;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.insets = new Insets(0, 2, 2, 2);
gbc.gridwidth = GridBagConstraints.RELATIVE;
p1.add(rseedLb, gbc);
gbc.weightx = 0;
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.weightx = 1;
p1.add(rseedTxt, gbc);
gbc.insets = new Insets(8, 2, 0, 2);
gbc.weightx = 0;
p1.add(percentLb, gbc);
gbc.insets = new Insets(0, 2, 2, 2);
gbc.gridwidth = GridBagConstraints.RELATIVE;
p1.add(percent2Lb, gbc);
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.weightx = 1;
p1.add(percentTxt, gbc);
gbc.insets = new Insets(8, 2, 2, 2);
JPanel p3 = new JPanel(gbl);
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.weightx = 1;
gbc.weighty = 0;
p3.add(p1, gbc);
gbc.insets = new Insets(8, 4, 8, 4);
p3.add(doneBt, gbc);
jd.getContentPane().setLayout(new BorderLayout());
jd.getContentPane().add(p3, BorderLayout.NORTH);
jd.pack();
jd.setLocation(m_resampleBt.getLocationOnScreen().x,
m_resampleBt.getLocationOnScreen().y - jd.getHeight());
jd.setVisible(true);
}
});
optionsPanel = new JPanel(new GridBagLayout()); // all the rest of the
// panels are in here.
final JPanel p2 = new JPanel(new BorderLayout()); // this has class colour
// panel
final JPanel p3 = new JPanel(new GridBagLayout()); // this has update and
// select buttons
final JPanel p4 = new JPanel(new GridBagLayout()); // this has the slider
// bars and combobox
GridBagConstraints gbc = new GridBagConstraints();
m_plotLBSizeD = m_plotSizeLb.getPreferredSize();
m_pointLBSizeD = m_pointSizeLb.getPreferredSize();
m_pointSizeLb.setText("PointSize: [1]");
m_pointSizeLb.setPreferredSize(m_pointLBSizeD);
m_resampleBt.setPreferredSize(m_selAttrib.getPreferredSize());
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.anchor = GridBagConstraints.NORTHWEST;
gbc.insets = new Insets(2, 2, 2, 2);
p4.add(m_plotSizeLb, gbc);
gbc.weightx = 1;
gbc.gridwidth = GridBagConstraints.REMAINDER;
p4.add(m_plotSize, gbc);
gbc.weightx = 0;
gbc.gridwidth = GridBagConstraints.RELATIVE;
p4.add(m_pointSizeLb, gbc);
gbc.weightx = 1;
gbc.gridwidth = GridBagConstraints.REMAINDER;
p4.add(m_pointSize, gbc);
gbc.weightx = 0;
gbc.gridwidth = GridBagConstraints.RELATIVE;
p4.add(new JLabel("Jitter: "), gbc);
gbc.weightx = 1;
gbc.gridwidth = GridBagConstraints.REMAINDER;
p4.add(m_jitter, gbc);
p4.add(m_classAttrib, gbc);
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.weightx = 1;
gbc.fill = GridBagConstraints.NONE;
p3.add(m_fastScroll, gbc);
p3.add(m_updateBt, gbc);
p3.add(m_selAttrib, gbc);
gbc.gridwidth = GridBagConstraints.RELATIVE;
gbc.weightx = 0;
gbc.fill = GridBagConstraints.VERTICAL;
gbc.anchor = GridBagConstraints.WEST;
p3.add(m_resampleBt, gbc);
gbc.gridwidth = GridBagConstraints.REMAINDER;
p3.add(m_resamplePercent, gbc);
p2.setBorder(BorderFactory.createTitledBorder("Class Colour"));
p2.add(m_cp, BorderLayout.SOUTH);
gbc.insets = new Insets(8, 5, 2, 5);
gbc.anchor = GridBagConstraints.SOUTHWEST;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.weightx = 1;
gbc.gridwidth = GridBagConstraints.RELATIVE;
optionsPanel.add(p4, gbc);
gbc.gridwidth = GridBagConstraints.REMAINDER;
optionsPanel.add(p3, gbc);
optionsPanel.add(p2, gbc);
m_fastScroll.setSelected(false);
m_fastScroll.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (!m_fastScroll.isSelected()) {
m_osi = null;
} else {
m_plottedCells =
new boolean[m_selectedAttribs.length][m_selectedAttribs.length];
}
MatrixPanel.this.invalidate();
MatrixPanel.this.repaint();
}
});
this.addComponentListener(new ComponentAdapter() {
@Override
public void componentResized(ComponentEvent cv) {
m_js.setMinimumSize(new Dimension(MatrixPanel.this.getWidth(),
MatrixPanel.this.getHeight() - optionsPanel.getPreferredSize().height
- 10));
jp.setDividerLocation(MatrixPanel.this.getHeight()
- optionsPanel.getPreferredSize().height - 10);
}
});
optionsPanel.setMinimumSize(new Dimension(0, 0));
jp = new JSplitPane(JSplitPane.VERTICAL_SPLIT, m_js, optionsPanel);
jp.setOneTouchExpandable(true);
jp.setResizeWeight(1);
this.setLayout(new BorderLayout());
this.add(jp, BorderLayout.CENTER);
/** Setting up the initial color list **/
for (int i = 0; i < m_defaultColors.length; i++) {
m_colorList.add(m_defaultColors[i]);
}
/** Initializing internal fields and components **/
m_selectedAttribs = m_attribList.getSelectedIndices();
m_plotsPanel = new Plot();
m_plotsPanel.setLayout(null);
m_js.getHorizontalScrollBar().setUnitIncrement(10);
m_js.getVerticalScrollBar().setUnitIncrement(10);
m_js.setViewportView(m_plotsPanel);
m_js.setColumnHeaderView(m_plotsPanel.getColHeader());
m_js.setRowHeaderView(m_plotsPanel.getRowHeader());
final JLabel lb = new JLabel(" Plot Matrix");
lb.setFont(f);
lb.setForeground(fontColor);
lb.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
m_js.setCorner(JScrollPane.UPPER_LEFT_CORNER, lb);
m_cp.setInstances(m_data);
m_cp.setBorder(BorderFactory.createEmptyBorder(15, 10, 10, 10));
m_cp.addRepaintNotify(m_plotsPanel);
// m_updateBt.doClick(); //not until setting up the instances
}
/**
* Initializes internal data fields, i.e. data values, type, missing and color
* cache arrays
*/
public void initInternalFields() {
Instances inst = m_data;
m_classIndex = m_classAttrib.getSelectedIndex();
m_selectedAttribs = m_attribList.getSelectedIndices();
double minC = 0, maxC = 0;
/** Resampling **/
double currentPercent = Double.parseDouble(m_resamplePercent.getText());
if (currentPercent <= 100) {
if (currentPercent != m_previousPercent) {
m_clearOSIPlottedCells = true;
}
inst = new Instances(m_data, 0, m_data.numInstances());
inst.randomize(new Random(Integer.parseInt(m_rseed.getText())));
// System.err.println("gettingPercent: " +
// Math.round(
// Double.parseDouble(m_resamplePercent.getText())
// / 100D * m_data.numInstances()
// )
// );
inst =
new Instances(inst, 0, (int) Math.round(currentPercent / 100D
* inst.numInstances()));
m_previousPercent = currentPercent;
}
m_points = new int[inst.numInstances()][m_selectedAttribs.length]; // changed
m_pointColors = new int[inst.numInstances()];
m_missing = new boolean[inst.numInstances()][m_selectedAttribs.length + 1]; // changed
m_type = new int[2]; // [m_selectedAttribs.length]; //changed
jitterVals = new int[inst.numInstances()][2];
/**
* Setting up the color list for non-numeric attribute as well as jittervals
**/
if (!(inst.attribute(m_classIndex).isNumeric())) {
for (int i = m_colorList.size(); i < inst.attribute(m_classIndex)
.numValues() + 1; i++) {
Color pc = m_defaultColors[i % 10];
int ija = i / 10;
ija *= 2;
for (int j = 0; j < ija; j++) {
pc = pc.darker();
}
m_colorList.add(pc);
}
for (int i = 0; i < inst.numInstances(); i++) {
// set to black for missing class value which is last colour is default
// list
if (inst.instance(i).isMissing(m_classIndex)) {
m_pointColors[i] = m_defaultColors.length - 1;
} else {
m_pointColors[i] = (int) inst.instance(i).value(m_classIndex);
}
jitterVals[i][0] =
rnd.nextInt(m_jitter.getValue() + 1) - m_jitter.getValue() / 2;
jitterVals[i][1] =
rnd.nextInt(m_jitter.getValue() + 1) - m_jitter.getValue() / 2;
}
}
/** Setting up color variations for numeric attribute as well as jittervals **/
else {
for (int i = 0; i < inst.numInstances(); i++) {
if (!(inst.instance(i).isMissing(m_classIndex))) {
minC = maxC = inst.instance(i).value(m_classIndex);
break;
}
}
for (int i = 1; i < inst.numInstances(); i++) {
if (!(inst.instance(i).isMissing(m_classIndex))) {
if (minC > inst.instance(i).value(m_classIndex)) {
minC = inst.instance(i).value(m_classIndex);
}
if (maxC < inst.instance(i).value(m_classIndex)) {
maxC = inst.instance(i).value(m_classIndex);
}
}
}
for (int i = 0; i < inst.numInstances(); i++) {
double r =
(inst.instance(i).value(m_classIndex) - minC) / (maxC - minC);
r = (r * 240) + 15;
m_pointColors[i] = (int) r;
jitterVals[i][0] =
rnd.nextInt(m_jitter.getValue() + 1) - m_jitter.getValue() / 2;
jitterVals[i][1] =
rnd.nextInt(m_jitter.getValue() + 1) - m_jitter.getValue() / 2;
}
}
/** Creating local cache of the data values **/
double min[] = new double[m_selectedAttribs.length], max = 0; // changed
double ratio[] = new double[m_selectedAttribs.length]; // changed
double cellSize = m_plotSize.getValue(), temp1 = 0, temp2 = 0;
for (int j = 0; j < m_selectedAttribs.length; j++) {
int i;
for (i = 0; i < inst.numInstances(); i++) {
min[j] = max = 0;
if (!(inst.instance(i).isMissing(m_selectedAttribs[j]))) {
min[j] = max = inst.instance(i).value(m_selectedAttribs[j]);
break;
}
}
for (; i < inst.numInstances(); i++) {
if (!(inst.instance(i).isMissing(m_selectedAttribs[j]))) {
if (inst.instance(i).value(m_selectedAttribs[j]) < min[j]) {
min[j] = inst.instance(i).value(m_selectedAttribs[j]);
}
if (inst.instance(i).value(m_selectedAttribs[j]) > max) {
max = inst.instance(i).value(m_selectedAttribs[j]);
}
}
}
ratio[j] = cellSize / (max - min[j]);
}
boolean classIndexProcessed = false;
for (int j = 0; j < m_selectedAttribs.length; j++) {
if (inst.attribute(m_selectedAttribs[j]).isNominal()
|| inst.attribute(m_selectedAttribs[j]).isString()) {
// m_type[0][j] = 1; m_type[1][j] =
// inst.attribute(m_selectedAttribs[j]).numValues();
temp1 = cellSize / inst.attribute(m_selectedAttribs[j]).numValues(); // m_type[1][j];
temp2 = temp1 / 2;
for (int i = 0; i < inst.numInstances(); i++) {
m_points[i][j] =
(int) Math.round(temp2 + temp1
* inst.instance(i).value(m_selectedAttribs[j]));
if (inst.instance(i).isMissing(m_selectedAttribs[j])) {
m_missing[i][j] = true; // represents missing value
if (m_selectedAttribs[j] == m_classIndex) {
m_missing[i][m_missing[0].length - 1] = true;
classIndexProcessed = true;
}
}
}
} else {
// m_type[0][j] = m_type[1][j] = 0;
for (int i = 0; i < inst.numInstances(); i++) {
m_points[i][j] =
(int) Math
.round((inst.instance(i).value(m_selectedAttribs[j]) - min[j])
* ratio[j]);
if (inst.instance(i).isMissing(m_selectedAttribs[j])) {
m_missing[i][j] = true; // represents missing value
if (m_selectedAttribs[j] == m_classIndex) {
m_missing[i][m_missing[0].length - 1] = true;
classIndexProcessed = true;
}
}
}
}
}
if (inst.attribute(m_classIndex).isNominal()
|| inst.attribute(m_classIndex).isString()) {
m_type[0] = 1;
m_type[1] = inst.attribute(m_classIndex).numValues();
} else {
m_type[0] = m_type[1] = 0;
}
if (classIndexProcessed == false) { // class Index has not been processed as
// class index is not among the selected
// attribs
for (int i = 0; i < inst.numInstances(); i++) {
if (inst.instance(i).isMissing(m_classIndex)) {
m_missing[i][m_missing[0].length - 1] = true;
}
}
}
m_cp.setColours(m_colorList);
}
/**
* Sets up the UI's attributes lists
*/
public void setupAttribLists() {
String[] tempAttribNames = new String[m_data.numAttributes()];
String type;
m_classAttrib.removeAllItems();
for (int i = 0; i < tempAttribNames.length; i++) {
type = " (" + Attribute.typeToStringShort(m_data.attribute(i)) + ")";
tempAttribNames[i] =
new String("Colour: " + m_data.attribute(i).name() + " " + type);
m_classAttrib.addItem(tempAttribNames[i]);
}
if (m_data.classIndex() == -1) {
m_classAttrib.setSelectedIndex(tempAttribNames.length - 1);
} else {
m_classAttrib.setSelectedIndex(m_data.classIndex());
}
m_attribList.setListData(tempAttribNames);
m_attribList.setSelectionInterval(0, tempAttribNames.length - 1);
}
/**
* Calculates the percentage to resample
*/
public void setPercent() {
if (m_data.numInstances() > 700) {
double percnt = 500D / m_data.numInstances() * 100;
percnt *= 100;
percnt = Math.round(percnt);
percnt /= 100;
m_resamplePercent.setText("" + percnt);
} else {
m_resamplePercent.setText("100");
}
}
/**
* This method changes the Instances object of this class to a new one. It
* also does all the necessary initializations for displaying the panel. This
* must be called before trying to display the panel.
*
* @param newInst The new set of Instances
*/
public void setInstances(Instances newInst) {
m_osi = null;
m_fastScroll.setSelected(false);
m_data = newInst;
setPercent();
setupAttribLists();
m_rseed.setText("1");
initInternalFields();
m_cp.setInstances(m_data);
m_cp.setCindex(m_classIndex);
m_updateBt.doClick();
}
/**
* Main method for testing this class
*/
public static void main(String[] args) {
final JFrame jf = new JFrame("Weka Explorer: MatrixPanel");
final JButton setBt = new JButton("Set Instances");
Instances data = null;
try {
if (args.length == 1) {
data = new Instances(new BufferedReader(new FileReader(args[0])));
} else {
System.out.println("Usage: MatrixPanel ");
System.exit(-1);
}
} catch (IOException ex) {
ex.printStackTrace();
System.exit(-1);
}
final MatrixPanel mp = new MatrixPanel();
mp.setInstances(data);
setBt.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
JFileChooser chooser =
new JFileChooser(new java.io.File(System.getProperty("user.dir")));
ExtensionFileFilter myfilter =
new ExtensionFileFilter("arff", "Arff data files");
chooser.setFileFilter(myfilter);
int returnVal = chooser.showOpenDialog(jf);
if (returnVal == JFileChooser.APPROVE_OPTION) {
try {
System.out.println("You chose to open this file: "
+ chooser.getSelectedFile().getName());
Instances in =
new Instances(new FileReader(chooser.getSelectedFile()
.getAbsolutePath()));
mp.setInstances(in);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
});
// System.out.println("Loaded: "+args[0]+"\nRelation: "+data.relationName()+"\nAttributes: "+data.numAttributes());
// System.out.println("The attributes are: ");
// for(int i=0; i r.x + r.width) {
break;
} else {
attribWidth =
fm.stringWidth(m_data.attribute(m_selectedAttrib).name());
g.drawString(
m_data.attribute(m_selectedAttrib).name(),
(attribWidth < cellSize) ? (xpos + (cellSize / 2 - attribWidth / 2))
: xpos, ypos);
}
xpos += cellSize + extpad;
}
fm = null;
r = null;
}
@Override
public Dimension getPreferredSize() {
fm = this.getFontMetrics(this.getFont());
return new Dimension(m_selectedAttribs.length * (cellSize + extpad),
2 * extpad + fm.getHeight());
}
};
jPlRowHeader = new JPanel() {
private static final long serialVersionUID = 8474957069309552844L;
java.awt.Rectangle r;
@Override
public void paint(Graphics g) {
r = g.getClipBounds();
g.setColor(this.getBackground());
g.fillRect(r.x, r.y, r.width, r.height);
g.setFont(f);
fm = g.getFontMetrics();
int xpos = 0, ypos = 0;
g.setColor(fontColor);
xpos = extpad;
ypos = extpad;
for (int j = m_selectedAttribs.length - 1; j >= 0; j--) {
if (ypos + cellSize < r.y) {
ypos += cellSize + extpad;
continue;
} else if (ypos > r.y + r.height) {
break;
} else {
g.drawString(m_data.attribute(m_selectedAttribs[j]).name(), xpos
+ extpad, ypos + cellSize / 2);
}
xpos = extpad;
ypos += cellSize + extpad;
}
r = null;
}
@Override
public Dimension getPreferredSize() {
return new Dimension(100 + extpad, m_selectedAttribs.length
* (cellSize + extpad));
}
};
jPlColHeader.setFont(f);
jPlRowHeader.setFont(f);
this.setFont(f);
}
public JPanel getRowHeader() {
return jPlRowHeader;
}
public JPanel getColHeader() {
return jPlColHeader;
}
@Override
public void mouseMoved(MouseEvent e) {
Graphics g = this.getGraphics();
int xpos = extpad, ypos = extpad;
for (int j = m_selectedAttribs.length - 1; j >= 0; j--) {
for (@SuppressWarnings("unused")
int m_selectedAttrib : m_selectedAttribs) {
if (e.getX() >= xpos && e.getX() <= xpos + cellSize + extpad) {
if (e.getY() >= ypos && e.getY() <= ypos + cellSize + extpad) {
if (xpos != lastxpos || ypos != lastypos) {
g.setColor(Color.red);
g.drawRect(xpos - 1, ypos - 1, cellSize + 1, cellSize + 1);
if (lastxpos != 0 && lastypos != 0) {
g.setColor(this.getBackground().darker());
g.drawRect(lastxpos - 1, lastypos - 1, cellSize + 1,
cellSize + 1);
}
lastxpos = xpos;
lastypos = ypos;
}
return;
}
}
xpos += cellSize + extpad;
}
xpos = extpad;
ypos += cellSize + extpad;
}
if (lastxpos != 0 && lastypos != 0) {
g.setColor(this.getBackground().darker());
g.drawRect(lastxpos - 1, lastypos - 1, cellSize + 1, cellSize + 1);
}
lastxpos = lastypos = 0;
}
@Override
public void mouseDragged(MouseEvent e) {
}
@Override
public void mouseClicked(MouseEvent e) {
int i = 0, j = 0, found = 0;
int xpos = extpad, ypos = extpad;
for (j = m_selectedAttribs.length - 1; j >= 0; j--) {
for (i = 0; i < m_selectedAttribs.length; i++) {
if (e.getX() >= xpos && e.getX() <= xpos + cellSize + extpad) {
if (e.getY() >= ypos && e.getY() <= ypos + cellSize + extpad) {
found = 1;
break;
}
}
xpos += cellSize + extpad;
}
if (found == 1) {
break;
}
xpos = extpad;
ypos += cellSize + extpad;
}
if (found == 0) {
return;
}
JFrame jf =
new JFrame("Weka Explorer: Visualizing " + m_data.relationName());
VisualizePanel vp = new VisualizePanel();
try {
PlotData2D pd = new PlotData2D(m_data);
pd.setPlotName("Master Plot");
vp.setMasterPlot(pd);
// System.out.println("x: "+i+" y: "+j);
vp.setXIndex(m_selectedAttribs[i]);
vp.setYIndex(m_selectedAttribs[j]);
vp.m_ColourCombo.setSelectedIndex(m_classIndex);
if (m_settings != null) {
vp.applySettings(m_settings, m_settingsOwnerID);
}
} catch (Exception ex) {
ex.printStackTrace();
}
jf.getContentPane().add(vp);
jf.setSize(800, 600);
jf.setVisible(true);
}
@Override
public void mouseEntered(MouseEvent e) {
}
@Override
public void mouseExited(MouseEvent e) {
}
@Override
public void mousePressed(MouseEvent e) {
}
@Override
public void mouseReleased(MouseEvent e) {
}
/**
* sets the new jitter value for the plots
*/
public void setJitter(int newjitter) {
}
/**
* sets the new size for the plots
*/
public void setCellSize(int newCellSize) {
cellSize = newCellSize;
initialize();
}
/**
* Returns the X and Y attributes of the plot the mouse is currently on
*/
@Override
public String getToolTipText(MouseEvent event) {
int xpos = extpad, ypos = extpad;
for (int j = m_selectedAttribs.length - 1; j >= 0; j--) {
for (int m_selectedAttrib : m_selectedAttribs) {
if (event.getX() >= xpos && event.getX() <= xpos + cellSize + extpad) {
if (event.getY() >= ypos
&& event.getY() <= ypos + cellSize + extpad) {
return ("X: " + m_data.attribute(m_selectedAttrib).name()
+ " Y: " + m_data.attribute(m_selectedAttribs[j]).name() + " (click to enlarge)");
}
}
xpos += cellSize + extpad;
}
xpos = extpad;
ypos += cellSize + extpad;
}
return ("Matrix Panel");
}
/**
* Paints a single Plot at xpos, ypos. and xattrib and yattrib on X and Y
* axes
*/
public void paintGraph(Graphics g, int xattrib, int yattrib, int xpos,
int ypos) {
int x, y;
g.setColor(m_backgroundColor.equals(Color.BLACK) ? m_backgroundColor
.brighter().brighter() : m_backgroundColor.darker().darker());
g.drawRect(xpos - 1, ypos - 1, cellSize + 1, cellSize + 1);
g.setColor(m_backgroundColor);
g.fillRect(xpos, ypos, cellSize, cellSize);
for (int i = 0; i < m_points.length; i++) {
if (!(m_missing[i][yattrib] || m_missing[i][xattrib])) {
if (m_type[0] == 0) {
if (m_missing[i][m_missing[0].length - 1]) {
g.setColor(m_defaultColors[m_defaultColors.length - 1]);
} else {
g.setColor(new Color(m_pointColors[i], 150,
(255 - m_pointColors[i])));
}
} else {
g.setColor(m_colorList.get(m_pointColors[i]));
}
if (m_points[i][xattrib] + jitterVals[i][0] < 0
|| m_points[i][xattrib] + jitterVals[i][0] > cellRange) {
if (cellRange - m_points[i][yattrib] + jitterVals[i][1] < 0
|| cellRange - m_points[i][yattrib] + jitterVals[i][1] > cellRange) {
// both x and y out of range don't add jitter
x = intpad + m_points[i][xattrib];
y = intpad + (cellRange - m_points[i][yattrib]);
} else {
// only x out of range
x = intpad + m_points[i][xattrib];
y =
intpad + (cellRange - m_points[i][yattrib]) + jitterVals[i][1];
}
} else if (cellRange - m_points[i][yattrib] + jitterVals[i][1] < 0
|| cellRange - m_points[i][yattrib] + jitterVals[i][1] > cellRange) {
// only y out of range
x = intpad + m_points[i][xattrib] + jitterVals[i][0];
y = intpad + (cellRange - m_points[i][yattrib]);
} else {
// none out of range
x = intpad + m_points[i][xattrib] + jitterVals[i][0];
y = intpad + (cellRange - m_points[i][yattrib]) + jitterVals[i][1];
}
if (datapointSize == 1) {
g.drawLine(x + xpos, y + ypos, x + xpos, y + ypos);
} else {
g.drawOval(x + xpos - datapointSize / 2, y + ypos - datapointSize
/ 2, datapointSize, datapointSize);
}
}
}
g.setColor(fontColor);
}
private void createOSI() {
int iwidth = this.getWidth();
int iheight = this.getHeight();
m_osi = this.createImage(iwidth, iheight);
clearOSI();
}
private void clearOSI() {
if (m_osi == null) {
return;
}
int iwidth = this.getWidth();
int iheight = this.getHeight();
Graphics m = m_osi.getGraphics();
m.setColor(this.getBackground().darker().darker());
m.fillRect(0, 0, iwidth, iheight);
}
/**
* Paints the matrix of plots in the current visible region
*/
public void paintME(Graphics g) {
Graphics g2 = g;
if (m_osi == null && m_fastScroll.isSelected()) {
createOSI();
}
if (m_osi != null && m_fastScroll.isSelected()) {
g2 = m_osi.getGraphics();
}
r = g.getClipBounds();
g.setColor(this.getBackground());
g.fillRect(r.x, r.y, r.width, r.height);
g.setColor(fontColor);
int xpos = 0, ypos = 0;
xpos = extpad;
ypos = extpad;
for (int j = m_selectedAttribs.length - 1; j >= 0; j--) {
if (ypos + cellSize < r.y) {
ypos += cellSize + extpad;
continue;
} else if (ypos > r.y + r.height) {
break;
} else {
for (int i = 0; i < m_selectedAttribs.length; i++) {
if (xpos + cellSize < r.x) {
xpos += cellSize + extpad;
continue;
} else if (xpos > r.x + r.width) {
break;
} else if (m_fastScroll.isSelected()) {
if (!m_plottedCells[i][j]) {
paintGraph(g2, i, j, xpos, ypos); // m_selectedAttribs[i],
// m_selectedAttribs[j], xpos,
// ypos);
m_plottedCells[i][j] = true;
}
} else {
paintGraph(g2, i, j, xpos, ypos);
}
xpos += cellSize + extpad;
}
}
xpos = extpad;
ypos += cellSize + extpad;
}
}
/**
* paints this JPanel (PlotsPanel)
*/
@Override
public void paintComponent(Graphics g) {
paintME(g);
if (m_osi != null && m_fastScroll.isSelected()) {
g.drawImage(m_osi, 0, 0, this);
}
}
}
/**
* Set the point size for the plots
*
* @param pointSize the point size to use
*/
public void setPointSize(int pointSize) {
if (pointSize <= m_pointSize.getMaximum()
&& pointSize > m_pointSize.getMinimum()) {
m_pointSize.setValue(pointSize);
}
}
/**
* Set the plot size
*
* @param plotSize the plot size to use
*/
public void setPlotSize(int plotSize) {
if (plotSize >= m_plotSize.getMinimum()
&& plotSize <= m_plotSize.getMaximum()) {
m_plotSize.setValue(plotSize);
}
}
/**
* Set the background colour for the cells in the matrix
*
* @param c the background colour
*/
public void setPlotBackgroundColour(Color c) {
m_backgroundColor = c;
}
/**
* @param settings
* @param ownerID
*/
public void applySettings(Settings settings, String ownerID) {
m_settings = settings;
m_settingsOwnerID = ownerID;
setPointSize(settings.getSetting(ownerID,
weka.gui.explorer.VisualizePanel.ScatterDefaults.POINT_SIZE_KEY,
weka.gui.explorer.VisualizePanel.ScatterDefaults.POINT_SIZE,
Environment.getSystemWide()));
setPlotSize(settings.getSetting(ownerID,
weka.gui.explorer.VisualizePanel.ScatterDefaults.PLOT_SIZE_KEY,
weka.gui.explorer.VisualizePanel.ScatterDefaults.PLOT_SIZE,
Environment.getSystemWide()));
setPlotBackgroundColour(settings.getSetting(ownerID,
VisualizeUtils.VisualizeDefaults.BACKGROUND_COLOUR_KEY,
VisualizeUtils.VisualizeDefaults.BACKGROUND_COLOR,
Environment.getSystemWide()));
}
/**
* Update the display. Typically called after changing plot size, point size
* etc.
*/
public void updatePanel() {
// m_selectedAttribs = m_attribList.getSelectedIndices();
initInternalFields();
Plot a = m_plotsPanel;
a.setCellSize(m_plotSize.getValue());
Dimension d =
new Dimension((m_selectedAttribs.length) * (a.cellSize + a.extpad) + 2,
(m_selectedAttribs.length) * (a.cellSize + a.extpad) + 2);
// System.out.println("Size: "+a.cellSize+" Extpad: "+
// a.extpad+" selected: "+
// m_selectedAttribs.length+' '+d);
a.setPreferredSize(d);
a.setSize(a.getPreferredSize());
a.setJitter(m_jitter.getValue());
if (m_fastScroll.isSelected() && m_clearOSIPlottedCells) {
m_plottedCells =
new boolean[m_selectedAttribs.length][m_selectedAttribs.length];
m_clearOSIPlottedCells = false;
}
if (m_regenerateOSI) {
m_osi = null;
}
m_js.revalidate();
m_cp.setColours(m_colorList);
m_cp.setCindex(m_classIndex);
m_regenerateOSI = false;
repaint();
}
}