ClassPanel.java
Upload User: rhdiban
Upload Date: 2013-08-09
Package Size: 15085k
Code Size: 18k
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.  *    ClassPanel.java
  18.  *    Copyright (C) 2000 Mark Hall, Malcolm Ware
  19.  *
  20.  */
  21. package weka.gui.visualize;
  22. import weka.core.Instances;
  23. import weka.core.Instance;
  24. import weka.core.Attribute;
  25. import weka.core.FastVector;
  26. import weka.core.Utils;
  27. import java.util.Random;
  28. import javax.swing.JPanel;
  29. import javax.swing.JColorChooser;
  30. import javax.swing.JLabel;
  31. import java.awt.Color;
  32. import java.awt.FontMetrics;
  33. import java.awt.Graphics;
  34. import java.awt.BorderLayout;
  35. import java.awt.Component;
  36. import java.awt.Font;
  37. import java.awt.event.MouseAdapter;
  38. import java.awt.event.MouseEvent;
  39. /**
  40.  * This panel displays coloured labels for nominal attributes and a spectrum
  41.  * for numeric attributes. It can also be told to colour on the basis
  42.  * of an array of doubles (this can be useful for displaying coloured labels
  43.  * that correspond to a clusterers predictions).
  44.  *
  45.  * @author Mark Hall (mhall@cs.waikato.ac.nz)
  46.  * @author Malcolm Ware (mfw4@cs.waikato.ac.nz)
  47.  * @version $Revision: 1.10 $
  48.  */
  49. public class ClassPanel extends JPanel {
  50.     
  51.   /** True when the panel has been enabled (ie after 
  52.       setNumeric or setNominal has been called */
  53.   private boolean m_isEnabled = false;
  54.   /** True if the colouring attribute is numeric */
  55.   private boolean m_isNumeric = false;
  56.     
  57.   /** The height of the spectrum for numeric class */
  58.   private final int m_spectrumHeight = 5;
  59.   /**  The maximum value for the colouring attribute */
  60.   private double m_maxC;
  61.     
  62.   /** The minimum value for the colouring attribute */
  63.   private double m_minC;
  64.   /** The size of the ticks */
  65.   private final int m_tickSize = 5;
  66.   /** Font metrics */
  67.   private FontMetrics m_labelMetrics = null;
  68.   /** The font used in labeling */
  69.   private Font m_labelFont = null;
  70.   /** The amount of space to leave either side of the legend */ 
  71.   private int m_HorizontalPad=0;
  72.   /** The precision with which to display real values */
  73.   private int m_precisionC;
  74.   /** Field width for numeric values */
  75.   private int m_fieldWidthC;
  76.   /** The old width. */
  77.   private int m_oldWidth = -9000;
  78.     
  79.   /** Instances being plotted */
  80.   private Instances m_Instances=null;
  81.   /** Index of the colouring attribute */
  82.   private int m_cIndex;
  83.   /** the list of colours to use for colouring nominal attribute labels */
  84.   private FastVector m_colorList;
  85.   /** An optional list of Components that use the colour list
  86.       maintained by this class. If the user changes a colour
  87.       using the colour chooser, then these components need to
  88.       be repainted in order to display the change */
  89.   private FastVector m_Repainters = new FastVector();
  90.   /** default colours for colouring discrete class */
  91.   protected Color [] m_DefaultColors = {Color.blue,
  92. Color.red,
  93. Color.green,
  94. Color.cyan,
  95. Color.pink,
  96. new Color(255, 0, 255),
  97. Color.orange,
  98. new Color(255, 0, 0),
  99. new Color(0, 255, 0),
  100. Color.white};
  101.   /** Inner Inner class used to create labels for nominal attributes
  102.    * so that there color can be changed.
  103.    */
  104.   private class NomLabel extends JLabel {
  105.     private int m_index = 0;
  106.     /** 
  107.      * Creates a label with its name and class index value.
  108.      * @param name The name of the nominal class value.
  109.      * @param id The index value for that class value.
  110.      */
  111.     public NomLabel(String name, int id) {
  112.       super(name);
  113.       m_index = id;
  114.       this.addMouseListener(new MouseAdapter() {
  115.   public void mouseClicked(MouseEvent e) {
  116.       
  117.     if ((e.getModifiers() & e.BUTTON1_MASK) == e.BUTTON1_MASK) {
  118.       Color tmp = JColorChooser.showDialog
  119. (ClassPanel.this, "Select new Color", 
  120.  (Color)m_colorList.elementAt(m_index));
  121.       if (tmp != null) {
  122. m_colorList.setElementAt(tmp, m_index);
  123. if (m_Repainters.size() > 0) {
  124.   for (int i=0;i<m_Repainters.size();i++) {
  125.     ((Component)(m_Repainters.elementAt(i))).repaint();
  126.   }
  127. }
  128. m_oldWidth = -9000;
  129. ClassPanel.this.repaint();
  130.       }
  131.     }
  132.   }
  133. });
  134.     }
  135.   }
  136.   public ClassPanel() {
  137.     /** Set up some default colours */
  138.     m_colorList = new FastVector(10);
  139.     for (int noa = m_colorList.size(); noa < 10; noa++) {
  140.       Color pc = m_DefaultColors[noa % 10];
  141.       int ija =  noa / 10;
  142.       ija *= 2; 
  143.       for (int j=0;j<ija;j++) {
  144. pc = pc.darker();
  145.       }
  146.       m_colorList.addElement(pc);
  147.     }
  148.   }
  149.   /**
  150.    * Adds a component that will need to be repainted if the user
  151.    * changes the colour of a label.
  152.    * @param c the component to be repainted
  153.    */
  154.   public void addRepaintNotify(Component c) {
  155.     m_Repainters.addElement(c);
  156.   }
  157.   /**
  158.    * Set up fonts and font metrics
  159.    * @param gx the graphics context
  160.    */
  161.   private void setFonts(Graphics gx) {
  162.     if (m_labelMetrics == null) {
  163.       m_labelFont = new Font("Monospaced", Font.PLAIN, 12);
  164.       m_labelMetrics = gx.getFontMetrics(m_labelFont);
  165.       int hf = m_labelMetrics.getAscent();
  166.       if (this.getHeight() < (3*hf)) {
  167. m_labelFont = new Font("Monospaced",Font.PLAIN,11);
  168. m_labelMetrics = gx.getFontMetrics(m_labelFont);
  169.       }
  170.     }
  171.     gx.setFont(m_labelFont);
  172.   }
  173.     
  174.   /**
  175.    * Enables the panel
  176.    * @param e true to enable the panel
  177.    */
  178.   public void setOn(boolean e) {
  179.     m_isEnabled = e;
  180.   }
  181.   /**
  182.    * Set the instances.
  183.    * @param insts the instances
  184.    */
  185.   public void setInstances(Instances insts) {
  186.     m_Instances = insts;
  187.   }
  188.   /**
  189.    * Set the index of the attribute to display coloured labels for
  190.    * @param cIndex the index of the attribute to display coloured labels for
  191.    */
  192.   public void setCindex(int cIndex) {
  193.     if (m_Instances.numAttributes() > 0) {
  194.       m_cIndex = cIndex;
  195.       if (m_Instances.attribute(m_cIndex).isNumeric()) {
  196. setNumeric();
  197.       } else {
  198. if (m_Instances.attribute(m_cIndex).numValues() > m_colorList.size()) {
  199.   extendColourMap();
  200. }
  201. setNominal();
  202.       }
  203.     }
  204.   }
  205.   /**
  206.    * Extends the list of colours if a new attribute with more values than
  207.    * the previous one is chosen
  208.    */
  209.   private void extendColourMap() {
  210.     if (m_Instances.attribute(m_cIndex).isNominal()) {
  211.       for (int i = m_colorList.size(); 
  212.    i < m_Instances.attribute(m_cIndex).numValues();
  213.    i++) {
  214. Color pc = m_DefaultColors[i % 10];
  215. int ija =  i / 10;
  216. ija *= 2; 
  217. for (int j=0;j<ija;j++) {
  218.   pc = pc.brighter();
  219. }
  220. m_colorList.addElement(pc);
  221.       }
  222.     }
  223.   }
  224.   /**
  225.    * Set a list of colours to use for colouring labels
  226.    * @param a list containing java.awt.Colors
  227.    */
  228.   public void setColours(FastVector cols) {
  229.     m_colorList = cols;
  230.   }
  231.     
  232.   /**
  233.    * Sets the legend to be for a nominal variable
  234.    * @param plotInstances the instances currently being plotted
  235.    * @param cIndex the index of the colouring attribute
  236.    */
  237.   protected void setNominal() {
  238.     m_isNumeric = false;
  239.     m_HorizontalPad = 0;
  240.     setOn(true);
  241.     m_oldWidth = -9000;
  242.      
  243.     this.repaint();
  244.   }
  245.   /**
  246.    * Sets the legend to be for a numeric variable
  247.    * @param mxC the maximum value of the colouring attribute
  248.    * @param mnC the minimum value of the colouring attribute
  249.    */
  250.   protected void setNumeric() {
  251.     m_isNumeric = true;
  252.     /*      m_maxC = mxC;
  253.     m_minC = mnC; */
  254.     double min=Double.POSITIVE_INFINITY;
  255.     double max=Double.NEGATIVE_INFINITY;
  256.     double value;
  257.     for (int i=0;i<m_Instances.numInstances();i++) {
  258.       if (!m_Instances.instance(i).isMissing(m_cIndex)) {
  259. value = m_Instances.instance(i).value(m_cIndex);
  260. if (value < min) {
  261.   min = value;
  262. }
  263. if (value > max) {
  264.   max = value;
  265. }
  266.       }
  267.     }
  268.      
  269.     // handle case where all values are missing
  270.     if (min == Double.POSITIVE_INFINITY) min = max = 0.0;
  271.     m_minC = min; m_maxC = max;
  272.     int whole = (int)Math.abs(m_maxC);
  273.     double decimal = Math.abs(m_maxC) - whole;
  274.     int nondecimal;
  275.     nondecimal = (whole > 0) 
  276.       ? (int)(Math.log(whole) / Math.log(10))
  277.       : 1;
  278.     
  279.     m_precisionC = (decimal > 0) 
  280.       ? (int)Math.abs(((Math.log(Math.abs(m_maxC)) / 
  281.       Math.log(10))))+2
  282.       : 1;
  283.     if (m_precisionC > VisualizeUtils.MAX_PRECISION) {
  284.       m_precisionC = 1;
  285.     }
  286.     String maxStringC = Utils.doubleToString(m_maxC,
  287.      nondecimal+1+m_precisionC
  288.      ,m_precisionC);
  289.     if (m_labelMetrics != null) {
  290.       m_HorizontalPad = m_labelMetrics.stringWidth(maxStringC);
  291.     }
  292.     whole = (int)Math.abs(m_minC);
  293.     decimal = Math.abs(m_minC) - whole;
  294.     nondecimal = (whole > 0) 
  295.       ? (int)(Math.log(whole) / Math.log(10))
  296.       : 1;
  297.     
  298.      m_precisionC = (decimal > 0) 
  299.        ? (int)Math.abs(((Math.log(Math.abs(m_minC)) / 
  300.       Math.log(10))))+2
  301.       : 1;
  302.      if (m_precisionC > VisualizeUtils.MAX_PRECISION) {
  303.        m_precisionC = 1;
  304.      }
  305.     
  306.      maxStringC = Utils.doubleToString(m_minC,
  307.        nondecimal+1+m_precisionC
  308.        ,m_precisionC);
  309.      if (m_labelMetrics != null) {
  310.        if (m_labelMetrics.stringWidth(maxStringC) > m_HorizontalPad) {
  311.  m_HorizontalPad = m_labelMetrics.stringWidth(maxStringC);
  312.        }
  313.      }
  314.     setOn(true);
  315.     this.repaint();
  316.   }
  317.     
  318.   /**
  319.    * Renders the legend for a nominal colouring attribute
  320.    * @param gx the graphics context
  321.    */
  322.   protected void paintNominal(Graphics gx) {
  323.     setFonts(gx);
  324.     int numClasses;
  325.     numClasses = m_Instances.attribute(m_cIndex).numValues();
  326.     int maxLabelLen = 0;
  327.     int idx=0;
  328.     int legendHeight;
  329.     int w = this.getWidth();
  330.     int hf = m_labelMetrics.getAscent();
  331.     for (int i=0;i<numClasses;i++) {
  332.       if (m_Instances.attribute(m_cIndex).value(i).length() > 
  333.   maxLabelLen) {
  334. maxLabelLen = m_Instances.
  335.   attribute(m_cIndex).value(i).length();
  336. idx = i;
  337.       }
  338.     }
  339.       
  340.     maxLabelLen = m_labelMetrics.stringWidth(m_Instances.
  341.      attribute(m_cIndex).value(idx));
  342.     
  343.     if (((w-(2*m_HorizontalPad))/(maxLabelLen+5)) >= numClasses) {
  344.       legendHeight = 1;
  345.     } else {
  346.       legendHeight = 2;
  347.     }
  348.     int x = m_HorizontalPad;
  349.     int y = 1 + hf;
  350.     // do the first row
  351.     int ci, mp;
  352.     Color pc;
  353.     int numToDo = ((legendHeight==1) ? numClasses : (numClasses/2));
  354.     for (int i=0;i<numToDo;i++) {
  355.      
  356.       gx.setColor((Color)m_colorList.elementAt(i));
  357.       // can we fit the full label or will each need to be trimmed?
  358.       if ((numToDo * maxLabelLen) > (w-(m_HorizontalPad*2))) {
  359. String val;
  360. val = m_Instances.attribute(m_cIndex).value(i);
  361. int sw = m_labelMetrics.stringWidth(val);
  362. int rm=0;
  363. // truncate string if necessary
  364. if (sw > ((w-(m_HorizontalPad*2)) / (numToDo))) {
  365.   int incr = (sw / val.length());
  366.   rm = (sw -  ((w-(m_HorizontalPad*2)) / numToDo)) / incr;
  367.   if (rm <= 0) {
  368.     rm = 0;
  369.   }
  370.   val = val.substring(0,val.length()-rm);
  371.   sw = m_labelMetrics.stringWidth(val);
  372. }
  373. NomLabel jj = new NomLabel(val, i);
  374. jj.setFont(gx.getFont());
  375. jj.setSize(m_labelMetrics.stringWidth(jj.getText()),
  376.    m_labelMetrics.getAscent() + 4);
  377. this.add(jj);
  378. jj.setLocation(x, y);
  379. jj.setForeground((Color)m_colorList.
  380.  elementAt(i % m_colorList.size()));
  381. x += sw + 2;
  382.       } else {
  383. NomLabel jj;
  384. jj = new NomLabel(m_Instances.attribute(m_cIndex).value(i), i);
  385. jj.setFont(gx.getFont());
  386. jj.setSize(m_labelMetrics.stringWidth(jj.getText()),
  387.    m_labelMetrics.getAscent() + 4);
  388. this.add(jj);
  389. jj.setLocation(x, y);
  390. jj.setForeground((Color)m_colorList.
  391.  elementAt(i % m_colorList.size()));
  392.   
  393. x += ((w-(m_HorizontalPad*2)) / numToDo);
  394.       }   
  395.     }
  396.     x = m_HorizontalPad;
  397.     y = 1+ hf + 5 +hf;
  398.     for (int i=numToDo;i<numClasses;i++) {
  399.       
  400.       gx.setColor((Color)m_colorList.elementAt(i));
  401.       if (((numClasses-numToDo+1) * maxLabelLen) > 
  402.   (w - (m_HorizontalPad*2))) {
  403. String val;
  404. val = m_Instances.attribute(m_cIndex).value(i);
  405. int sw = m_labelMetrics.stringWidth(val);
  406. int rm=0;
  407. // truncate string if necessary
  408. if (sw > ((w-(m_HorizontalPad*2)) / (numClasses-numToDo+1))) {
  409.   int incr = (sw / val.length());
  410.   rm = (sw -  ((w-(m_HorizontalPad*2)) / (numClasses-numToDo))) 
  411.     / incr;
  412.   if (rm <= 0) {
  413.     rm = 0;
  414.   }
  415.   val = val.substring(0,val.length()-rm);
  416.   sw = m_labelMetrics.stringWidth(val);
  417. }
  418. //this is the clipped string
  419. NomLabel jj = new NomLabel(val, i);
  420. jj.setFont(gx.getFont());
  421. jj.setSize(m_labelMetrics.stringWidth(jj.getText()),
  422.    m_labelMetrics.getAscent() + 4);
  423. this.add(jj);
  424. jj.setLocation(x, y);
  425. jj.setForeground((Color)m_colorList.
  426.  elementAt(i % m_colorList.size()));
  427. x += sw +2;
  428.       } else {
  429. //this is the full string
  430. NomLabel jj;
  431. jj = new NomLabel(m_Instances.attribute(m_cIndex).value(i), i);
  432. jj.setFont(gx.getFont());
  433. jj.setSize(m_labelMetrics.stringWidth(jj.getText()),
  434.    m_labelMetrics.getAscent() + 4);
  435. this.add(jj);
  436. jj.setLocation(x, y);
  437. jj.setForeground((Color)m_colorList.
  438.  elementAt(i % m_colorList.size()));
  439. x += ((w - (m_HorizontalPad*2)) / (numClasses-numToDo));
  440.       }   
  441.     }
  442.   }
  443.   /**
  444.    * Renders the legend for a numeric colouring attribute
  445.    * @param gx the graphics context
  446.    */
  447.   protected void paintNumeric(Graphics gx) {
  448.     setFonts(gx);
  449.     if (m_HorizontalPad == 0) {
  450.       setCindex(m_cIndex);
  451.     }
  452.     int w = this.getWidth();
  453.     double rs = 15;
  454.     double incr = 240.0 / (double)(w-(m_HorizontalPad*2));
  455.     int hf = m_labelMetrics.getAscent();
  456.       
  457.     for (int i=m_HorizontalPad;i<
  458.    (w-m_HorizontalPad);i++) {
  459.       Color c = new Color((int)rs,150,(int)(255-rs));
  460.       gx.setColor(c);
  461.       gx.drawLine(i,0,
  462.   i,0+m_spectrumHeight);
  463.       rs += incr;
  464.     }
  465.     int whole = (int)Math.abs(m_maxC);
  466.     double decimal = Math.abs(m_maxC) - whole;
  467.     int nondecimal;
  468.     nondecimal = (whole > 0) 
  469.       ? (int)(Math.log(whole) / Math.log(10))
  470.       : 1;
  471.     
  472.     m_precisionC = (decimal > 0) 
  473.       ? (int)Math.abs(((Math.log(Math.abs(m_maxC)) / 
  474. Math.log(10))))+2
  475.       : 1;
  476.     if (m_precisionC > VisualizeUtils.MAX_PRECISION) {
  477.       m_precisionC = 1;
  478.     }
  479.     String maxStringC = Utils.doubleToString(m_maxC,
  480.      nondecimal+1+m_precisionC
  481.      ,m_precisionC);
  482.     int mswc = m_labelMetrics.stringWidth(maxStringC);
  483.     int tmsc = mswc;
  484.     if (w > (2 * tmsc)) {
  485.       gx.setColor(Color.black);
  486.       gx.drawLine(m_HorizontalPad,
  487.   (m_spectrumHeight+5),
  488.   w-m_HorizontalPad,
  489.   (m_spectrumHeight+5));
  490.       gx.drawLine(w-m_HorizontalPad,
  491.   (m_spectrumHeight+5),
  492.   w-m_HorizontalPad,
  493.   (m_spectrumHeight+5+m_tickSize));
  494.       gx.drawString(maxStringC, 
  495.     (w-m_HorizontalPad)-(mswc/2),
  496.     (m_spectrumHeight+5+m_tickSize+hf));
  497.       gx.drawLine(m_HorizontalPad,
  498.   (m_spectrumHeight+5),
  499.   m_HorizontalPad,
  500.   (m_spectrumHeight+5+m_tickSize));
  501.       whole = (int)Math.abs(m_minC);
  502.       decimal = Math.abs(m_minC) - whole;
  503.       nondecimal = (whole > 0) 
  504. ? (int)(Math.log(whole) / Math.log(10))
  505. : 1;
  506.       
  507.       m_precisionC = (decimal > 0) 
  508. ? (int)Math.abs(((Math.log(Math.abs(m_minC)) / 
  509.   Math.log(10))))+2
  510. : 1;
  511.       if (m_precisionC > VisualizeUtils.MAX_PRECISION) {
  512. m_precisionC = 1;
  513.       }
  514.       
  515.       maxStringC = Utils.doubleToString(m_minC,
  516. nondecimal+1+m_precisionC
  517. ,m_precisionC);
  518.       mswc = m_labelMetrics.stringWidth(maxStringC);
  519.       gx.drawString(maxStringC, 
  520.     m_HorizontalPad-(mswc/2),
  521.     (m_spectrumHeight+5+m_tickSize+hf));
  522.       // draw the middle value if there is space
  523.       if (w > (3 * tmsc)) {
  524. double mid = m_minC+((m_maxC-m_minC)/2.0);
  525. gx.drawLine(m_HorizontalPad+((w-(2*m_HorizontalPad))/2),
  526.     (m_spectrumHeight+5),
  527.     m_HorizontalPad+((w-(2*m_HorizontalPad))/2),
  528.     (m_spectrumHeight+5+m_tickSize));
  529. whole = (int)Math.abs(mid);
  530. decimal = Math.abs(mid) - whole;
  531. nondecimal = (whole > 0) 
  532.   ? (int)(Math.log(whole) / Math.log(10))
  533.   : 1;
  534. m_precisionC = (decimal > 0) 
  535.   ? (int)Math.abs(((Math.log(Math.abs(mid)) / 
  536.     Math.log(10))))+2
  537.   : 1;
  538. if (m_precisionC > VisualizeUtils.MAX_PRECISION) {
  539.   m_precisionC = 1;
  540. }
  541. maxStringC = Utils.doubleToString(mid,
  542.   nondecimal+1+m_precisionC
  543.   ,m_precisionC);
  544. mswc = m_labelMetrics.stringWidth(maxStringC);
  545. gx.drawString(maxStringC,
  546.       m_HorizontalPad+((w-(2*m_HorizontalPad))/2)-(mswc/2),
  547.       (m_spectrumHeight+5+m_tickSize+hf));
  548.       }
  549.     }
  550.   }
  551.   /**
  552.    * Renders this component
  553.    * @param gx the graphics context
  554.    */
  555.   public void paintComponent(Graphics gx) {
  556.     super.paintComponent(gx);
  557.     if (m_isEnabled) {
  558.       if (m_isNumeric) {
  559. m_oldWidth = -9000;   //done so that if change back to nom, it will
  560. //work
  561. this.removeAll();
  562. paintNumeric(gx);
  563.       } else {
  564. if (m_Instances != null && 
  565.     m_Instances.numInstances() > 0 && 
  566.     m_Instances.numAttributes() > 0) {
  567.   if (m_oldWidth != this.getWidth()) {
  568.     this.removeAll();
  569.     m_oldWidth = this.getWidth();
  570.     paintNominal(gx);
  571.   }
  572. }
  573.       }
  574.     }
  575.   }
  576.   /**
  577.    * Main method for testing this class.
  578.    * @param args first argument must specify an arff file. Second can
  579.    * specify an optional index to colour labels on
  580.    */
  581.   public static void main(String [] args) {
  582.     try {
  583.       if (args.length < 1) {
  584. System.err.println("Usage : weka.gui.visualize.ClassPanel <dataset> "
  585.    +"[class col]");
  586. System.exit(1);
  587.       }
  588.       final javax.swing.JFrame jf = 
  589. new javax.swing.JFrame("Weka Knowledge Explorer: Class");
  590.       jf.setSize(500,100);
  591.       jf.getContentPane().setLayout(new BorderLayout());
  592.       final ClassPanel p2 = new ClassPanel();
  593.       jf.getContentPane().add(p2, BorderLayout.CENTER);
  594.       jf.addWindowListener(new java.awt.event.WindowAdapter() {
  595.   public void windowClosing(java.awt.event.WindowEvent e) {
  596.     jf.dispose();
  597.     System.exit(0);
  598.   }
  599. });
  600.       if (args.length >= 1) {
  601. System.err.println("Loading instances from " + args[0]);
  602. java.io.Reader r = new java.io.BufferedReader(
  603.    new java.io.FileReader(args[0]));
  604. Instances i = new Instances(r);
  605. i.setClassIndex(i.numAttributes()-1);
  606. p2.setInstances(i);
  607.       }
  608.       if (args.length > 1) {
  609. p2.setCindex((Integer.parseInt(args[1]))-1);
  610.       } else {
  611. p2.setCindex(0);
  612.       }
  613.       jf.setVisible(true);
  614.     } catch (Exception ex) {
  615.       ex.printStackTrace();
  616.       System.err.println(ex.getMessage());
  617.     }
  618.   }
  619. }