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

Windows Develop

Development Platform:

Java

  1. /*
  2.  *    This program is free software; you can redistribute it and/or modify
  3.  *    it under the terms of the GNU General Public License as published by
  4.  *    the Free Software Foundation; either version 2 of the License, or
  5.  *    (at your option) any later version.
  6.  *
  7.  *    This program is distributed in the hope that it will be useful,
  8.  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
  9.  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  10.  *    GNU General Public License for more details.
  11.  *
  12.  *    You should have received a copy of the GNU General Public License
  13.  *    along with this program; if not, write to the Free Software
  14.  *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15.  */
  16. /*
  17.  *    VisualizePanel.java
  18.  *    Copyright (C) 1999 Mark Hall, Malcolm Ware
  19.  *
  20.  */
  21. package weka.gui.visualize;
  22. import weka.gui.*;
  23. import weka.classifiers.*;
  24. import weka.core.Instances;
  25. import weka.core.Instance;
  26. import weka.core.Attribute;
  27. import weka.core.FastVector;
  28. import weka.core.Utils;
  29. import java.util.Random;
  30. import java.io.File;
  31. import java.io.Writer;
  32. import java.io.BufferedWriter;
  33. import java.io.FileWriter;
  34. import java.awt.FlowLayout;
  35. import java.awt.BorderLayout;
  36. import java.awt.GridLayout;
  37. import java.awt.GridBagLayout;
  38. import java.awt.GridBagConstraints;
  39. import java.awt.Insets;
  40. import java.awt.Font;
  41. import java.awt.event.InputEvent;
  42. import java.awt.event.WindowAdapter;
  43. import java.awt.event.WindowEvent;
  44. import java.awt.event.ActionListener;
  45. import java.awt.event.ActionEvent;
  46. import java.awt.event.MouseAdapter;
  47. import java.awt.event.MouseMotionAdapter;
  48. import java.awt.event.MouseEvent;
  49. import java.awt.Dimension;
  50. import javax.swing.JPanel;
  51. import javax.swing.JLabel;
  52. import javax.swing.JButton;
  53. import javax.swing.JPopupMenu;
  54. import javax.swing.JMenuItem;
  55. import javax.swing.BorderFactory;
  56. import javax.swing.JTextArea;
  57. import javax.swing.JScrollPane;
  58. import javax.swing.JColorChooser;
  59. import javax.swing.JRadioButton;
  60. import javax.swing.ButtonGroup;
  61. import javax.swing.JOptionPane;
  62. import javax.swing.JComboBox;
  63. import javax.swing.DefaultComboBoxModel;
  64. import javax.swing.JTextField;
  65. import javax.swing.SwingConstants;
  66. import javax.swing.JFrame;
  67. import javax.swing.event.ChangeListener;
  68. import javax.swing.event.ChangeEvent;
  69. import javax.swing.JViewport;
  70. import javax.swing.JSlider;
  71. import javax.swing.JFileChooser;
  72. import javax.swing.filechooser.FileFilter;
  73. import java.awt.Color;
  74. import java.awt.FontMetrics;
  75. import java.awt.Graphics;
  76. /** 
  77.  * This panel allows the user to visualize a dataset (and if provided) a
  78.  * classifier's/clusterer's predictions in two dimensions.
  79.  *
  80.  * If the user selects a nominal attribute as the colouring attribute then
  81.  * each point is drawn in a colour that corresponds to the discrete value
  82.  * of that attribute for the instance. If the user selects a numeric
  83.  * attribute to colour on, then the points are coloured using a spectrum
  84.  * ranging from blue to red (low values to high).
  85.  *
  86.  * When a classifier's predictions are supplied they are plotted in one
  87.  * of two ways (depending on whether the class is nominal or numeric).<br>
  88.  * For nominal class: an error made by a classifier is plotted as a square
  89.  * in the colour corresponding to the class it predicted.<br>
  90.  * For numeric class: predictions are plotted as varying sized x's, where
  91.  * the size of the x is related to the magnitude of the error.
  92.  *
  93.  * @author Mark Hall (mhall@cs.waikato.ac.nz)
  94.  * @author Malcolm Ware (mfw4@cs.waikato.ac.nz)
  95.  * @version $Revision: 1.18 $
  96.  */
  97. public class VisualizePanel extends JPanel {
  98.   /** Inner class to handle plotting */
  99.   protected class PlotPanel extends JPanel implements Plot2DCompanion {
  100.     /** The actual generic plotting panel */
  101.     protected Plot2D m_plot2D = new Plot2D();
  102.     /** The instances from the master plot */
  103.     protected Instances m_plotInstances=null;
  104.     /** The master plot */
  105.     protected PlotData2D m_originalPlot=null;
  106.     
  107.     /** Indexes of the attributes to go on the x and y axis and the attribute
  108. to use for colouring and the current shape for drawing */
  109.     protected int m_xIndex=0;
  110.     protected int m_yIndex=0;
  111.     protected int m_cIndex=0;
  112.     protected int m_sIndex=0;
  113.  
  114.     /** Axis padding */
  115.     private final int m_axisPad = 5;
  116.     /** Tick size */
  117.     private final int m_tickSize = 5;
  118.     /**the offsets of the axes once label metrics are calculated */
  119.     private int m_XaxisStart=0;
  120.     private int m_YaxisStart=0;
  121.     private int m_XaxisEnd=0;
  122.     private int m_YaxisEnd=0;
  123.     /** True if the user is currently dragging a box. */
  124.     private boolean m_createShape;
  125.     
  126.     /** contains all the shapes that have been drawn for these attribs */
  127.     private FastVector m_shapes;
  128.     /** contains the points of the shape currently being drawn. */
  129.     private FastVector m_shapePoints;
  130.     /** contains the position of the mouse (used for rubberbanding). */
  131.     private Dimension m_newMousePos;
  132.     //////
  133.     /** Constructor */
  134.     public PlotPanel() {
  135.       this.setBackground(m_plot2D.getBackground());
  136.       this.setLayout(new BorderLayout());
  137.       this.add(m_plot2D, BorderLayout.CENTER);
  138.       m_plot2D.setPlotCompanion(this);
  139.       m_createShape = false;        
  140.       m_shapes = null;////
  141.       m_shapePoints = null;
  142.       m_newMousePos = new Dimension();
  143.       this.addMouseListener(new MouseAdapter() {
  144.   ///////      
  145.   public void mousePressed(MouseEvent e) {
  146.     if ((e.getModifiers() & e.BUTTON1_MASK) == e.BUTTON1_MASK) {
  147.       //
  148.       if (m_sIndex == 0) {
  149. //do nothing it will get dealt to in the clicked method
  150.       }
  151.       else if (m_sIndex == 1) {
  152. m_createShape = true;
  153. m_shapePoints = new FastVector(5);
  154. m_shapePoints.addElement(new Double(m_sIndex));
  155. m_shapePoints.addElement(new Double(e.getX()));
  156. m_shapePoints.addElement(new Double(e.getY()));
  157. m_shapePoints.addElement(new Double(e.getX()));
  158. m_shapePoints.addElement(new Double(e.getY()));
  159. // Graphics g = PlotPanel.this.getGraphics();
  160. Graphics g = m_plot2D.getGraphics();
  161. g.setColor(Color.black);
  162. g.setXORMode(Color.white);
  163. g.drawRect(((Double)m_shapePoints.elementAt(1)).intValue(),
  164.    ((Double)m_shapePoints.elementAt(2)).intValue(),
  165.    ((Double)m_shapePoints.elementAt(3)).intValue() -
  166.    ((Double)m_shapePoints.elementAt(1)).intValue(), 
  167.    ((Double)m_shapePoints.elementAt(4)).intValue() -
  168.    ((Double)m_shapePoints.elementAt(2)).intValue());
  169. g.dispose();
  170.       }
  171.       //System.out.println("clicked");
  172.     }
  173.     //System.out.println("clicked");
  174.   }
  175.   //////
  176.   public void mouseClicked(MouseEvent e) {
  177.     
  178.     if ((m_sIndex == 2 || m_sIndex == 3) && 
  179. (m_createShape || 
  180.  (e.getModifiers() & e.BUTTON1_MASK) == e.BUTTON1_MASK)) {
  181.       if (m_createShape) {
  182. //then it has been started already.
  183. Graphics g = m_plot2D.getGraphics();
  184. g.setColor(Color.black);
  185. g.setXORMode(Color.white);
  186. if ((e.getModifiers() & e.BUTTON1_MASK) == e.BUTTON1_MASK) {
  187.   m_shapePoints.addElement(new 
  188.     Double(m_plot2D.convertToAttribX(e.getX())));
  189.   
  190.   m_shapePoints.addElement(new 
  191.     Double(m_plot2D.convertToAttribY(e.getY())));
  192.   
  193.   m_newMousePos.width = e.getX();
  194.   m_newMousePos.height = e.getY();
  195.   g.drawLine((int)Math.ceil
  196.      (m_plot2D.convertToPanelX
  197.       (((Double)m_shapePoints.
  198. elementAt(m_shapePoints.size() - 2)).
  199.        doubleValue())),
  200.      
  201.      (int)Math.ceil
  202.      (m_plot2D.convertToPanelY
  203.       (((Double)m_shapePoints.
  204. elementAt(m_shapePoints.size() - 1)).
  205.        doubleValue())),
  206.      m_newMousePos.width, m_newMousePos.height);
  207.   
  208. }
  209. else if (m_sIndex == 3) {
  210.   //then extend the lines to infinity 
  211.   //(100000 or so should be enough).
  212.   //the area is selected by where the user right clicks 
  213.   //the mouse button
  214.   
  215.   m_createShape = false;
  216.   if (m_shapePoints.size() >= 5) {
  217.     double cx = Math.ceil
  218.       (m_plot2D.convertToPanelX
  219.        (((Double)m_shapePoints.elementAt
  220.  (m_shapePoints.size() - 4)).doubleValue()));
  221.     
  222.     double cx2 = Math.ceil
  223.       (m_plot2D.convertToPanelX
  224.        (((Double)m_shapePoints.elementAt
  225.  (m_shapePoints.size() - 2)).doubleValue())) - 
  226.       cx;
  227.     
  228.     cx2 *= 50000;
  229.     
  230.     double cy = Math.ceil
  231.       (m_plot2D.
  232.        convertToPanelY(((Double)m_shapePoints.
  233. elementAt(m_shapePoints.size() - 3)).
  234.        doubleValue()));
  235.     double cy2 = Math.ceil
  236.       (m_plot2D.convertToPanelY(((Double)m_shapePoints.
  237.   elementAt(m_shapePoints.size() - 1)).
  238.   doubleValue())) - cy;
  239.     cy2 *= 50000;
  240.     
  241.     
  242.     double cxa = Math.ceil(m_plot2D.convertToPanelX
  243.    (((Double)m_shapePoints.
  244.      elementAt(3)).
  245.     doubleValue()));
  246.     double cxa2 = Math.ceil(m_plot2D.convertToPanelX
  247.     (((Double)m_shapePoints.
  248.       elementAt(1)).
  249.      doubleValue())) - cxa;
  250.     cxa2 *= 50000;
  251.     
  252.     
  253.     double cya = Math.ceil
  254.       (m_plot2D.convertToPanelY
  255.        (((Double)m_shapePoints.elementAt(4)).
  256. doubleValue()));
  257.     double cya2 = Math.ceil
  258.       (m_plot2D.convertToPanelY
  259.        (((Double)m_shapePoints.elementAt(2)).
  260. doubleValue())) - cya;
  261.     
  262.     cya2 *= 50000;
  263.     
  264.     m_shapePoints.setElementAt
  265.       (new Double(m_plot2D.convertToAttribX(cxa2 + cxa)), 1);
  266.     
  267.     m_shapePoints.setElementAt
  268.       (new Double(m_plot2D.convertToAttribY(cy2 + cy)), 
  269.        m_shapePoints.size() - 1);
  270.     
  271.     m_shapePoints.setElementAt
  272.       (new Double(m_plot2D.convertToAttribX(cx2 + cx)), 
  273.        m_shapePoints.size() - 2);
  274.     
  275.     m_shapePoints.setElementAt
  276.       (new Double(m_plot2D.convertToAttribY(cya2 + cya)), 2);
  277.     
  278.     
  279.     //determine how infinity line should be built
  280.     
  281.     cy = Double.POSITIVE_INFINITY;
  282.     cy2 = Double.NEGATIVE_INFINITY;
  283.     if (((Double)m_shapePoints.elementAt(1)).
  284. doubleValue() > 
  285. ((Double)m_shapePoints.elementAt(3)).
  286. doubleValue()) {
  287.       if (((Double)m_shapePoints.elementAt(2)).
  288.   doubleValue() == 
  289.   ((Double)m_shapePoints.elementAt(4)).
  290.   doubleValue()) {
  291. cy = ((Double)m_shapePoints.elementAt(2)).
  292.   doubleValue();
  293.       }
  294.     }
  295.     if (((Double)m_shapePoints.elementAt
  296.  (m_shapePoints.size() - 2)).doubleValue() > 
  297. ((Double)m_shapePoints.elementAt
  298.  (m_shapePoints.size() - 4)).doubleValue()) {
  299.       if (((Double)m_shapePoints.elementAt
  300.    (m_shapePoints.size() - 3)).
  301.   doubleValue() == 
  302.   ((Double)m_shapePoints.elementAt
  303.    (m_shapePoints.size() - 1)).doubleValue()) {
  304. cy2 = ((Double)m_shapePoints.lastElement()).
  305.   doubleValue();
  306.       }
  307.     }
  308.     m_shapePoints.addElement(new Double(cy));
  309.     m_shapePoints.addElement(new Double(cy2));
  310.     
  311.     if (!inPolyline(m_shapePoints, m_plot2D.convertToAttribX
  312.     (e.getX()), 
  313.     m_plot2D.convertToAttribY(e.getY()))) {
  314.       Double tmp = (Double)m_shapePoints.
  315. elementAt(m_shapePoints.size() - 2);
  316.       m_shapePoints.setElementAt
  317. (m_shapePoints.lastElement(), 
  318.  m_shapePoints.size() - 2);
  319.       m_shapePoints.setElementAt
  320. (tmp, m_shapePoints.size() - 1);
  321.     }
  322.     
  323.     if (m_shapes == null) {
  324.       m_shapes = new FastVector(4);
  325.     }
  326.     m_shapes.addElement(m_shapePoints);
  327.     m_submit.setText("Submit");
  328.     m_submit.setActionCommand("Submit");
  329.     
  330.     m_submit.setEnabled(true);
  331.   }
  332.   
  333.   m_shapePoints = null;
  334.   PlotPanel.this.repaint();
  335.   
  336. }
  337. else {
  338.   //then close the shape
  339.   m_createShape = false;
  340.   if (m_shapePoints.size() >= 7) {
  341.     m_shapePoints.addElement(m_shapePoints.elementAt(1));
  342.     m_shapePoints.addElement(m_shapePoints.elementAt(2));
  343.     if (m_shapes == null) {
  344.       m_shapes = new FastVector(4);
  345.     }
  346.     m_shapes.addElement(m_shapePoints);
  347.    
  348.     m_submit.setText("Submit");
  349.     m_submit.setActionCommand("Submit");
  350.     
  351.     m_submit.setEnabled(true);
  352.   }
  353.   m_shapePoints = null;
  354.   PlotPanel.this.repaint();
  355. }
  356. g.dispose();
  357. //repaint();
  358.       }
  359.       else if ((e.getModifiers() & e.BUTTON1_MASK) == e.BUTTON1_MASK) {
  360. //then this is the first point
  361. m_createShape = true;
  362. m_shapePoints = new FastVector(17);
  363. m_shapePoints.addElement(new Double(m_sIndex));
  364. m_shapePoints.addElement(new 
  365.   Double(m_plot2D.convertToAttribX(e.getX()))); //the new point
  366. m_shapePoints.addElement(new 
  367.   Double(m_plot2D.convertToAttribY(e.getY())));
  368. m_newMousePos.width = e.getX();      //the temp mouse point
  369. m_newMousePos.height = e.getY();
  370. Graphics g = m_plot2D.getGraphics();
  371. g.setColor(Color.black);
  372. g.setXORMode(Color.white);
  373. g.drawLine((int)Math.ceil
  374.    (m_plot2D.convertToPanelX(((Double)m_shapePoints.
  375.      elementAt(1)).doubleValue())),
  376.    (int)Math.ceil
  377.    (m_plot2D.convertToPanelY(((Double)m_shapePoints.
  378.      elementAt(2)).doubleValue())),
  379.    m_newMousePos.width, m_newMousePos.height);
  380. g.dispose();
  381.       }
  382.     }
  383.     else {
  384.       if ((e.getModifiers() & InputEvent.BUTTON1_MASK) == 
  385.   InputEvent.BUTTON1_MASK) {
  386. m_plot2D.searchPoints(e.getX(),e.getY(), false);
  387.       } else {
  388. m_plot2D.searchPoints(e.getX(), e.getY(), true);
  389.       }
  390.     }
  391.   }
  392.   
  393.   /////////             
  394.   public void mouseReleased(MouseEvent e) {
  395.     if (m_createShape) {
  396.       if (((Double)m_shapePoints.elementAt(0)).intValue() == 1) {
  397. m_createShape = false;
  398. Graphics g = m_plot2D.getGraphics();
  399. g.setColor(Color.black);
  400. g.setXORMode(Color.white);
  401. g.drawRect(((Double)m_shapePoints.elementAt(1)).
  402.    intValue(), 
  403.    ((Double)m_shapePoints.elementAt(2)).intValue(),
  404.    ((Double)m_shapePoints.elementAt(3)).intValue() -
  405.    ((Double)m_shapePoints.elementAt(1)).intValue(), 
  406.    ((Double)m_shapePoints.elementAt(4)).intValue() -
  407.    ((Double)m_shapePoints.elementAt(2)).intValue());
  408. g.dispose();
  409. if (checkPoints(((Double)m_shapePoints.elementAt(1)).
  410. doubleValue(), 
  411. ((Double)m_shapePoints.elementAt(2)).
  412. doubleValue()) &&
  413.     checkPoints(((Double)m_shapePoints.elementAt(3)).
  414. doubleValue(), 
  415. ((Double)m_shapePoints.elementAt(4)).
  416. doubleValue())) {
  417.   //then the points all land on the screen
  418.   //now do special check for the rectangle
  419.   if (((Double)m_shapePoints.elementAt(1)).doubleValue() <
  420.       ((Double)m_shapePoints.elementAt(3)).doubleValue() 
  421.       &&
  422.       ((Double)m_shapePoints.elementAt(2)).doubleValue() <
  423.       ((Double)m_shapePoints.elementAt(4)).doubleValue()) {
  424.     //then the rectangle is valid
  425.     if (m_shapes == null) {
  426.       m_shapes = new FastVector(2);
  427.     }
  428.     m_shapePoints.setElementAt(new 
  429.       Double(m_plot2D.convertToAttribX(((Double)m_shapePoints.
  430.        elementAt(1)).
  431.       doubleValue())), 1);
  432.     m_shapePoints.setElementAt(new 
  433.       Double(m_plot2D.convertToAttribY(((Double)m_shapePoints.
  434.        elementAt(2)).
  435.       doubleValue())), 2);
  436.     m_shapePoints.setElementAt(new 
  437.       Double(m_plot2D.convertToAttribX(((Double)m_shapePoints.
  438.        elementAt(3)).
  439.       doubleValue())), 3);
  440.     m_shapePoints.setElementAt(new 
  441.       Double(m_plot2D.convertToAttribY(((Double)m_shapePoints.
  442.        elementAt(4)).
  443.       doubleValue())), 4);
  444.     
  445.     m_shapes.addElement(m_shapePoints);
  446.     
  447.     m_submit.setText("Submit");
  448.     m_submit.setActionCommand("Submit");
  449.     
  450.     m_submit.setEnabled(true);
  451.     PlotPanel.this.repaint();
  452.   }
  453. }
  454. m_shapePoints = null;
  455.       }
  456.     }
  457.   }
  458. });
  459.       
  460.       this.addMouseMotionListener(new MouseMotionAdapter() {
  461.   public void mouseDragged(MouseEvent e) {
  462.     //check if the user is dragging a box
  463.     if (m_createShape) {
  464.       if (((Double)m_shapePoints.elementAt(0)).intValue() == 1) {
  465. Graphics g = m_plot2D.getGraphics();
  466. g.setColor(Color.black);
  467. g.setXORMode(Color.white);
  468. g.drawRect(((Double)m_shapePoints.elementAt(1)).intValue(), 
  469.    ((Double)m_shapePoints.elementAt(2)).intValue(),
  470.    ((Double)m_shapePoints.elementAt(3)).intValue() -
  471.    ((Double)m_shapePoints.elementAt(1)).intValue(), 
  472.    ((Double)m_shapePoints.elementAt(4)).intValue() -
  473.    ((Double)m_shapePoints.elementAt(2)).intValue());
  474. m_shapePoints.setElementAt(new Double(e.getX()), 3);
  475. m_shapePoints.setElementAt(new Double(e.getY()), 4);
  476. g.drawRect(((Double)m_shapePoints.elementAt(1)).intValue(), 
  477.    ((Double)m_shapePoints.elementAt(2)).intValue(),
  478.    ((Double)m_shapePoints.elementAt(3)).intValue() -
  479.    ((Double)m_shapePoints.elementAt(1)).intValue(), 
  480.    ((Double)m_shapePoints.elementAt(4)).intValue() -
  481.    ((Double)m_shapePoints.elementAt(2)).intValue());
  482. g.dispose();
  483.       }
  484.     }
  485.   }
  486.   
  487.   public void mouseMoved(MouseEvent e) {
  488.     if (m_createShape) {
  489.       if (((Double)m_shapePoints.elementAt(0)).intValue() == 2 || 
  490.   ((Double)m_shapePoints.elementAt(0)).intValue() == 3) {
  491. Graphics g = m_plot2D.getGraphics();
  492. g.setColor(Color.black);
  493. g.setXORMode(Color.white);
  494. g.drawLine((int)Math.ceil(m_plot2D.convertToPanelX
  495.   (((Double)m_shapePoints.elementAt
  496.     (m_shapePoints.size() - 2)).
  497.    doubleValue())),
  498.    (int)Math.ceil(m_plot2D.convertToPanelY
  499.   (((Double)m_shapePoints.elementAt
  500.     (m_shapePoints.size() - 1)).
  501.    doubleValue())),
  502.    m_newMousePos.width, m_newMousePos.height);
  503. m_newMousePos.width = e.getX();
  504. m_newMousePos.height = e.getY();
  505. g.drawLine((int)Math.ceil(m_plot2D.convertToPanelX
  506.   (((Double)m_shapePoints.elementAt
  507.     (m_shapePoints.size() - 2)).
  508.    doubleValue())),
  509.    (int)Math.ceil(m_plot2D.convertToPanelY
  510.   (((Double)m_shapePoints.elementAt
  511.     (m_shapePoints.size() - 1)).
  512.    doubleValue())),
  513.    m_newMousePos.width, m_newMousePos.height);
  514. g.dispose();
  515.       }
  516.     }
  517.   }
  518. });
  519.       
  520.       m_submit.addActionListener(new ActionListener() {
  521.   public void actionPerformed(ActionEvent e) {
  522.  
  523.     if (e.getActionCommand().equals("Submit")) {
  524.       if (m_splitListener != null && m_shapes != null) {
  525. //then send the split to the listener
  526. Instances sub_set1 = new Instances(m_plot2D.getMasterPlot().
  527.    m_plotInstances, 500);
  528. Instances sub_set2 = new Instances(m_plot2D.getMasterPlot().
  529.    m_plotInstances, 500);
  530. if (m_plot2D.getMasterPlot().
  531.     m_plotInstances != null) {
  532.   
  533.   for (int noa = 0 ; noa < m_plot2D.getMasterPlot().
  534.  m_plotInstances.numInstances(); noa++) {
  535.     if (!m_plot2D.getMasterPlot().
  536. m_plotInstances.instance(noa).isMissing(m_xIndex) &&
  537. !m_plot2D.getMasterPlot().
  538. m_plotInstances.instance(noa).isMissing(m_yIndex)){
  539.       
  540.       if (inSplit(m_plot2D.getMasterPlot().
  541.   m_plotInstances.instance(noa))) {
  542. sub_set1.add(m_plot2D.getMasterPlot().
  543.      m_plotInstances.instance(noa));
  544.       }
  545.       else {
  546. sub_set2.add(m_plot2D.getMasterPlot().
  547.      m_plotInstances.instance(noa));
  548.       }
  549.     }
  550.   }
  551.   FastVector tmp = m_shapes;
  552.   cancelShapes();
  553.   m_splitListener.userDataEvent(new 
  554.     VisualizePanelEvent(tmp, sub_set1, sub_set2, m_xIndex, 
  555. m_yIndex));
  556. }
  557.       }
  558.       else if (m_shapes != null && 
  559.        m_plot2D.getMasterPlot().m_plotInstances != null) { 
  560. Instances sub_set1 = new Instances(m_plot2D.getMasterPlot().
  561.    m_plotInstances, 500);
  562. int count = 0;
  563. for (int noa = 0 ; noa < m_plot2D.getMasterPlot().
  564.        m_plotInstances.numInstances(); noa++) {
  565.   if (inSplit(m_plot2D.getMasterPlot().
  566.       m_plotInstances.instance(noa))) {
  567.     sub_set1.add(m_plot2D.getMasterPlot().
  568.  m_plotInstances.instance(noa));
  569.     count++;
  570.   }
  571.   
  572. }
  573. int [] nSizes = null;
  574. int [] nTypes = null;
  575. int x = m_xIndex;
  576. int y = m_yIndex;
  577. if (m_originalPlot == null) {
  578.   //this sets these instances as the instances 
  579.   //to go back to.
  580.   m_originalPlot = m_plot2D.getMasterPlot();
  581. }
  582. if (count > 0) {
  583.   nTypes = new int[count];
  584.   nSizes = new int[count];
  585.   count = 0;
  586.   for (int noa = 0; noa < m_plot2D.getMasterPlot().
  587.  m_plotInstances.numInstances(); 
  588.        noa++) {
  589.     if (inSplit(m_plot2D.getMasterPlot().
  590. m_plotInstances.instance(noa))) {
  591.       nTypes[count] = m_plot2D.getMasterPlot().
  592. m_shapeType[noa];
  593.       nSizes[count] = m_plot2D.getMasterPlot().
  594. m_shapeSize[noa];
  595.       count++;
  596.     }
  597.   }
  598. }
  599. cancelShapes();
  600. PlotData2D newPlot = new PlotData2D(sub_set1);
  601. try {
  602.   newPlot.setShapeSize(nSizes);
  603.   newPlot.setShapeType(nTypes);
  604.   m_plot2D.removeAllPlots();
  605.   
  606.   VisualizePanel.this.addPlot(newPlot);
  607. } catch (Exception ex) {
  608.   System.err.println(ex);
  609.   ex.printStackTrace();
  610. }
  611. try {
  612.   VisualizePanel.this.setXIndex(x);
  613.   VisualizePanel.this.setYIndex(y);
  614. } catch(Exception er) {
  615.   System.out.println("Error : " + er);
  616.   //  System.out.println("Part of user input so had to" +
  617.   //  " catch here");
  618. }
  619.       }
  620.     }
  621.     else if (e.getActionCommand().equals("Reset")) {
  622.       int x = m_xIndex;
  623.       int y = m_yIndex;
  624.       m_plot2D.removeAllPlots();
  625.       try {
  626. VisualizePanel.this.addPlot(m_originalPlot);
  627.       } catch (Exception ex) {
  628. System.err.println(ex);
  629. ex.printStackTrace();
  630.       }
  631.       try {
  632. VisualizePanel.this.setXIndex(x);
  633. VisualizePanel.this.setYIndex(y);
  634.       } catch(Exception er) {
  635. System.out.println("Error : " + er);
  636.       }
  637.     }
  638.   }  
  639. });
  640.       m_cancel.addActionListener(new ActionListener() {
  641.   public void actionPerformed(ActionEvent e) {
  642.     cancelShapes();
  643.     PlotPanel.this.repaint();
  644.   }
  645. });
  646.       ////////////
  647.     }
  648.     
  649.     /**
  650.      * @return The FastVector containing all the shapes.
  651.      */
  652.     public FastVector getShapes() {
  653.       
  654.       return m_shapes;
  655.     }
  656.     
  657.     /**
  658.      * Sets the list of shapes to empty and also cancels
  659.      * the current shape being drawn (if applicable).
  660.      */
  661.     public void cancelShapes() {
  662.        
  663.       if (m_splitListener == null) {
  664. m_submit.setText("Reset");
  665. m_submit.setActionCommand("Reset");
  666. if (m_originalPlot == null || 
  667.     m_originalPlot.m_plotInstances == m_plotInstances) {
  668.   m_submit.setEnabled(false);
  669. }
  670. else {
  671.   m_submit.setEnabled(true);
  672. }
  673.       }
  674.       else {
  675. m_submit.setEnabled(false);
  676.       }
  677.       
  678.       m_createShape = false;
  679.       m_shapePoints = null;
  680.       m_shapes = null;
  681.       this.repaint();
  682.     }
  683.     /**
  684.      * This can be used to set the shapes that should appear.
  685.      * @param v The list of shapes.
  686.      */
  687.     public void setShapes(FastVector v) {
  688.       //note that this method should be fine for doubles,
  689.       //but anything else that uses something other than doubles 
  690.       //(or uneditable objects) could have unsafe copies.
  691.       if (v != null) {
  692. FastVector temp;
  693. m_shapes = new FastVector(v.size());
  694. for (int noa = 0; noa < v.size(); noa++) {
  695.   temp = new FastVector(((FastVector)v.elementAt(noa)).size());
  696.   m_shapes.addElement(temp);
  697.   for (int nob = 0; nob < ((FastVector)v.elementAt(noa)).size()
  698.  ; nob++) {
  699.     
  700.     temp.addElement(((FastVector)v.elementAt(noa)).elementAt(nob));
  701.     
  702.   }
  703. }
  704.       }
  705.       else {
  706. m_shapes = null;
  707.       }
  708.       this.repaint();
  709.     }
  710.     
  711.     /** 
  712.      * This will check the values of the screen points passed and make sure 
  713.      * that they land on the screen
  714.      * @param x1 The x coord.
  715.      * @param y1 The y coord.
  716.      */
  717.     private boolean checkPoints(double x1, double y1) {
  718.       if (x1 < 0 || x1 > this.getSize().width || y1 < 0 
  719.   || y1 > this.getSize().height) {
  720. return false;
  721.       }
  722.       return true;
  723.     }
  724.     
  725.     /**
  726.      * This will check if an instance is inside or outside of the current
  727.      * shapes.
  728.      * @param i The instance to check.
  729.      * @return True if 'i' falls inside the shapes, false otherwise.
  730.      */
  731.     public boolean inSplit(Instance i) {
  732.       //this will check if the instance lies inside the shapes or not
  733.       
  734.       if (m_shapes != null) {
  735. FastVector stmp;
  736. double x1, y1, x2, y2;
  737. for (int noa = 0; noa < m_shapes.size(); noa++) {
  738.   stmp = (FastVector)m_shapes.elementAt(noa);
  739.   if (((Double)stmp.elementAt(0)).intValue() == 1) {
  740.     //then rectangle
  741.     x1 = ((Double)stmp.elementAt(1)).doubleValue();
  742.     y1 = ((Double)stmp.elementAt(2)).doubleValue();
  743.     x2 = ((Double)stmp.elementAt(3)).doubleValue();
  744.     y2 = ((Double)stmp.elementAt(4)).doubleValue();
  745.     if (i.value(m_xIndex) >= x1 && i.value(m_xIndex) <= x2 &&
  746. i.value(m_yIndex) <= y1 && i.value(m_yIndex) >= y2) {
  747.       //then is inside split so return true;
  748.       return true;
  749.     }
  750.   }
  751.   else if (((Double)stmp.elementAt(0)).intValue() == 2) {
  752.     //then polygon
  753.     if (inPoly(stmp, i.value(m_xIndex), i.value(m_yIndex))) {
  754.       return true;
  755.     }
  756.   }
  757.   else if (((Double)stmp.elementAt(0)).intValue() == 3) {
  758.     //then polyline
  759.     if (inPolyline(stmp, i.value(m_xIndex), i.value(m_yIndex))) {
  760.       return true;
  761.     }
  762.   }
  763. }
  764.       }
  765.       return false;
  766.     }
  767.     
  768.     /**
  769.      * Checks to see if the coordinate passed is inside the ployline
  770.      * passed, Note that this is done using attribute values and not there
  771.      * respective screen values.
  772.      * @param ob The polyline.
  773.      * @param x The x coord.
  774.      * @param y The y coord.
  775.      * @return True if it falls inside the polyline, false otherwise.
  776.      */
  777.     private boolean inPolyline(FastVector ob, double x, double y) {
  778.       //this works similar to the inPoly below except that
  779.       //the first and last lines are treated as extending infinite in one 
  780.       //direction and 
  781.       //then infinitly in the x dirction their is a line that will 
  782.       //normaly be infinite but
  783.       //can be finite in one or both directions
  784.       
  785.       int countx = 0;
  786.       double vecx, vecy;
  787.       double change;
  788.       double x1, y1, x2, y2;
  789.       
  790.       for (int noa = 1; noa < ob.size() - 4; noa+= 2) {
  791. y1 = ((Double)ob.elementAt(noa+1)).doubleValue();
  792. y2 = ((Double)ob.elementAt(noa+3)).doubleValue();
  793. x1 = ((Double)ob.elementAt(noa)).doubleValue();
  794. x2 = ((Double)ob.elementAt(noa+2)).doubleValue();
  795. //System.err.println(y1 + " " + y2 + " " + x1 + " " + x2);
  796. vecy = y2 - y1;
  797. vecx = x2 - x1;
  798. if (noa == 1 && noa == ob.size() - 6) {
  799.   //then do special test first and last edge
  800.   if (vecy != 0) {
  801.     change = (y - y1) / vecy;
  802.     if (vecx * change + x1 >= x) {
  803.       //then intersection
  804.       countx++;
  805.     }
  806.   }
  807. }
  808. else if (noa == 1) {
  809.   if ((y < y2 && vecy > 0) || (y > y2 && vecy < 0)) {
  810.     //now just determine intersection or not
  811.     change = (y - y1) / vecy;
  812.     if (vecx * change + x1 >= x) {
  813.       //then intersection on horiz
  814.       countx++;
  815.     }
  816.   }
  817. }
  818. else if (noa == ob.size() - 6) {
  819.   //then do special test on last edge
  820.   if ((y <= y1 && vecy < 0) || (y >= y1 && vecy > 0)) {
  821.     change = (y - y1) / vecy;
  822.     if (vecx * change + x1 >= x) {
  823.       countx++;
  824.     }
  825.   }
  826. }
  827. else if ((y1 <= y && y < y2) || (y2 < y && y <= y1)) {
  828.   //then continue tests.
  829.   if (vecy == 0) {
  830.     //then lines are parallel stop tests in 
  831.     //ofcourse it should never make it this far
  832.   }
  833.   else {
  834.     change = (y - y1) / vecy;
  835.     if (vecx * change + x1 >= x) {
  836.       //then intersects on horiz
  837.       countx++;
  838.     }
  839.   }
  840. }
  841.       }
  842.       
  843.       //now check for intersection with the infinity line
  844.       y1 = ((Double)ob.elementAt(ob.size() - 2)).doubleValue();
  845.       y2 = ((Double)ob.elementAt(ob.size() - 1)).doubleValue();
  846.       
  847.       if (y1 > y2) {
  848. //then normal line
  849. if (y1 >= y && y > y2) {
  850.   countx++;
  851. }
  852.       }
  853.       else {
  854. //then the line segment is inverted
  855. if (y1 >= y || y > y2) {
  856.   countx++;
  857. }
  858.       }
  859.       
  860.       if ((countx % 2) == 1) {
  861. return true;
  862.       }
  863.       else {
  864. return false;
  865.       }
  866.     }
  867.     /**
  868.      * This checks to see if The coordinate passed is inside
  869.      * the polygon that was passed.
  870.      * @param ob The polygon.
  871.      * @param x The x coord.
  872.      * @param y The y coord.
  873.      * @return True if the coordinate is in the polygon, false otherwise.
  874.      */
  875.     private boolean inPoly(FastVector ob, double x, double y) {
  876.       //brief on how this works
  877.       //it draws a line horizontally from the point to the right (infinitly)
  878.       //it then sees how many lines of the polygon intersect this, 
  879.       //if it is even then the point is
  880.       // outside the polygon if it's odd then it's inside the polygon
  881.       int count = 0;
  882.       double vecx, vecy;
  883.       double change;
  884.       double x1, y1, x2, y2;
  885.       for (int noa = 1; noa < ob.size() - 2; noa += 2) {
  886. y1 = ((Double)ob.elementAt(noa+1)).doubleValue();
  887. y2 = ((Double)ob.elementAt(noa+3)).doubleValue();
  888. if ((y1 <= y && y < y2) || (y2 < y && y <= y1)) {
  889.   //then continue tests.
  890.   vecy = y2 - y1;
  891.   if (vecy == 0) {
  892.     //then lines are parallel stop tests for this line
  893.   }
  894.   else {
  895.     x1 = ((Double)ob.elementAt(noa)).doubleValue();
  896.     x2 = ((Double)ob.elementAt(noa+2)).doubleValue();
  897.     vecx = x2 - x1;
  898.     change = (y - y1) / vecy;
  899.     if (vecx * change + x1 >= x) {
  900.       //then add to count as an intersected line
  901.       count++;
  902.     }
  903.   }
  904. }
  905.       }
  906.       if ((count % 2) == 1) {
  907. //then lies inside polygon
  908. //System.out.println("in");
  909. return true;
  910.       }
  911.       else {
  912. //System.out.println("out");
  913. return false;
  914.       }
  915.       //System.out.println("WHAT?!?!?!?!!?!??!?!");
  916.       //return false;
  917.     }
  918.     /**
  919.      * Set level of jitter and repaint the plot using the new jitter value
  920.      * @param j the level of jitter
  921.      */
  922.     public void setJitter(int j) {
  923.       m_plot2D.setJitter(j);
  924.     }
  925.     /**
  926.      * Set the index of the attribute to go on the x axis
  927.      * @param x the index of the attribute to use on the x axis
  928.      */
  929.     public void setXindex(int x) {
  930.       // this just ensures that the shapes get disposed of 
  931.       //if the attribs change
  932.       if (x != m_xIndex) {
  933. cancelShapes();
  934.       }
  935.       m_xIndex = x;
  936.       m_plot2D.setXindex(x);
  937.       if (m_showAttBars) {
  938. m_attrib.setX(x);
  939.       }
  940.       //      this.repaint();
  941.     }
  942.     
  943.     /**
  944.      * Set the index of the attribute to go on the y axis
  945.      * @param y the index of the attribute to use on the y axis
  946.      */
  947.     public void setYindex(int y) {
  948.     
  949.       // this just ensures that the shapes get disposed of 
  950.       //if the attribs change
  951.       if (y != m_yIndex) {
  952. cancelShapes();
  953.       }
  954.       m_yIndex = y;
  955.       m_plot2D.setYindex(y);
  956.       if (m_showAttBars) {
  957. m_attrib.setY(y);
  958.       }
  959.       //      this.repaint();
  960.     }
  961.     /**
  962.      * Set the index of the attribute to use for colouring
  963.      * @param c the index of the attribute to use for colouring
  964.      */
  965.     public void setCindex(int c) {
  966.       m_cIndex = c;
  967.       m_plot2D.setCindex(c);
  968.       if (m_showAttBars) {
  969. m_attrib.setCindex(c, m_plot2D.getMaxC(), m_plot2D.getMinC());
  970.       }
  971.       m_classPanel.setCindex(c);
  972.       this.repaint();
  973.     }
  974.     /**
  975.      * Set the index of the attribute to use for the shape.
  976.      * @param s the index of the attribute to use for the shape
  977.      */
  978.     public void setSindex(int s) {
  979.       if (s != m_sIndex) {
  980. m_shapePoints = null;
  981. m_createShape = false;
  982.       }
  983.       m_sIndex = s;
  984.       this.repaint();
  985.     }
  986.     /**
  987.      * Clears all existing plots and sets a new master plot
  988.      * @param newPlot the new master plot
  989.      * @exception Exception if plot could not be added
  990.      */
  991.     public void setMasterPlot(PlotData2D newPlot) throws Exception {
  992.       m_plot2D.removeAllPlots();
  993.       this.addPlot(newPlot);
  994.     }
  995.     /**
  996.      * Adds a plot. If there are no plots so far this plot becomes
  997.      * the master plot and, if it has a custom colour defined then
  998.      * the class panel is removed.
  999.      * @param newPlot the plot to add.
  1000.      * @exception Exception if plot could not be added
  1001.      */
  1002.     public void addPlot(PlotData2D newPlot) throws Exception {
  1003.       if (m_plot2D.getPlots().size() == 0) {
  1004. m_plot2D.addPlot(newPlot);
  1005. if (m_plotSurround.getComponentCount() > 1 && 
  1006.     m_plotSurround.getComponent(1) == m_attrib &&
  1007.     m_showAttBars) {
  1008.   try {
  1009.     m_attrib.setInstances(newPlot.m_plotInstances);
  1010.     m_attrib.setCindex(0);m_attrib.setX(0); m_attrib.setY(0);
  1011.   } catch (Exception ex) {
  1012.     // more attributes than the panel can handle?
  1013.     // Due to hard coded constraints in GridBagLayout
  1014.     m_plotSurround.remove(m_attrib);
  1015.     System.err.println("Warning : data contains more attributes "
  1016.        +"than can be displayed as attribute bars.");
  1017.     if (m_Log != null) {
  1018.       m_Log.logMessage("Warning : data contains more attributes "
  1019.        +"than can be displayed as attribute bars.");
  1020.     }
  1021.   }
  1022. } else if (m_showAttBars) {
  1023.   try {
  1024.     m_attrib.setInstances(newPlot.m_plotInstances);
  1025.     m_attrib.setCindex(0);m_attrib.setX(0); m_attrib.setY(0);
  1026.     GridBagConstraints constraints = new GridBagConstraints();
  1027.     constraints.fill = constraints.BOTH;
  1028.     constraints.insets = new Insets(0, 0, 0, 0);
  1029.     constraints.gridx=4;constraints.gridy=0;constraints.weightx=1;
  1030.     constraints.gridwidth=1;constraints.gridheight=1;
  1031.     constraints.weighty=5;
  1032.     m_plotSurround.add(m_attrib, constraints);
  1033.   } catch (Exception ex) {
  1034.     System.err.println("Warning : data contains more attributes "
  1035.        +"than can be displayed as attribute bars.");
  1036.     if (m_Log != null) {
  1037.       m_Log.logMessage("Warning : data contains more attributes "
  1038.        +"than can be displayed as attribute bars.");
  1039.     }
  1040.   }
  1041. }
  1042. m_classPanel.setInstances(newPlot.m_plotInstances);
  1043. plotReset(newPlot.m_plotInstances, newPlot.getCindex());
  1044. if (newPlot.m_useCustomColour) {
  1045.   VisualizePanel.this.remove(m_classSurround);
  1046.   switchToLegend();
  1047.   m_legendPanel.setPlotList(m_plot2D.getPlots());
  1048.   m_ColourCombo.setEnabled(false);
  1049. }
  1050.       } else  {
  1051. if (!newPlot.m_useCustomColour) {
  1052.   VisualizePanel.this.add(m_classSurround, BorderLayout.SOUTH);
  1053.   m_ColourCombo.setEnabled(true);
  1054. }
  1055. if (m_plot2D.getPlots().size() == 1) {
  1056.   switchToLegend();
  1057. }
  1058. m_plot2D.addPlot(newPlot);
  1059. m_legendPanel.setPlotList(m_plot2D.getPlots());
  1060.       }
  1061.     }
  1062.     /**
  1063.      * Remove the attibute panel and replace it with the legend panel
  1064.      */
  1065.     protected void switchToLegend() {
  1066.       if (m_plotSurround.getComponentCount() > 1 && 
  1067.   m_plotSurround.getComponent(1) == m_attrib) {
  1068. m_plotSurround.remove(m_attrib);
  1069.       }
  1070.       if (m_plotSurround.getComponentCount() > 1 &&
  1071.   m_plotSurround.getComponent(1) == m_legendPanel) {
  1072. return;
  1073.       }
  1074.       GridBagConstraints constraints = new GridBagConstraints();
  1075.       constraints.fill = constraints.BOTH;
  1076.       constraints.insets = new Insets(0, 0, 0, 0);
  1077.       constraints.gridx=4;constraints.gridy=0;constraints.weightx=1;
  1078.       constraints.gridwidth=1;constraints.gridheight=1;
  1079.       constraints.weighty=5;
  1080.       m_plotSurround.add(m_legendPanel, constraints);
  1081.       setSindex(0);
  1082.       m_ShapeCombo.setEnabled(false);
  1083.     }
  1084.     /**
  1085.      * Reset the visualize panel's buttons and the plot panels instances
  1086.      */
  1087.     private void plotReset(Instances inst, int cIndex) {
  1088.       if (m_splitListener == null) {
  1089. m_submit.setText("Reset");
  1090. m_submit.setActionCommand("Reset");
  1091. //if (m_origInstances == null || m_origInstances == inst) {
  1092. if (m_originalPlot == null || m_originalPlot.m_plotInstances == inst) {
  1093.   m_submit.setEnabled(false);
  1094. }
  1095. else {
  1096.   m_submit.setEnabled(true);
  1097. }
  1098.       } 
  1099.       else {
  1100. m_submit.setEnabled(false);
  1101.       }
  1102.       m_plotInstances = inst;
  1103.       if (m_splitListener != null) {
  1104. m_plotInstances.randomize(new Random());
  1105.       }
  1106.       m_xIndex=0;
  1107.       m_yIndex=0;
  1108.       m_cIndex=cIndex;
  1109.       cancelShapes();
  1110.     }
  1111.     /**
  1112.      * Set a list of colours to use for plotting points
  1113.      * @param cols a list of java.awt.Colors
  1114.      */
  1115.     public void setColours(FastVector cols) {
  1116.       m_plot2D.setColours(cols);
  1117.       m_colorList = cols;
  1118.     }
  1119.     
  1120.     /**
  1121.      * This will draw the shapes created onto the panel.
  1122.      * For best visual, this should be the first thing to be drawn
  1123.      * (and it currently is).
  1124.      * @param gx The graphics context.
  1125.      */
  1126.     private void drawShapes(Graphics gx) {
  1127.       //FastVector tmp = m_plot.getShapes();
  1128.       
  1129.       if (m_shapes != null) {
  1130. FastVector stmp;
  1131. int x1, y1, x2, y2;
  1132. for (int noa = 0; noa < m_shapes.size(); noa++) {
  1133.   stmp = (FastVector)m_shapes.elementAt(noa);
  1134.   if (((Double)stmp.elementAt(0)).intValue() == 1) {
  1135.     //then rectangle
  1136.     x1 = (int)m_plot2D.convertToPanelX(((Double)stmp.elementAt(1)).
  1137.       doubleValue());
  1138.     y1 = (int)m_plot2D.convertToPanelY(((Double)stmp.elementAt(2)).
  1139.       doubleValue());
  1140.     x2 = (int)m_plot2D.convertToPanelX(((Double)stmp.elementAt(3)).
  1141.       doubleValue());
  1142.     y2 = (int)m_plot2D.convertToPanelY(((Double)stmp.elementAt(4)).
  1143.       doubleValue());
  1144.     
  1145.     gx.setColor(Color.gray);
  1146.     gx.fillRect(x1, y1, x2 - x1, y2 - y1);
  1147.     gx.setColor(Color.black);
  1148.     gx.drawRect(x1, y1, x2 - x1, y2 - y1);
  1149.     
  1150.   }
  1151.   else if (((Double)stmp.elementAt(0)).intValue() == 2) {
  1152.     //then polygon
  1153.     int[] ar1, ar2;
  1154.     ar1 = getXCoords(stmp);
  1155.     ar2 = getYCoords(stmp);
  1156.     gx.setColor(Color.gray);
  1157.     gx.fillPolygon(ar1, ar2, (stmp.size() - 1) / 2); 
  1158.     gx.setColor(Color.black);
  1159.     gx.drawPolyline(ar1, ar2, (stmp.size() - 1) / 2);
  1160.   }
  1161.   else if (((Double)stmp.elementAt(0)).intValue() == 3) {
  1162.     //then polyline
  1163.     int[] ar1, ar2;
  1164.     FastVector tmp = makePolygon(stmp);
  1165.     ar1 = getXCoords(tmp);
  1166.     ar2 = getYCoords(tmp);
  1167.     
  1168.     gx.setColor(Color.gray);
  1169.     gx.fillPolygon(ar1, ar2, (tmp.size() - 1) / 2);
  1170.     gx.setColor(Color.black);
  1171.     gx.drawPolyline(ar1, ar2, (tmp.size() - 1) / 2);
  1172.   }
  1173. }
  1174.       }
  1175.       
  1176.       if (m_shapePoints != null) {
  1177. //then the current image needs to be refreshed
  1178. if (((Double)m_shapePoints.elementAt(0)).intValue() == 2 ||
  1179.     ((Double)m_shapePoints.elementAt(0)).intValue() == 3) {
  1180.   gx.setColor(Color.black);
  1181.   gx.setXORMode(Color.white);
  1182.   int[] ar1, ar2;
  1183.   ar1 = getXCoords(m_shapePoints);
  1184.   ar2 = getYCoords(m_shapePoints);
  1185.   gx.drawPolyline(ar1, ar2, (m_shapePoints.size() - 1) / 2);
  1186.   m_newMousePos.width = (int)Math.ceil
  1187.     (m_plot2D.convertToPanelX(((Double)m_shapePoints.elementAt
  1188.       (m_shapePoints.size() - 2)).doubleValue()));
  1189.   
  1190.   m_newMousePos.height = (int)Math.ceil
  1191.     (m_plot2D.convertToPanelY(((Double)m_shapePoints.elementAt
  1192.       (m_shapePoints.size() - 1)).doubleValue()));
  1193.   
  1194.   gx.drawLine((int)Math.ceil
  1195.      (m_plot2D.convertToPanelX(((Double)m_shapePoints.elementAt
  1196. (m_shapePoints.size() - 2)).
  1197.        doubleValue())),
  1198.       (int)Math.ceil(m_plot2D.convertToPanelY
  1199.      (((Double)m_shapePoints.elementAt
  1200.        (m_shapePoints.size() - 1)).
  1201.       doubleValue())),
  1202.       m_newMousePos.width, m_newMousePos.height);
  1203.   gx.setPaintMode();
  1204. }
  1205.       }
  1206.     }
  1207.     
  1208.     /**
  1209.      * This is called for polylines to see where there two lines that
  1210.      * extend to infinity cut the border of the view.
  1211.      * @param x1 an x point along the line
  1212.      * @param y1 the accompanying y point.
  1213.      * @param x2 The x coord of the end point of the line.
  1214.      * @param y2 The y coord of the end point of the line.
  1215.      * @param x 0 or the width of the border line if it has one.
  1216.      * @param y 0 or the height of the border line if it has one.
  1217.      * @param offset The offset for the border line (either for x or y
  1218.      * dependant on which one doesn't change).
  1219.      * @return double array that contains the coordinate for the point 
  1220.      * that the polyline cuts the border (which ever side that may be).
  1221.      */
  1222.     private double[] lineIntersect(double x1, double y1, double x2, double y2, 
  1223.    double x, double y, double offset) {
  1224.       //the first 4 params are thestart and end points of a line
  1225.       //the next param is either 0 for no change in x or change in x, 
  1226.       //the next param is the same for y
  1227.       //the final 1 is the offset for either x or y (which ever has no change)
  1228.       double xval;
  1229.       double yval;
  1230.       double xn = -100, yn = -100;
  1231.       double change;
  1232.       if (x == 0) {
  1233. if ((x1 <= offset && offset < x2) || (x1 >= offset && offset > x2)) {
  1234.   //then continue
  1235.   xval = x1 - x2;
  1236.   change = (offset - x2) / xval;
  1237.   yn = (y1 - y2) * change + y2;
  1238.   if (0 <= yn && yn <= y) {
  1239.     //then good
  1240.     xn = offset;
  1241.   }
  1242.   else {
  1243.     //no intersect
  1244.     xn = -100;
  1245.   }
  1246. }
  1247.       }
  1248.       else if (y == 0) {
  1249. if ((y1 <= offset && offset < y2) || (y1 >= offset && offset > y2)) {
  1250.   //the continue
  1251.   yval = (y1 - y2);
  1252.   change = (offset - y2) / yval;
  1253.   xn = (x1 - x2) * change + x2;
  1254.   if (0 <= xn && xn <= x) {
  1255.     //then good
  1256.     yn = offset;
  1257.   }
  1258.   else {
  1259.     xn = -100;
  1260.   }
  1261. }
  1262.       }
  1263.       double[] ret = new double[2];
  1264.       ret[0] = xn;
  1265.       ret[1] = yn;
  1266.       return ret;
  1267.     }
  1268.     /**
  1269.      * This will convert a polyline to a polygon for drawing purposes
  1270.      * So that I can simply use the polygon drawing function.
  1271.      * @param v The polyline to convert.
  1272.      * @return A FastVector containing the polygon.
  1273.      */
  1274.     private FastVector makePolygon(FastVector v) {
  1275.       FastVector building = new FastVector(v.size() + 10);
  1276.       double x1, y1, x2, y2;
  1277.       int edge1 = 0, edge2 = 0;
  1278.       for (int noa = 0; noa < v.size() - 2; noa++) {
  1279. building.addElement(new Double(((Double)v.elementAt(noa)).
  1280.        doubleValue()));
  1281.       }
  1282.       
  1283.       //now clip the lines
  1284.       double[] new_coords;
  1285.       //note lineIntersect , expects the values to have been converted to 
  1286.       //screen coords
  1287.       //note the first point passed is the one that gets shifted.
  1288.       x1 = m_plot2D.convertToPanelX(((Double)v.elementAt(1)).doubleValue());
  1289.       y1 = m_plot2D.convertToPanelY(((Double)v.elementAt(2)).doubleValue());
  1290.       x2 = m_plot2D.convertToPanelX(((Double)v.elementAt(3)).doubleValue());
  1291.       y2 = m_plot2D.convertToPanelY(((Double)v.elementAt(4)).doubleValue());
  1292.       if (x1 < 0) {
  1293. //test left
  1294. new_coords = lineIntersect(x1, y1, x2, y2, 0, this.getHeight(), 0);
  1295. edge1 = 0;
  1296. if (new_coords[0] < 0) {
  1297.   //then not left
  1298.   if (y1 < 0) {
  1299.     //test top
  1300.     new_coords = lineIntersect(x1, y1, x2, y2, this.getWidth(), 0, 0);
  1301.     edge1 = 1;
  1302.   }
  1303.   else {
  1304.     //test bottom
  1305.     new_coords = lineIntersect(x1, y1, x2, y2, this.getWidth(), 0, 
  1306.        this.getHeight());
  1307.     edge1 = 3;
  1308.   }
  1309. }
  1310.       }
  1311.       else if (x1 > this.getWidth()) {
  1312. //test right
  1313. new_coords = lineIntersect(x1, y1, x2, y2, 0, this.getHeight(), 
  1314.    this.getWidth());
  1315. edge1 = 2;
  1316. if (new_coords[0] < 0) {
  1317.   //then not right
  1318.   if (y1 < 0) {
  1319.     //test top
  1320.     new_coords = lineIntersect(x1, y1, x2, y2, this.getWidth(), 0, 0);
  1321.     edge1 = 1;
  1322.   }
  1323.   else {
  1324.     //test bottom
  1325.     new_coords = lineIntersect(x1, y1, x2, y2, this.getWidth(), 0, 
  1326.        this.getHeight());
  1327.     edge1 = 3;
  1328.   }
  1329. }
  1330.       }
  1331.       else if (y1 < 0) {
  1332. //test top
  1333. new_coords = lineIntersect(x1, y1, x2, y2, this.getWidth(), 0, 0);
  1334. edge1 = 1;
  1335.       }
  1336.       else {
  1337. //test bottom
  1338. new_coords = lineIntersect(x1, y1, x2, y2, this.getWidth(), 0, 
  1339.    this.getHeight());
  1340. edge1 = 3;
  1341.       }
  1342.       
  1343.       building.setElementAt(new 
  1344. Double(m_plot2D.convertToAttribX(new_coords[0])), 1);
  1345.       building.setElementAt(new 
  1346. Double(m_plot2D.convertToAttribY(new_coords[1])), 2);
  1347.       x1 = m_plot2D.convertToPanelX(((Double)v.elementAt(v.size() - 4)).
  1348.     doubleValue());
  1349.       y1 = m_plot2D.convertToPanelY(((Double)v.elementAt(v.size() - 3)).
  1350.     doubleValue());
  1351.       x2 = m_plot2D.convertToPanelX(((Double)v.elementAt(v.size() - 6)).
  1352.     doubleValue());
  1353.       y2 = m_plot2D.convertToPanelY(((Double)v.elementAt(v.size() - 5)).
  1354.     doubleValue());
  1355.       
  1356.       if (x1 < 0) {
  1357. //test left
  1358. new_coords = lineIntersect(x1, y1, x2, y2, 0, this.getHeight(), 0);
  1359. edge2 = 0;
  1360. if (new_coords[0] < 0) {
  1361.   //then not left
  1362.   if (y1 < 0) {
  1363.     //test top
  1364.     new_coords = lineIntersect(x1, y1, x2, y2, this.getWidth(), 0, 0);
  1365.     edge2 = 1;
  1366.   }
  1367.   else {
  1368.     //test bottom
  1369.     new_coords = lineIntersect(x1, y1, x2, y2, this.getWidth(), 0, 
  1370.        this.getHeight());
  1371.     edge2 = 3;
  1372.   }
  1373. }
  1374.       }
  1375.       else if (x1 > this.getWidth()) {
  1376. //test right
  1377. new_coords = lineIntersect(x1, y1, x2, y2, 0, this.getHeight(), 
  1378.    this.getWidth());
  1379. edge2 = 2;
  1380. if (new_coords[0] < 0) {
  1381.   //then not right
  1382.   if (y1 < 0) {
  1383.     //test top
  1384.     new_coords = lineIntersect(x1, y1, x2, y2, this.getWidth(), 0, 0);
  1385.     edge2 = 1;
  1386.   }
  1387.   else {
  1388.     //test bottom
  1389.     new_coords = lineIntersect(x1, y1, x2, y2, this.getWidth(), 0, 
  1390.        this.getHeight());
  1391.     edge2 = 3;
  1392.   }
  1393. }
  1394.       }
  1395.       else if (y1 < 0) {
  1396. //test top
  1397. new_coords = lineIntersect(x1, y1, x2, y2, this.getWidth(), 0, 0);
  1398. edge2 = 1;
  1399.       }
  1400.       else {
  1401. //test bottom
  1402. new_coords = lineIntersect(x1, y1, x2, y2, this.getWidth(), 0, 
  1403.    this.getHeight());
  1404. edge2 = 3;
  1405.       }
  1406.       
  1407.       building.setElementAt(new 
  1408. Double(m_plot2D.convertToAttribX(new_coords[0])), building.size() - 2);
  1409.       building.setElementAt(new 
  1410. Double(m_plot2D.convertToAttribY(new_coords[1])), building.size() - 1);
  1411.       
  1412.       //trust me this complicated piece of code will
  1413.       //determine what points on the boundary of the view to add to the polygon
  1414.       int xp, yp;
  1415.       xp = this.getWidth() * ((edge2 & 1) ^ ((edge2 & 2) / 2));
  1416.       yp = this.getHeight() * ((edge2 & 2) / 2);
  1417.       //System.out.println(((-1 + 4) % 4) + " hoi");
  1418.       
  1419.       if (inPolyline(v, m_plot2D.convertToAttribX(xp), 
  1420.      m_plot2D.convertToAttribY(yp))) {
  1421. //then add points in a clockwise direction
  1422. building.addElement(new Double(m_plot2D.convertToAttribX(xp)));
  1423. building.addElement(new Double(m_plot2D.convertToAttribY(yp)));
  1424. for (int noa = (edge2 + 1) % 4; noa != edge1; noa = (noa + 1) % 4) {
  1425.   xp = this.getWidth() * ((noa & 1) ^ ((noa & 2) / 2));
  1426.   yp = this.getHeight() * ((noa & 2) / 2);
  1427.   building.addElement(new Double(m_plot2D.convertToAttribX(xp)));
  1428.   building.addElement(new Double(m_plot2D.convertToAttribY(yp)));
  1429. }
  1430.       }
  1431.       else {
  1432. xp = this.getWidth() * ((edge2 & 2) / 2);
  1433. yp = this.getHeight() * (1 & ~((edge2 & 1) ^ ((edge2 & 2) / 2)));
  1434. if (inPolyline(v, m_plot2D.convertToAttribX(xp), 
  1435.        m_plot2D.convertToAttribY(yp))) {
  1436.   //then add points in anticlockwise direction
  1437.   building.addElement(new Double(m_plot2D.convertToAttribX(xp)));
  1438.   building.addElement(new Double(m_plot2D.convertToAttribY(yp)));
  1439.   for (int noa = (edge2 + 3) % 4; noa != edge1; noa = (noa + 3) % 4) {
  1440.     xp = this.getWidth() * ((noa & 2) / 2);
  1441.     yp = this.getHeight() * (1 & ~((noa & 1) ^ ((noa & 2) / 2)));
  1442.     building.addElement(new Double(m_plot2D.convertToAttribX(xp)));
  1443.     building.addElement(new Double(m_plot2D.convertToAttribY(yp)));
  1444.   }
  1445. }
  1446.       }
  1447.       return building;
  1448.     }
  1449.     /**
  1450.      * This will extract from a polygon shape its x coodrdinates
  1451.      * so that an awt.Polygon can be created.
  1452.      * @param v The polygon shape.
  1453.      * @return an int array containing the screen x coords for the polygon.
  1454.      */
  1455.     private int[] getXCoords(FastVector v) {
  1456.       int cach = (v.size() - 1) / 2;
  1457.       int[] ar = new int[cach];
  1458.       for (int noa = 0; noa < cach; noa ++) {
  1459. ar[noa] = (int)m_plot2D.convertToPanelX(((Double)v.elementAt(noa * 2 +
  1460. 1)).doubleValue());
  1461.       }
  1462.       return ar;
  1463.     }
  1464.     /**
  1465.      * This will extract from a polygon shape its y coordinates
  1466.      * so that an awt.Polygon can be created.
  1467.      * @param v The polygon shape.
  1468.      * @return an int array containing the screen y coords for the polygon.
  1469.      */
  1470.     private int[] getYCoords(FastVector v) {
  1471.       int cach = (v.size() - 1) / 2;
  1472.       int[] ar = new int[cach];
  1473.       for (int noa = 0; noa < cach; noa ++) {
  1474. ar[noa] = (int)m_plot2D.
  1475.   convertToPanelY(((Double)v.elementAt(noa * 2 + 2)).
  1476.   doubleValue());
  1477.       }
  1478.       return ar;
  1479.     }
  1480.     
  1481.     /**
  1482.      * Renders the polygons if necessary
  1483.      * @param gx the graphics context
  1484.      */
  1485.     public void prePlot(Graphics gx) {
  1486.       super.paintComponent(gx);
  1487.       if (m_plotInstances != null) {
  1488. drawShapes(gx); // will be in paintComponent of ShapePlot2D
  1489.       }
  1490.     }
  1491.   }
  1492.   /** default colours for colouring discrete class */
  1493.   protected Color [] m_DefaultColors = {Color.blue,
  1494. Color.red,
  1495. Color.green,
  1496. Color.cyan,
  1497. Color.pink,
  1498. new Color(255, 0, 255),
  1499. Color.orange,
  1500. new Color(255, 0, 0),
  1501. new Color(0, 255, 0),
  1502. Color.white};
  1503.   
  1504.   /** Lets the user select the attribute for the x axis */
  1505.   protected JComboBox m_XCombo = new JComboBox();
  1506.   /** Lets the user select the attribute for the y axis */
  1507.   protected JComboBox m_YCombo = new JComboBox();
  1508.   /** Lets the user select the attribute to use for colouring */
  1509.   protected JComboBox m_ColourCombo = new JComboBox();
  1510.   
  1511.   /** Lets the user select the shape they want to create for instance 
  1512.    * selection. */
  1513.   protected JComboBox m_ShapeCombo = new JComboBox();
  1514.   /** Button for the user to enter the splits. */
  1515.   protected JButton m_submit = new JButton("Submit");
  1516.   
  1517.   /** Button for the user to remove all splits. */
  1518.   protected JButton m_cancel = new JButton("Clear");
  1519.   /** Button for the user to save the visualized set of instances */
  1520.   protected JButton m_saveBut = new JButton("Save");
  1521.   /** Stop the combos from growing out of control */
  1522.   private Dimension COMBO_SIZE = new Dimension(250, m_saveBut
  1523.        .getPreferredSize().height);
  1524.   /** file chooser for saving instances */
  1525.   protected JFileChooser m_FileChooser 
  1526.     = new JFileChooser(new File(System.getProperty("user.dir")));
  1527.   /** Filter to ensure only arff files are selected */  
  1528.   protected FileFilter m_ArffFilter =
  1529.     new ExtensionFileFilter(Instances.FILE_EXTENSION, "Arff data files");
  1530.   /** Label for the jitter slider */
  1531.   protected JLabel m_JitterLab= new JLabel("Jitter",SwingConstants.RIGHT);
  1532.   /** The jitter slider */
  1533.   protected JSlider m_Jitter = new JSlider(0,50,0);
  1534.   /** The panel that displays the plot */
  1535.   protected PlotPanel m_plot = new PlotPanel();
  1536.   /** The panel that displays the attributes , using color to represent 
  1537.    * another attribute. */
  1538.   protected AttributePanel m_attrib = new AttributePanel();
  1539.   /** The panel that displays legend info if there is more than one plot */
  1540.   protected LegendPanel m_legendPanel = new LegendPanel();
  1541.   /** Panel that surrounds the plot panel with a titled border */
  1542.   protected JPanel m_plotSurround = new JPanel();
  1543.   /** Panel that surrounds the class panel with a titled border */
  1544.   protected JPanel m_classSurround = new JPanel();
  1545.   /** An optional listener that we will inform when ComboBox selections
  1546.       change */
  1547.   protected ActionListener listener = null;
  1548.   /** An optional listener that we will inform when the user creates a 
  1549.    * split to seperate instances. */
  1550.   protected VisualizePanelListener m_splitListener = null;
  1551.   /** The name of the plot (not currently displayed, but can be used
  1552.       in the containing Frame or Panel) */
  1553.   protected String m_plotName = "";
  1554.   /** The panel that displays the legend for the colouring attribute */
  1555.   protected ClassPanel m_classPanel = new ClassPanel();
  1556.   
  1557.   /** The list of the colors used */
  1558.   protected FastVector m_colorList;
  1559.   /** These hold the names of preferred columns to visualize on---if the
  1560.       user has defined them in the Visualize.props file */
  1561.   protected String m_preferredXDimension = null;
  1562.   protected String m_preferredYDimension = null;
  1563.   protected String m_preferredColourDimension = null;
  1564.   /** Show the attribute bar panel */
  1565.   protected boolean m_showAttBars = true;
  1566.   /** the logger */
  1567.   protected Logger m_Log;
  1568.   
  1569.   /**
  1570.    * Sets the Logger to receive informational messages
  1571.    *
  1572.    * @param newLog the Logger that will now get info messages
  1573.    */
  1574.   public void setLog(Logger newLog) {
  1575.     m_Log = newLog;
  1576.   }
  1577.   /** This constructor allows a VisualizePanelListener to be set. */
  1578.   public VisualizePanel(VisualizePanelListener ls) {
  1579.     this();
  1580.     m_splitListener = ls;
  1581.   }
  1582.   /**
  1583.    * Set the properties for the VisualizePanel
  1584.    */
  1585.   private void setProperties(String relationName) {
  1586.     if (VisualizeUtils.VISUALIZE_PROPERTIES != null) {
  1587.       String thisClass = this.getClass().getName();
  1588.       if (relationName == null) {
  1589. String showAttBars = thisClass+".displayAttributeBars";
  1590. String val = VisualizeUtils.VISUALIZE_PROPERTIES.
  1591.   getProperty(showAttBars);
  1592. if (val == null) {
  1593.   System.err.println("Displaying attribute bars ");
  1594.   m_showAttBars = true;
  1595. } else {
  1596.   if (val.compareTo("true") == 0 || val.compareTo("on") == 0) {
  1597.     System.err.println("Displaying attribute bars ");
  1598.     m_showAttBars = true;
  1599.   } else {
  1600.     m_showAttBars = false;
  1601.   }
  1602. }
  1603.       } else {
  1604. System.err.println("Looking for preferred visualization dimensions for "
  1605.    +relationName);
  1606. String xcolKey = thisClass+"."+relationName+".XDimension";
  1607. String ycolKey = thisClass+"."+relationName+".YDimension";
  1608. String ccolKey = thisClass+"."+relationName+".ColourDimension";
  1609.       
  1610. m_preferredXDimension = VisualizeUtils.VISUALIZE_PROPERTIES.
  1611.   getProperty(xcolKey);
  1612. if (m_preferredXDimension == null) {
  1613.   System.err.println("No preferred X dimension found in "
  1614.      +VisualizeUtils.PROPERTY_FILE
  1615.      +" for "+xcolKey);
  1616. } else {
  1617.   System.err.println("Setting preferred X dimension to "
  1618.      +m_preferredXDimension);
  1619. }
  1620. m_preferredYDimension = VisualizeUtils.VISUALIZE_PROPERTIES.
  1621.   getProperty(ycolKey);
  1622. if (m_preferredYDimension == null) {
  1623.   System.err.println("No preferred Y dimension found in "
  1624.      +VisualizeUtils.PROPERTY_FILE
  1625.      +" for "+ycolKey);
  1626. } else {
  1627.   System.err.println("Setting preferred dimension Y to "
  1628.      +m_preferredYDimension);
  1629. }
  1630. m_preferredColourDimension = VisualizeUtils.VISUALIZE_PROPERTIES.
  1631.   getProperty(ccolKey);
  1632. if (m_preferredColourDimension == null) {
  1633.   System.err.println("No preferred Colour dimension found in "
  1634.      +VisualizeUtils.PROPERTY_FILE
  1635.      +" for "+ycolKey);
  1636. } else {
  1637.   System.err.println("Setting preferred Colour dimension to "
  1638.      +m_preferredColourDimension);
  1639. }
  1640.       }
  1641.     }
  1642.   }
  1643.   /**
  1644.    * Constructor
  1645.    */
  1646.   public VisualizePanel() {
  1647.     setProperties(null);
  1648.     m_FileChooser.setFileFilter(m_ArffFilter);
  1649.     m_FileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
  1650.     m_XCombo.setToolTipText("Select the attribute for the x axis");
  1651.     m_YCombo.setToolTipText("Select the attribute for the y axis");
  1652.     m_ColourCombo.setToolTipText("Select the attribute to colour on");
  1653.     m_ShapeCombo.setToolTipText("Select the shape to use for data selection"); 
  1654.     m_XCombo.setPreferredSize(COMBO_SIZE);
  1655.     m_YCombo.setPreferredSize(COMBO_SIZE);
  1656.     m_ColourCombo.setPreferredSize(COMBO_SIZE);
  1657.     m_ShapeCombo.setPreferredSize(COMBO_SIZE);
  1658.     m_XCombo.setMaximumSize(COMBO_SIZE);
  1659.     m_YCombo.setMaximumSize(COMBO_SIZE);
  1660.     m_ColourCombo.setMaximumSize(COMBO_SIZE);
  1661.     m_ShapeCombo.setMaximumSize(COMBO_SIZE);
  1662.     
  1663.     m_XCombo.setMinimumSize(COMBO_SIZE);
  1664.     m_YCombo.setMinimumSize(COMBO_SIZE);
  1665.     m_ColourCombo.setMinimumSize(COMBO_SIZE);
  1666.     m_ShapeCombo.setMinimumSize(COMBO_SIZE);
  1667.     //////////
  1668.     m_XCombo.setEnabled(false);
  1669.     m_YCombo.setEnabled(false);
  1670.     m_ColourCombo.setEnabled(false);
  1671.     m_ShapeCombo.setEnabled(false);
  1672.     // tell the class panel and the legend panel that we want to know when 
  1673.     // colours change
  1674.     m_classPanel.addRepaintNotify(this);
  1675.     m_legendPanel.addRepaintNotify(this);
  1676.     m_colorList = new FastVector(10);
  1677.     for (int noa = m_colorList.size(); noa < 10; noa++) {
  1678.       Color pc = m_DefaultColors[noa % 10];
  1679.       int ija =  noa / 10;
  1680.       ija *= 2; 
  1681.       for (int j=0;j<ija;j++) {
  1682. pc = pc.darker();
  1683.       }
  1684.       
  1685.       m_colorList.addElement(pc);
  1686.     }
  1687.     m_plot.setColours(m_colorList);
  1688.     m_classPanel.setColours(m_colorList);
  1689.     m_attrib.setColours(m_colorList);
  1690.     m_attrib.addAttributePanelListener(new AttributePanelListener() {
  1691. public void attributeSelectionChange(AttributePanelEvent e) {
  1692.   if (e.m_xChange) {
  1693.     m_XCombo.setSelectedIndex(e.m_indexVal);
  1694.   } else {
  1695.     m_YCombo.setSelectedIndex(e.m_indexVal);
  1696.   }
  1697. }
  1698.       });
  1699.     
  1700.     m_XCombo.addActionListener(new ActionListener() {
  1701. public void actionPerformed(ActionEvent e) {
  1702.   int selected = m_XCombo.getSelectedIndex();
  1703.   if (selected < 0) {
  1704.     selected = 0;
  1705.   }
  1706.   m_plot.setXindex(selected);
  1707.  
  1708.   // try sending on the event if anyone is listening
  1709.   if (listener != null) {
  1710.     listener.actionPerformed(e);
  1711.   }
  1712. }
  1713.       });
  1714.     m_YCombo.addActionListener(new ActionListener() {
  1715. public void actionPerformed(ActionEvent e) {
  1716.   int selected = m_YCombo.getSelectedIndex();
  1717.   if (selected < 0) {
  1718.     selected = 0;
  1719.   }
  1720.   m_plot.setYindex(selected);
  1721.  
  1722.   // try sending on the event if anyone is listening
  1723.   if (listener != null) {
  1724.     listener.actionPerformed(e);
  1725.   }
  1726. }
  1727.       });
  1728.     m_ColourCombo.addActionListener(new ActionListener() {
  1729. public void actionPerformed(ActionEvent e) {
  1730.   int selected = m_ColourCombo.getSelectedIndex();
  1731.   if (selected < 0) {
  1732.     selected = 0;
  1733.   }
  1734.   m_plot.setCindex(selected);
  1735.   if (listener != null) {
  1736.     listener.actionPerformed(e);
  1737.   }
  1738. }
  1739.       });
  1740.     
  1741.     ///////
  1742.     m_ShapeCombo.addActionListener(new ActionListener() {
  1743. public void actionPerformed(ActionEvent e) {
  1744.   int selected = m_ShapeCombo.getSelectedIndex();
  1745.   if (selected < 0) {
  1746.     selected = 0;
  1747.   }
  1748.   m_plot.setSindex(selected);
  1749.   // try sending on the event if anyone is listening
  1750.   if (listener != null) {
  1751.     listener.actionPerformed(e);
  1752.   }
  1753. }
  1754.       });
  1755.     ///////////////////////////////////////
  1756.     m_Jitter.addChangeListener(new ChangeListener() {
  1757. public void stateChanged(ChangeEvent e) {
  1758.   m_plot.setJitter(m_Jitter.getValue());
  1759. }
  1760.       });
  1761.     m_saveBut.setEnabled(false);
  1762.     m_saveBut.setToolTipText("Save the visible instances to a file");
  1763.     m_saveBut.addActionListener(new ActionListener() {
  1764. public void actionPerformed(ActionEvent e) {
  1765.   saveVisibleInstances();
  1766. }
  1767.       });
  1768.     
  1769.     JPanel combos = new JPanel();
  1770.     GridBagLayout gb = new GridBagLayout();
  1771.     GridBagConstraints constraints = new GridBagConstraints();
  1772.     m_XCombo.setLightWeightPopupEnabled(false);
  1773.     m_YCombo.setLightWeightPopupEnabled(false);
  1774.     m_ColourCombo.setLightWeightPopupEnabled(false);
  1775.     m_ShapeCombo.setLightWeightPopupEnabled(false);
  1776.     combos.setBorder(BorderFactory.createEmptyBorder(10, 5, 10, 5));
  1777.     combos.setLayout(gb);
  1778.     constraints.gridx=0;constraints.gridy=0;constraints.weightx=5;
  1779.     constraints.fill = GridBagConstraints.HORIZONTAL;
  1780.     constraints.gridwidth=2;constraints.gridheight=1;
  1781.     constraints.insets = new Insets(0,2,0,2);
  1782.     combos.add(m_XCombo,constraints);
  1783.     constraints.gridx=2;constraints.gridy=0;constraints.weightx=5;
  1784.     constraints.gridwidth=2;constraints.gridheight=1;
  1785.     combos.add(m_YCombo,constraints);
  1786.     constraints.gridx=0;constraints.gridy=1;constraints.weightx=5;
  1787.     constraints.gridwidth=2;constraints.gridheight=1;
  1788.     combos.add(m_ColourCombo,constraints);
  1789.     //
  1790.     constraints.gridx=2;constraints.gridy=1;constraints.weightx=5;
  1791.     constraints.gridwidth=2;constraints.gridheight=1;
  1792.     combos.add(m_ShapeCombo,constraints);
  1793.    
  1794.     JPanel mbts = new JPanel();
  1795.     mbts.setLayout(new GridLayout(1,3));
  1796.     mbts.add(m_submit); mbts.add(m_cancel); mbts.add(m_saveBut);
  1797.     constraints.gridx=0;constraints.gridy=2;constraints.weightx=5;
  1798.     constraints.gridwidth=2;constraints.gridheight=1;
  1799.     combos.add(mbts, constraints);
  1800.     ////////////////////////////////
  1801.     constraints.gridx=2;constraints.gridy=2;constraints.weightx=5;
  1802.     constraints.gridwidth=1;constraints.gridheight=1;
  1803.     constraints.insets = new Insets(10,0,0,5);
  1804.     combos.add(m_JitterLab,constraints);
  1805.     constraints.gridx=3;constraints.gridy=2;
  1806.     constraints.weightx=5;
  1807.     constraints.insets = new Insets(10,0,0,0);
  1808.     combos.add(m_Jitter,constraints);
  1809.     m_classSurround = new JPanel();
  1810.     m_classSurround.
  1811.       setBorder(BorderFactory.createTitledBorder("Class colour")); 
  1812.     m_classSurround.setLayout(new BorderLayout());
  1813.     m_classPanel.setBorder(BorderFactory.createEmptyBorder(15,10,10,10));
  1814.     m_classSurround.add(m_classPanel, BorderLayout.CENTER);
  1815.     GridBagLayout gb2 = new GridBagLayout();
  1816.     m_plotSurround.setBorder(BorderFactory.createTitledBorder("Plot"));
  1817.     m_plotSurround.setLayout(gb2);
  1818.     constraints.fill = constraints.BOTH;
  1819.     constraints.insets = new Insets(0, 0, 0, 10);
  1820.     constraints.gridx=0;constraints.gridy=0;constraints.weightx=3;
  1821.     constraints.gridwidth=4;constraints.gridheight=1;constraints.weighty=5;
  1822.     m_plotSurround.add(m_plot, constraints);
  1823.     
  1824.     if (m_showAttBars) {
  1825.       constraints.insets = new Insets(0, 0, 0, 0);
  1826.       constraints.gridx=4;constraints.gridy=0;constraints.weightx=1;
  1827.       constraints.gridwidth=1;constraints.gridheight=1;constraints.weighty=5;
  1828.       m_plotSurround.add(m_attrib, constraints);
  1829.     }
  1830.     setLayout(new BorderLayout());
  1831.     add(combos, BorderLayout.NORTH);
  1832.     add(m_plotSurround, BorderLayout.CENTER);
  1833.     add(m_classSurround, BorderLayout.SOUTH);
  1834.     
  1835.     String [] SNames = new String [4];
  1836.     SNames[0] = "Select Instance";
  1837.     SNames[1] = "Rectangle";
  1838.     SNames[2] = "Polygon";
  1839.     SNames[3] = "Polyline";
  1840.     m_ShapeCombo.setModel(new DefaultComboBoxModel(SNames));
  1841.     m_ShapeCombo.setEnabled(true);
  1842.   }
  1843.   /**
  1844.    * Save the currently visible set of instances to a file
  1845.    */
  1846.   private void saveVisibleInstances() {
  1847.     FastVector plots = m_plot.m_plot2D.getPlots();
  1848.     if (plots != null) {
  1849.       PlotData2D master = (PlotData2D)plots.elementAt(0);
  1850.       Instances saveInsts = new Instances(master.getPlotInstances());
  1851.       for (int i = 1; i < plots.size(); i++) {
  1852. PlotData2D temp = (PlotData2D)plots.elementAt(i);
  1853. Instances addInsts = temp.getPlotInstances();
  1854. for (int j = 0; j < addInsts.numInstances(); j++) {
  1855.   saveInsts.add(addInsts.instance(j));
  1856. }
  1857.       }
  1858.       try {
  1859. int returnVal = m_FileChooser.showSaveDialog(this);
  1860. if (returnVal == JFileChooser.APPROVE_OPTION) {
  1861.   File sFile = m_FileChooser.getSelectedFile();
  1862.   if (!sFile.getName().toLowerCase().
  1863.       endsWith(Instances.FILE_EXTENSION)) {
  1864.     sFile = new File(sFile.getParent(), sFile.getName() 
  1865.      + Instances.FILE_EXTENSION);
  1866.   }
  1867.   File selected = sFile;
  1868.   Writer w = new BufferedWriter(new FileWriter(selected));
  1869.   w.write(saveInsts.toString());
  1870.   w.close();
  1871. }
  1872.       } catch (Exception ex) {
  1873. ex.printStackTrace();
  1874.       }
  1875.     }
  1876.   }
  1877.   /**
  1878.    * Sets the index used for colouring. If this method is called then
  1879.    * the supplied index is used and the combo box for selecting colouring
  1880.    * attribute is disabled.
  1881.    * @param index the index of the attribute to use for colouring
  1882.    */
  1883.   public void setColourIndex(int index) {
  1884.     if (index >= 0) {
  1885.       m_ColourCombo.setSelectedIndex(index);
  1886.     } else {
  1887.       m_ColourCombo.setSelectedIndex(0);
  1888.     }
  1889.     m_ColourCombo.setEnabled(false);
  1890.   }
  1891.   
  1892.   
  1893.   /**
  1894.    * Set the index of the attribute for the x axis 
  1895.    * @param index the index for the x axis
  1896.    * @exception Exception if index is out of range.
  1897.    */
  1898.   public void setXIndex(int index) throws Exception {
  1899.     if (index >= 0 && index < m_XCombo.getItemCount()) {
  1900.       m_XCombo.setSelectedIndex(index);
  1901.     } else {
  1902.       throw new Exception("x index is out of range!");
  1903.     }
  1904.   }
  1905.   /**
  1906.    * Get the index of the attribute on the x axis
  1907.    * @return the index of the attribute on the x axis
  1908.    */
  1909.   public int getXIndex() {
  1910.     return m_XCombo.getSelectedIndex();
  1911.   }
  1912.   /**
  1913.    * Set the index of the attribute for the y axis 
  1914.    * @param index the index for the y axis
  1915.    * @exception Exception if index is out of range.
  1916.    */
  1917.   public void setYIndex(int index) throws Exception {
  1918.     if (index >= 0 && index < m_YCombo.getItemCount()) {
  1919.       m_YCombo.setSelectedIndex(index);
  1920.     } else {
  1921.       throw new Exception("y index is out of range!");
  1922.     }
  1923.   }
  1924.   
  1925.   /**
  1926.    * Get the index of the attribute on the y axis
  1927.    * @return the index of the attribute on the x axis
  1928.    */
  1929.   public int getYIndex() {
  1930.     return m_YCombo.getSelectedIndex();
  1931.   }
  1932.   /**
  1933.    * Get the index of the attribute selected for coloring
  1934.    * @return the index of the attribute on the x axis
  1935.    */
  1936.   public int getCIndex() {
  1937.     return m_ColourCombo.getSelectedIndex();
  1938.   }
  1939.   /**
  1940.    * Get the index of the shape selected for creating splits.
  1941.    * @return The index of the shape.
  1942.    */
  1943.   public int getSIndex() {
  1944.     return m_ShapeCombo.getSelectedIndex();
  1945.   }
  1946.   
  1947.   /** 
  1948.    * Set the shape for creating splits.
  1949.    * @param index The index of the shape.
  1950.    * @exception Exception if index is out of range.
  1951.    */
  1952.   public void setSIndex(int index) throws Exception {
  1953.     if (index >= 0 && index < m_ShapeCombo.getItemCount()) {
  1954.       m_ShapeCombo.setSelectedIndex(index);
  1955.     }
  1956.     else {
  1957.       throw new Exception("s index is out of range!");
  1958.     }
  1959.   }
  1960.   /**
  1961.    * Add a listener for this visualize panel
  1962.    * @param act an ActionListener
  1963.    */
  1964.   public void addActionListener(ActionListener act) {
  1965.     listener = act;
  1966.   }
  1967.   /**
  1968.    * Set a name for this plot
  1969.    * @param plotName the name for the plot
  1970.    */
  1971.   public void setName(String plotName) {
  1972.     m_plotName = plotName;
  1973.   }
  1974.   /**
  1975.    * Returns the name associated with this plot. "" is returned if no
  1976.    * name is set.
  1977.    * @return the name of the plot
  1978.    */
  1979.   public String getName() {
  1980.     return m_plotName;
  1981.   }
  1982.   /**
  1983.    * Get the master plot's instances
  1984.    * @return the master plot's instances
  1985.    */
  1986.   public Instances getInstances() {
  1987.     return m_plot.m_plotInstances;
  1988.   }
  1989.   /**
  1990.    * Sets the Colors in use for a different attrib
  1991.    * if it is not a nominal attrib and or does not have
  1992.    * more possible values then this will do nothing.
  1993.    * otherwise it will add default colors to see that
  1994.    * there is a color for the attrib to begin with.
  1995.    * @param a The index of the attribute to color.
  1996.    * @param i The instances object that contains the attribute.
  1997.    */
  1998.   protected void newColorAttribute(int a, Instances i) {
  1999.     if (i.attribute(a).isNominal()) {
  2000.       for (int noa = m_colorList.size(); noa < i.attribute(a).numValues();
  2001.    noa++) {
  2002. Color pc = m_DefaultColors[noa % 10];
  2003. int ija =  noa / 10;
  2004. ija *= 2; 
  2005. for (int j=0;j<ija;j++) {
  2006.   pc = pc.brighter();
  2007. }
  2008. m_colorList.addElement(pc);
  2009.       }
  2010.       m_plot.setColours(m_colorList);
  2011.       m_attrib.setColours(m_colorList);
  2012.       m_classPanel.setColours(m_colorList);
  2013.     }
  2014.   }
  2015.   /**
  2016.    * This will set the shapes for the instances.
  2017.    * @param l A list of the shapes, providing that
  2018.    * the objects in the lists are non editable the data will be
  2019.    * kept intact.
  2020.    */
  2021.   public void setShapes(FastVector l) {
  2022.     m_plot.setShapes(l);
  2023.   }
  2024.   /**
  2025.    * Tells the panel to use a new set of instances.
  2026.    * @param inst a set of Instances
  2027.    */
  2028.   public void setInstances(Instances inst) {
  2029.     if (inst.numAttributes() > 0 && inst.numInstances() > 0) {
  2030.       newColorAttribute(inst.numAttributes()-1, inst);
  2031.     }
  2032.     PlotData2D temp = new PlotData2D(inst);
  2033.     temp.setPlotName(inst.relationName());
  2034.     
  2035.     try {
  2036.       setMasterPlot(temp);
  2037.     } catch (Exception ex) {
  2038.       System.err.println(ex);
  2039.       ex.printStackTrace();
  2040.     } 
  2041.   }
  2042.   public void setUpComboBoxes(Instances inst) {
  2043.     setProperties(inst.relationName());
  2044.     int prefX = -1;
  2045.     int prefY = -1;
  2046.     int prefC = -1;
  2047.     String [] XNames = new String [inst.numAttributes()];
  2048.     String [] YNames = new String [inst.numAttributes()];
  2049.     String [] CNames = new String [inst.numAttributes()];
  2050.     String [] SNames = new String [4];
  2051.     for (int i = 0; i < XNames.length; i++) {
  2052.       String type = "";
  2053.       switch (inst.attribute(i).type()) {
  2054.       case Attribute.NOMINAL:
  2055. type = " (Nom)";
  2056. break;
  2057.       case Attribute.NUMERIC:
  2058. type = " (Num)";
  2059. break;
  2060.       case Attribute.STRING:
  2061. type = " (Str)";
  2062. break;
  2063.       default:
  2064. type = " (???)";
  2065.       }
  2066.       XNames[i] = "X: "+ inst.attribute(i).name()+type;
  2067.       YNames[i] = "Y: "+ inst.attribute(i).name()+type;
  2068.       CNames[i] = "Colour: "+ inst.attribute(i).name()+type;
  2069.       if (m_preferredXDimension != null) {
  2070. if (m_preferredXDimension.compareTo(inst.attribute(i).name()) == 0) {
  2071.   prefX = i;
  2072.   System.err.println("Found preferred X dimension");
  2073. }
  2074.       }
  2075.       if (m_preferredYDimension != null) {
  2076. if (m_preferredYDimension.compareTo(inst.attribute(i).name()) == 0) {
  2077.   prefY = i;
  2078.   System.err.println("Found preferred Y dimension");
  2079. }
  2080.       }
  2081.       if (m_preferredColourDimension != null) {
  2082. if (m_preferredColourDimension.
  2083.     compareTo(inst.attribute(i).name()) == 0) {
  2084.   prefC = i;
  2085.   System.err.println("Found preferred Colour dimension");
  2086. }
  2087.       }
  2088.     }
  2089.     m_XCombo.setModel(new DefaultComboBoxModel(XNames));
  2090.     m_YCombo.setModel(new DefaultComboBoxModel(YNames));
  2091.     m_ColourCombo.setModel(new DefaultComboBoxModel(CNames));
  2092.     //m_ShapeCombo.setModel(new DefaultComboBoxModel(SNames));
  2093.     //m_ShapeCombo.setEnabled(true);
  2094.     m_XCombo.setEnabled(true);
  2095.     m_YCombo.setEnabled(true);
  2096.     
  2097.     if (m_splitListener == null) {
  2098.       m_ColourCombo.setEnabled(true);
  2099.       m_ColourCombo.setSelectedIndex(inst.numAttributes()-1);
  2100.     }
  2101.     m_plotSurround.setBorder((BorderFactory.createTitledBorder("Plot: "
  2102.       +inst.relationName())));
  2103.     try {
  2104.       if (prefX != -1) {
  2105. setXIndex(prefX);
  2106.       }
  2107.       if (prefY != -1) {
  2108. setYIndex(prefY);
  2109.       }
  2110.       if (prefC != -1) {
  2111. m_ColourCombo.setSelectedIndex(prefC);
  2112.       }
  2113.     } catch (Exception ex) {
  2114.       System.err.println("Problem setting preferred Visualization dimensions");
  2115.     }
  2116.   }
  2117.   /**
  2118.    * Set the master plot for the visualize panel
  2119.    * @param newPlot the new master plot
  2120.    * @exception Exception if the master plot could not be set
  2121.    */
  2122.   public void setMasterPlot(PlotData2D newPlot) throws Exception {
  2123.     m_plot.setMasterPlot(newPlot);
  2124.     setUpComboBoxes(newPlot.m_plotInstances);
  2125.     m_saveBut.setEnabled(true);
  2126.     repaint();
  2127.   }
  2128.   /**
  2129.    * Set a new plot to the visualize panel
  2130.    * @param newPlot the new plot to add
  2131.    * @exception Exception if the plot could not be added
  2132.    */
  2133.   public void addPlot(PlotData2D newPlot) throws Exception {
  2134.     m_plot.addPlot(newPlot);
  2135.     if (m_plot.m_plot2D.getMasterPlot() != null) {
  2136.       setUpComboBoxes(newPlot.m_plotInstances);
  2137.     }
  2138.     m_saveBut.setEnabled(true);
  2139.     repaint();
  2140.   }
  2141.   /**
  2142.    * Main method for testing this class
  2143.    */
  2144.   public static void main(String [] args) {
  2145.     try {
  2146.       if (args.length < 1) {
  2147. System.err.println("Usage : weka.gui.visualize.VisualizePanel "
  2148.    +"<dataset> [<dataset> <dataset>...]");
  2149. System.exit(1);
  2150.       }
  2151.       final javax.swing.JFrame jf = 
  2152. new javax.swing.JFrame("Weka Knowledge Explorer: Visualize");
  2153.       jf.setSize(500,400);
  2154.       jf.getContentPane().setLayout(new BorderLayout());
  2155.       final VisualizePanel sp = new VisualizePanel();
  2156.       
  2157.       jf.getContentPane().add(sp, BorderLayout.CENTER);
  2158.       jf.addWindowListener(new java.awt.event.WindowAdapter() {
  2159. public void windowClosing(java.awt.event.WindowEvent e) {
  2160.   jf.dispose();
  2161.   System.exit(0);
  2162. }
  2163.       });
  2164.       jf.setVisible(true);
  2165.       if (args.length >= 1) {
  2166. for (int j = 0; j < args.length; j++) {
  2167.   System.err.println("Loading instances from " + args[j]);
  2168.   java.io.Reader r = new java.io.BufferedReader(
  2169.      new java.io.FileReader(args[j]));
  2170.   Instances i = new Instances(r);
  2171.   i.setClassIndex(i.numAttributes()-1);
  2172.   PlotData2D pd1 = new PlotData2D(i);
  2173.   
  2174.   if (j == 0) {
  2175.     pd1.setPlotName("Master plot");
  2176.     sp.setMasterPlot(pd1);
  2177.   } else {
  2178.     pd1.setPlotName("Plot "+(j+1));
  2179.     pd1.m_useCustomColour = true;
  2180.     pd1.m_customColour = (j % 2 == 0) ? Color.red : Color.blue; 
  2181.     sp.addPlot(pd1);
  2182.   }
  2183. }
  2184.       }
  2185.     } catch (Exception ex) {
  2186.       ex.printStackTrace();
  2187.       System.err.println(ex.getMessage());
  2188.     }
  2189.   }
  2190. }