All Downloads are FREE. Search and download functionalities are using the official Maven repository.

weka.gui.visualize.Plot2D Maven / Gradle / Ivy

Go to download

The Waikato Environment for Knowledge Analysis (WEKA), a machine learning workbench. This is the stable version. Apart from bugfixes, this version does not receive any other updates.

There is a newer version: 3.8.6
Show newest version
/*
 *    This program is free software; you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation; either version 2 of the License, or
 *    (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License
 *    along with this program; if not, write to the Free Software
 *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

/*
 *    Plot2D.java
 *    Copyright (C) 2000 University of Waikato, Hamilton, New Zealand
 *
 */

package weka.gui.visualize;

import weka.core.FastVector;
import weka.core.Instances;
import weka.core.Utils;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.event.InputEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.Random;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;

/**
 * This class plots datasets in two dimensions. It can also plot
 * classifier errors and clusterer predictions.
 * 
 * @author Mark Hall ([email protected])
 * @version $Revision: 7059 $
 */
public class Plot2D
  extends JPanel {

  /** for serialization */
  private static final long serialVersionUID = -1673162410856660442L;  

  /* constants for shape types */
  public static final int MAX_SHAPES = 5;
  public static final int ERROR_SHAPE = 1000;
  public static final int MISSING_SHAPE = 2000;
  public static final int CONST_AUTOMATIC_SHAPE = -1;
  public static final int X_SHAPE = 0;
  public static final int PLUS_SHAPE = 1;
  public static final int DIAMOND_SHAPE = 2;
  public static final int TRIANGLEUP_SHAPE = 3;
  public static final int TRIANGLEDOWN_SHAPE = 4;
  public static final int DEFAULT_SHAPE_SIZE = 2;

  /** Default colour for the axis */
  protected Color m_axisColour = Color.green;

  /** Default colour for the plot background */
  protected Color m_backgroundColour = Color.black;

  /** The plots to display */
  protected FastVector m_plots = new FastVector();

  /** The master plot */
  protected PlotData2D m_masterPlot = null;

  /** The name of the master plot */
  protected String m_masterName = Messages.getInstance().getString("Plot2D_MasterName_Text");

  /** The instances to be plotted */
  protected Instances m_plotInstances=null;

  /** An optional "compainion" of the panel. If specified, this
      class will get to do its thing with our graphics context
      before we do any drawing. Eg. the visualize panel may need
      to draw polygons etc. before we draw plot axis and data points */
  protected Plot2DCompanion m_plotCompanion=null;

  /** For popping up text info on data points */
  protected JFrame m_InstanceInfo = null;
  protected JTextArea m_InstanceInfoText = new JTextArea();

  /** The list of the colors used */
  protected FastVector m_colorList;

  /** default colours for colouring discrete class */
  protected Color [] m_DefaultColors = {Color.blue,
					Color.red,
					Color.green,
					Color.cyan,
					Color.pink,
					new Color(255, 0, 255),
					Color.orange,
					new Color(255, 0, 0),
					new Color(0, 255, 0),
					Color.white};

  /** Indexes of the attributes to go on the x and y axis and the attribute
      to use for colouring and the current shape for drawing */
  protected int m_xIndex=0;
  protected int m_yIndex=0;
  protected int m_cIndex=0;
  protected int m_sIndex=0;

  /** Holds the min and max values of the x, y and colouring attributes 
   over all plots */
  protected double m_maxX;
  protected double m_minX;
  protected double m_maxY;
  protected double m_minY;
  protected double m_maxC;
  protected double m_minC;
    
  /** Axis padding */
  protected final int m_axisPad = 5;

  /** Tick size */
  protected final int m_tickSize = 5;

  /**the offsets of the axes once label metrics are calculated */
  protected int m_XaxisStart=0;
  protected int m_YaxisStart=0;
  protected int m_XaxisEnd=0;
  protected int m_YaxisEnd=0;

  /** if the user resizes the window, or the attributes selected for
      the attributes change, then the lookup table for points needs
      to be recalculated */
  protected boolean m_plotResize = true;
  
  /** if the user changes attribute assigned to an axis */
  protected boolean m_axisChanged = false;

  /** An array used to show if a point is hidden or not.
   * This is used for speeding up the drawing of the plot panel
   * although I am not sure how much performance this grants over
   * not having it.
   */
  protected int[][] m_drawnPoints;

  /** Font for labels */
  protected Font m_labelFont;
  protected FontMetrics m_labelMetrics=null; 

  /** the level of jitter */
  protected int m_JitterVal=0;

  /** random values for perterbing the data points */
  protected Random m_JRand = new Random(0);

  /** lookup table for plotted points */
  protected double [][] m_pointLookup=null;

  /** Constructor */
  public Plot2D() {
    super();
    setProperties();
    this.setBackground(m_backgroundColour);
    m_InstanceInfoText.setFont(new Font("Monospaced", Font.PLAIN,12));
    m_InstanceInfoText.setEditable(false);

    m_drawnPoints = new int[this.getWidth()][this.getHeight()];

    /** Set up some default colours */
    m_colorList = new FastVector(10);
    for (int noa = m_colorList.size(); noa < 10; noa++) {
      Color pc = m_DefaultColors[noa % 10];
      int ija =  noa / 10;
      ija *= 2; 
      for (int j=0;j this.getSize().width || y1 < 0 
	|| y1 > this.getSize().height) {
      return false;
    }
    return true;
  }

  /**
   * Set a companion class. This is a class that might want
   * to render something on the plot before we do our thing. Eg,
   * Malcolm's shape drawing stuff needs to happen before we plot
   * axis and points
   * @param p a companion class
   */
  public void setPlotCompanion(Plot2DCompanion p) {
    m_plotCompanion = p;
  }

  /**
   * Set level of jitter and repaint the plot using the new jitter value
   * @param j the level of jitter
   */
  public void setJitter(int j) {
    if (m_plotInstances.numAttributes() > 0 
	&& m_plotInstances.numInstances() > 0) {
      if (j >= 0) {
	m_JitterVal = j;
	m_JRand = new Random(m_JitterVal);
	//      if (m_pointLookup != null) {
	m_drawnPoints = new int[m_XaxisEnd - m_XaxisStart + 1]
	  [m_YaxisEnd - m_YaxisStart + 1];
	updatePturb();
	//      }
	this.repaint();
      }
    }
  }

  /**
   * Set a list of colours to use when colouring points according
   * to class values or cluster numbers
   * @param cols the list of colours to use
   */
  public void setColours (FastVector cols) {
    m_colorList = cols;
  }

  /**
   * Set the index of the attribute to go on the x axis
   * @param x the index of the attribute to use on the x axis
   */
  public void setXindex(int x) {
    m_xIndex = x;
    for (int i=0;i 
	    longest) {
	  longest = m_masterPlot.m_plotInstances.attribute(j).name().length();
	}
      }

      StringBuffer insts = new StringBuffer(); 
      for (int jj=0;jj= px-size) && (x <= px+size) &&
		(y >= py-size) && (y <= py+size)) {
	      {
		insts.append(Messages.getInstance().getString("Plot2D_SearchPoints_Text_First") + temp_plot.m_plotName
			     + Messages.getInstance().getString("Plot2D_SearchPoints_Text_Second") + (i + 1 ) + Messages.getInstance().getString("Plot2D_SearchPoints_Text_Third"));
		for (int j=0;j 0) {
	// Pop up a new frame
	if (newFrame || m_InstanceInfo == null) {
	  JTextArea jt = new JTextArea();
	  jt.setFont(new Font("Monospaced", Font.PLAIN,12));
	  jt.setEditable(false);
	  jt.setText(insts.toString());
	  final JFrame jf = new JFrame(Messages.getInstance().getString("Plot2D_SearchPoints_JFrame_Text"));
	  final JFrame testf = m_InstanceInfo;
	  jf.addWindowListener(new WindowAdapter() {
	      public void windowClosing(WindowEvent e) {
		if (!newFrame || testf == null) {
		  m_InstanceInfo = null;
		}
		jf.dispose();
	      }
	    });
	  jf.getContentPane().setLayout(new BorderLayout());
	  jf.getContentPane().add(new JScrollPane(jt), BorderLayout.CENTER);
	  jf.pack();
	  jf.setSize(320, 400);
	  jf.setVisible(true);
	  if (m_InstanceInfo == null) {
	    m_InstanceInfo = jf;
	    m_InstanceInfoText = jt;
	  }
	}  else {
	  // Overwrite info in existing frame	  
	  m_InstanceInfoText.setText(insts.toString());
	}
      }
    }
  }
  

  /**
   * Determine the min and max values for axis and colouring attributes
   */
  public void determineBounds() {
    double value,min,max;
    
    // find maximums minimums over all plots
    m_minX = ((PlotData2D)m_plots.elementAt(0)).m_minX;
    m_maxX = ((PlotData2D)m_plots.elementAt(0)).m_maxX;
    m_minY = ((PlotData2D)m_plots.elementAt(0)).m_minY;
    m_maxY = ((PlotData2D)m_plots.elementAt(0)).m_maxY;
    m_minC = ((PlotData2D)m_plots.elementAt(0)).m_minC;
    m_maxC = ((PlotData2D)m_plots.elementAt(0)).m_maxC;
    for (int i=1;i m_maxX) {
	m_maxX = value;
      }
      value = ((PlotData2D)m_plots.elementAt(i)).m_minY;
      if (value < m_minY) {
	m_minY= value;
      }
      value = ((PlotData2D)m_plots.elementAt(i)).m_maxY;
      if (value > m_maxY) {
	m_maxY = value;
      }
      value = ((PlotData2D)m_plots.elementAt(i)).m_minC;
      if (value < m_minC) {
	m_minC = value;
      }
      value = ((PlotData2D)m_plots.elementAt(i)).m_maxC;
      if (value > m_maxC) {
	m_maxC = value;
      }
    }

    fillLookup();
    this.repaint();
  }

    
  //to convert screen coords to attrib values
  // note that I use a double to avoid accuracy 
  //headaches with ints
  /**
   * convert a Panel x coordinate to a raw x value.
   * @param scx The Panel x coordinate
   * @return A raw x value.
   */
  public double convertToAttribX(double scx) {
    double temp = m_XaxisEnd - m_XaxisStart;
    double temp2 = ((scx - m_XaxisStart) * (m_maxX - m_minX)) / temp;
      
    temp2 = temp2 + m_minX;
      
    return temp2;
  }
    
  /**
   * convert a Panel y coordinate to a raw y value.
   * @param scy The Panel y coordinate
   * @return A raw y value.
   */
  public double convertToAttribY(double scy) {
    double temp = m_YaxisEnd - m_YaxisStart;
    double temp2 = ((scy - m_YaxisEnd) * (m_maxY - m_minY)) / temp;
      
    temp2 = -(temp2 - m_minY);
      
    return temp2;
  }
  //////
    
  /**
   * returns a value by which an x value can be peturbed. Makes sure
   * that the x value+pturb stays within the plot bounds
   * @param xvalP the x coordinate to be peturbed
   * @param xj a random number to use in calculating a peturb value
   * @return a peturb value
   */
  int pturbX(double xvalP, double xj) {
    int xpturb = 0;
    if (m_JitterVal > 0) {
      xpturb = (int)((double)m_JitterVal * (xj / 2.0));
      if (((xvalP + xpturb) < m_XaxisStart) || 
	  ((xvalP + xpturb) > m_XaxisEnd)) {
	xpturb *= -1;
      }
    }
    return xpturb;
  }

  /**
   * Convert an raw x value to Panel x coordinate.
   * @param xval the raw x value
   * @return an x value for plotting in the panel.
   */
  public double convertToPanelX(double xval) {
    double temp = (xval - m_minX)/(m_maxX - m_minX);
    double temp2 = temp * (m_XaxisEnd - m_XaxisStart);
      
    temp2 = temp2 + m_XaxisStart;
	
    return temp2;
  }

  /**
   * returns a value by which a y value can be peturbed. Makes sure
   * that the y value+pturb stays within the plot bounds
   * @param yvalP the y coordinate to be peturbed
   * @param yj a random number to use in calculating a peturb value
   * @return a peturb value
   */
  int pturbY(double yvalP, double yj) {
    int ypturb = 0;
    if (m_JitterVal > 0) {
      ypturb = (int)((double)m_JitterVal * (yj / 2.0));
      if (((yvalP + ypturb) < m_YaxisStart) || 
	  ((yvalP + ypturb) > m_YaxisEnd)) {
	ypturb *= -1;
      }
    }
    return ypturb;
  }

  /**
   * Convert an raw y value to Panel y coordinate.
   * @param yval the raw y value
   * @return an y value for plotting in the panel.
   */
  public double convertToPanelY(double yval) {
    double temp = (yval - m_minY)/(m_maxY - m_minY);
    double temp2 = temp * (m_YaxisEnd - m_YaxisStart);
      
    temp2 = m_YaxisEnd - temp2;

    return temp2;
  }

  /**
   * Draws an X.
   * @param gx the graphics context
   * @param x the x coord
   * @param y the y coord
   * @param size the size of the shape
   */
  private static void drawX(Graphics gx, double x, double y, int size) {
     gx.drawLine((int)(x-size),(int)(y-size),
		  (int)(x+size),(int)(y+size));
     
      gx.drawLine((int)(x+size),(int)(y-size),
		  (int)(x-size),(int)(y+size));     
  }

  /**
   * Draws a plus.
   * @param gx the graphics context
   * @param x the x coord
   * @param y the y coord
   * @param size the size of the shape
   */
  private static void drawPlus(Graphics gx, double x, double y, int size) {
     gx.drawLine((int)(x-size),(int)(y),
		  (int)(x+size),(int)(y));
     
      gx.drawLine((int)(x),(int)(y-size),
		  (int)(x),(int)(y+size));     
  }

  /**
   * Draws a diamond.
   * @param gx the graphics context
   * @param x the x coord
   * @param y the y coord
   * @param size the size of the shape
   */
  private static void drawDiamond(Graphics gx, double x, double y, int size) {
    gx.drawLine((int)(x-size),(int)(y),
		(int)(x),(int)(y-size));
    
    gx.drawLine((int)(x),(int)(y-size),
		  (int)(x+size),(int)(y));

    gx.drawLine((int)(x+size),(int)(y),
		  (int)(x),(int)(y+size));

     gx.drawLine((int)(x),(int)(y+size),
		  (int)(x-size),(int)(y));
  }

  /**
   * Draws an triangle (point at top).
   * @param gx the graphics context
   * @param x the x coord
   * @param y the y coord
   * @param size the size of the shape
   */
  private static void drawTriangleUp(Graphics gx, double x, 
				     double y, int size) {
    gx.drawLine((int)(x),(int)(y-size),
		(int)(x-size),(int)(y+size));

    gx.drawLine((int)(x-size),(int)(y+size),
		(int)(x+size),(int)(y+size));

    gx.drawLine((int)(x+size),(int)(y+size),
		(int)(x),(int)(y-size));

  }

  /**
   * Draws an triangle (point at bottom).
   * @param gx the graphics context
   * @param x the x coord
   * @param y the y coord
   * @param size the size of the shape
   */
  private static void drawTriangleDown(Graphics gx, double x, 
				       double y, int size) {
    gx.drawLine((int)(x),(int)(y+size),
		(int)(x-size),(int)(y-size));

    gx.drawLine((int)(x-size),(int)(y-size),
		(int)(x+size),(int)(y-size));

    gx.drawLine((int)(x+size),(int)(y-size),
		(int)(x),(int)(y+size));

  }

  /**
   * Draws a data point at a given set of panel coordinates at a given
   * size and connects a line to the previous point.
   * @param x the x coord
   * @param y the y coord
   * @param xprev the x coord of the previous point
   * @param yprev the y coord of the previous point
   * @param size the size of the point
   * @param shape the shape of the data point (square is reserved for nominal
   * error data points). Shapes: 0=x, 1=plus, 2=diamond, 3=triangle(up),
   * 4 = triangle (down).
   * @param gx the graphics context
   */
  protected static void drawDataPoint(double x, 
			       double y,
			       double xprev,
			       double yprev,
			       int size,
			       int shape,
			       Graphics gx) {

    drawDataPoint(x,y,size,shape,gx);

    // connect a line to the previous point
    gx.drawLine((int)x, (int)y, (int)xprev, (int)yprev);
  }

  /**
   * Draws a data point at a given set of panel coordinates at a given
   * size.
   * @param x the x coord
   * @param y the y coord
   * @param size the size of the point
   * @param shape the shape of the data point (square is reserved for nominal
   * error data points). Shapes: 0=x, 1=plus, 2=diamond, 3=triangle(up),
   * 4 = triangle (down).
   * @param gx the graphics context
   */
  protected static void drawDataPoint(double x, 
				      double y,
				      int size,
				      int shape,
				      Graphics gx) {

    Font lf = new Font("Monospaced", Font.PLAIN, 12);
    FontMetrics fm = gx.getFontMetrics(lf);

    if (size == 0) {
      size = 1;
    }

    if (shape != ERROR_SHAPE && shape != MISSING_SHAPE) {
      shape = shape % 5;
    }

    switch (shape) {
    case X_SHAPE:
      drawX(gx, x, y, size);
      break;      
    case PLUS_SHAPE:
      drawPlus(gx, x, y, size);
      break;
    case DIAMOND_SHAPE:
      drawDiamond(gx, x, y, size);
      break;
    case TRIANGLEUP_SHAPE:
      drawTriangleUp(gx, x, y, size);
      break;
    case TRIANGLEDOWN_SHAPE:
      drawTriangleDown(gx, x, y, size);
      break;
    case ERROR_SHAPE: // draws the nominal error shape 
      gx.drawRect((int)(x-size),(int)(y-size),(size*2),(size*2));
      break;
    case MISSING_SHAPE:
      int hf = fm.getAscent();
      int width = fm.stringWidth("M");
      gx.drawString("M",(int)(x-(width / 2)), (int)(y+(hf / 2)));
      break;
    }
  }

  /**
   * Updates the perturbed values for the plots when the jitter value is
   * changed
   */
  private void updatePturb() {
    double xj=0;
    double yj=0;
    for (int j=0;j 0) {
	    xj = m_JRand.nextGaussian();
	    yj = m_JRand.nextGaussian();
	  }
	  temp_plot.m_pointLookup[i][2] = 
	    pturbX(temp_plot.m_pointLookup[i][0],xj);
	  temp_plot.m_pointLookup[i][3] = 
	    pturbY(temp_plot.m_pointLookup[i][1],yj);
	}
      }
    }
  }

  /**
   * Fills the lookup caches for the plots. Also calculates errors for
   * numeric predictions (if any) in plots
   */
  private void fillLookup() {

    for (int j=0;j 0 &&
	  temp_plot.m_plotInstances.numAttributes() > 0) {
	for (int i=0;i 0) {
	    prevx = (temp_plot.m_pointLookup[i - 1][0] + 
			temp_plot.m_pointLookup[i - 1][2]);
	    prevy = (temp_plot.m_pointLookup[i - 1][1] + 
			temp_plot.m_pointLookup[i - 1][3]);
	  }

	  int x_range = (int)x - m_XaxisStart;
	  int y_range = (int)y - m_YaxisStart;

	  if (x_range >= 0 && y_range >= 0) {
	    if (m_drawnPoints[x_range][y_range] == i 
		|| m_drawnPoints[x_range][y_range] == 0
		|| temp_plot.m_shapeSize[i] == temp_plot.m_alwaysDisplayPointsOfThisSize
		|| temp_plot.m_displayAllPoints == true) {
	      m_drawnPoints[x_range][y_range] = i;
	      if (temp_plot.m_plotInstances.attribute(m_cIndex).isNominal()) {
		if (temp_plot.m_plotInstances.attribute(m_cIndex).numValues() >
		    m_colorList.size() && 
		    !temp_plot.m_useCustomColour) {
		  extendColourMap(temp_plot.m_plotInstances.
				  attribute(m_cIndex).numValues());
		}

		Color ci;
		if (temp_plot.m_plotInstances.instance(i).
		    isMissing(m_cIndex)) {
		  ci = Color.gray;
		} else {
		  int ind = (int)temp_plot.m_plotInstances.instance(i).
		    value(m_cIndex);
		  ci = (Color)m_colorList.elementAt(ind);
		}

		if (!temp_plot.m_useCustomColour) {
		  gx.setColor(ci);	    
		} else {
		  gx.setColor(temp_plot.m_customColour);
		}

		if (temp_plot.m_plotInstances.instance(i).
		    isMissing(m_cIndex)) {
		  if (temp_plot.m_connectPoints[i] == true) {
		    drawDataPoint(x,y,prevx,prevy,temp_plot.m_shapeSize[i],
				  MISSING_SHAPE,gx);
		  } else {
		    drawDataPoint(x,y,temp_plot.m_shapeSize[i],
				  MISSING_SHAPE,gx);
		  }
		} else {
		  if (temp_plot.m_shapeType[i] == CONST_AUTOMATIC_SHAPE) {
		    if (temp_plot.m_connectPoints[i] == true) {
		      drawDataPoint(x,y,prevx,prevy,
				    temp_plot.m_shapeSize[i],j,gx);
		    } else {
		      drawDataPoint(x,y,temp_plot.m_shapeSize[i],j,gx);
		    }
		  } else {
		    if (temp_plot.m_connectPoints[i] == true) {
		       drawDataPoint(x,y,prevx,prevy,temp_plot.m_shapeSize[i],
				     temp_plot.m_shapeType[i],gx);
		    } else {
		      drawDataPoint(x,y,temp_plot.m_shapeSize[i],
				    temp_plot.m_shapeType[i],gx);
		    }
		  }
		}
	      } else {
		double r;
		Color ci = null;
		if (!temp_plot.m_plotInstances.instance(i).
		    isMissing(m_cIndex)) {
		  r = (temp_plot.m_plotInstances.instance(i).
		       value(m_cIndex) - m_minC) / (m_maxC - m_minC);
		  r = (r * 240) + 15;
		  ci = new Color((int)r,150,(int)(255-r));
		} else {
		  ci = Color.gray;
		}
		if (!temp_plot.m_useCustomColour) {
		  gx.setColor(ci);
		} else {
		  gx.setColor(temp_plot.m_customColour);
		}
		if (temp_plot.m_plotInstances.instance(i).
		    isMissing(m_cIndex)) {
		  if (temp_plot.m_connectPoints[i] == true) {
		    drawDataPoint(x,y,prevx,prevy,temp_plot.m_shapeSize[i],
				  MISSING_SHAPE,gx);
		  } else {
		    drawDataPoint(x,y,temp_plot.m_shapeSize[i],
				  MISSING_SHAPE,gx);
		  }
		} else {
		  if (temp_plot.m_shapeType[i] == CONST_AUTOMATIC_SHAPE) {
		    if (temp_plot.m_connectPoints[i] == true) {
		      drawDataPoint(x,y,prevx,prevy,
				    temp_plot.m_shapeSize[i],j,gx);
		    } else {
		      drawDataPoint(x,y,temp_plot.m_shapeSize[i],j,gx);
		    }
		  } else {
		    if (temp_plot.m_connectPoints[i] == true) {
		      drawDataPoint(x,y,prevx,prevy,temp_plot.m_shapeSize[i],
				    temp_plot.m_shapeType[i],gx);
		    } else {
		      drawDataPoint(x,y,temp_plot.m_shapeSize[i],
				    temp_plot.m_shapeType[i],gx);
		    }
		  }
		}
	      }
	    }
	  }
	}
      }
    }
  }

  /*
  public void determineAxisPositions(Graphics gx) {
    setFonts(gx);
    int mxs = m_XaxisStart;
    int mxe = m_XaxisEnd;
    int mys = m_YaxisStart;
    int mye = m_YaxisEnd;
    m_axisChanged = false;

    int h = this.getHeight();
    int w = this.getWidth();
    int hf = m_labelMetrics.getAscent();
    int mswx=0;
    int mswy=0;

    //      determineBounds();
    int fieldWidthX = (int)((Math.log(m_maxX)/Math.log(10)))+1;
    int precisionX = 1;
    if ((Math.abs(m_maxX-m_minX) < 1) && ((m_maxY-m_minX) != 0)) {
      precisionX = (int)Math.abs(((Math.log(Math.abs(m_maxX-m_minX)) / 
				   Math.log(10))))+1;
    }
    String maxStringX = Utils.doubleToString(m_maxX,
					     fieldWidthX+1+precisionX
					     ,precisionX);
    mswx = m_labelMetrics.stringWidth(maxStringX);
    int fieldWidthY = (int)((Math.log(m_maxY)/Math.log(10)))+1;
    int precisionY = 1;
    if (Math.abs((m_maxY-m_minY)) < 1 && ((m_maxY-m_minY) != 0)) {
      precisionY = (int)Math.abs(((Math.log(Math.abs(m_maxY-m_minY)) / 
				   Math.log(10))))+1;
    }
    String maxStringY = Utils.doubleToString(m_maxY,
					     fieldWidthY+1+precisionY
					     ,precisionY);
    String minStringY = Utils.doubleToString(m_minY,
					     fieldWidthY+1+precisionY
					     ,precisionY);

    if (m_plotInstances.attribute(m_yIndex).isNumeric()) {
      mswy = (m_labelMetrics.stringWidth(maxStringY) > 
	      m_labelMetrics.stringWidth(minStringY))
	? m_labelMetrics.stringWidth(maxStringY)
	: m_labelMetrics.stringWidth(minStringY);
    } else {
      mswy = m_labelMetrics.stringWidth("MM");
    }

    m_YaxisStart = m_axisPad;
    m_XaxisStart = 0+m_axisPad+m_tickSize+mswy;

    m_XaxisEnd = w-m_axisPad-(mswx/2);
      
    m_YaxisEnd = h-m_axisPad-(2 * hf)-m_tickSize;
    } */

  /**
   * Draws the axis and a spectrum if the colouring attribute is numeric
   * @param gx the graphics context
   */
  private void paintAxis(Graphics gx) {
    setFonts(gx);
    int mxs = m_XaxisStart;
    int mxe = m_XaxisEnd;
    int mys = m_YaxisStart;
    int mye = m_YaxisEnd;
    m_plotResize = false;

    int h = this.getHeight();
    int w = this.getWidth();
    int hf = m_labelMetrics.getAscent();
    int mswx=0;
    int mswy=0;

    //      determineBounds();
    int precisionXmax = 1;
    int precisionXmin = 1;
    int precisionXmid = 1;
    /*if ((Math.abs(m_maxX-m_minX) < 1) && ((m_maxY-m_minX) != 0)) {
      precisionX = (int)Math.abs(((Math.log(Math.abs(m_maxX-m_minX)) / 
				   Math.log(10))))+1;
				   } */
    int whole = (int)Math.abs(m_maxX);
    double decimal = Math.abs(m_maxX) - whole;
    int nondecimal;
    nondecimal = (whole > 0) 
      ? (int)(Math.log(whole) / Math.log(10))
      : 1;
    
    precisionXmax = (decimal > 0) 
      ? (int)Math.abs(((Math.log(Math.abs(m_maxX)) / 
				      Math.log(10))))+2
      : 1;
    if (precisionXmax > VisualizeUtils.MAX_PRECISION) {
      precisionXmax = 1;
    }

    String maxStringX = Utils.doubleToString(m_maxX,
					     nondecimal+1+precisionXmax
					     ,precisionXmax);

    whole = (int)Math.abs(m_minX);
    decimal = Math.abs(m_minX) - whole;
    nondecimal = (whole > 0) 
      ? (int)(Math.log(whole) / Math.log(10))
      : 1;
    precisionXmin = (decimal > 0) 
      ? (int)Math.abs(((Math.log(Math.abs(m_minX)) / 
				      Math.log(10))))+2
      : 1;
    if (precisionXmin > VisualizeUtils.MAX_PRECISION) {
      precisionXmin = 1;
    }
   
    String minStringX = Utils.doubleToString(m_minX,
					     nondecimal+1+precisionXmin,
					     precisionXmin);

    mswx = m_labelMetrics.stringWidth(maxStringX);

    int precisionYmax = 1;
    int precisionYmin = 1;
    int precisionYmid = 1;
    whole = (int)Math.abs(m_maxY);
    decimal = Math.abs(m_maxY) - whole;
    nondecimal = (whole > 0) 
      ? (int)(Math.log(whole) / Math.log(10))
      : 1;
    precisionYmax = (decimal > 0) 
      ? (int)Math.abs(((Math.log(Math.abs(m_maxY)) / 
				      Math.log(10))))+2
      : 1;
    if (precisionYmax > VisualizeUtils.MAX_PRECISION) {
      precisionYmax = 1;
    }
    
    String maxStringY = Utils.doubleToString(m_maxY,
					     nondecimal+1+precisionYmax
					     ,precisionYmax);


    whole = (int)Math.abs(m_minY);
    decimal = Math.abs(m_minY) - whole;
    nondecimal = (whole > 0) 
      ? (int)(Math.log(whole) / Math.log(10))
      : 1;
    precisionYmin = (decimal > 0) 
      ? (int)Math.abs(((Math.log(Math.abs(m_minY)) / 
				      Math.log(10))))+2
      : 1;
    if (precisionYmin > VisualizeUtils.MAX_PRECISION) {
      precisionYmin = 1;
    }
   
    String minStringY = Utils.doubleToString(m_minY,
					     nondecimal+1+precisionYmin
					     ,precisionYmin);

    if (m_plotInstances.attribute(m_yIndex).isNumeric()) {
      mswy = (m_labelMetrics.stringWidth(maxStringY) > 
	      m_labelMetrics.stringWidth(minStringY))
	? m_labelMetrics.stringWidth(maxStringY)
	: m_labelMetrics.stringWidth(minStringY);
      mswy += m_labelMetrics.stringWidth("M");
    } else {
      mswy = m_labelMetrics.stringWidth("MM");
    }

    m_YaxisStart = m_axisPad;
    m_XaxisStart = 0+m_axisPad+m_tickSize+mswy;

    m_XaxisEnd = w-m_axisPad-(mswx/2);
      
    m_YaxisEnd = h-m_axisPad-(2 * hf)-m_tickSize;

    // draw axis
    gx.setColor(m_axisColour);
    if (m_plotInstances.attribute(m_xIndex).isNumeric()) {
      if (w > (2 * mswx)) {
	
	gx.drawString(maxStringX, 
		      m_XaxisEnd-(mswx/2),
		      m_YaxisEnd+hf+m_tickSize);
	
	mswx = m_labelMetrics.stringWidth(minStringX);
	gx.drawString(minStringX,
		      (m_XaxisStart-(mswx/2)),
		      m_YaxisEnd+hf+m_tickSize);

	// draw the middle value
	if (w > (3 * mswx) && 
	    (m_plotInstances.attribute(m_xIndex).isNumeric())) {
	  double mid = m_minX+((m_maxX-m_minX)/2.0);
	   whole = (int)Math.abs(mid);
	   decimal = Math.abs(mid) - whole;
	   nondecimal = (whole > 0) 
	     ? (int)(Math.log(whole) / Math.log(10))
	     : 1;
	   precisionXmid = (decimal > 0) 
	     ? (int)Math.abs(((Math.log(Math.abs(mid)) / 
			       Math.log(10))))+2
	     : 1;
	   if (precisionXmid > VisualizeUtils.MAX_PRECISION) {
	     precisionXmid = 1;
	   }
	  
	  String maxString = Utils.doubleToString(mid,
						  nondecimal+1+precisionXmid,
						  precisionXmid);
	  int sw = m_labelMetrics.stringWidth(maxString);
	  double mx = m_XaxisStart+((double)(m_XaxisEnd-m_XaxisStart)/2.0);
	  gx.drawString(maxString,
			(int)(mx-(((double)sw)/2.0)),
			m_YaxisEnd+hf+m_tickSize);
	  gx.drawLine((int)mx,m_YaxisEnd,(int)mx,m_YaxisEnd+m_tickSize);
	}
      }
    } else {
      int numValues = m_plotInstances.attribute(m_xIndex).numValues();
      int div = (numValues % 2 > 0) ? (numValues/2)+1 : (numValues/2);
      int maxXStringWidth = (m_XaxisEnd - m_XaxisStart) / numValues;

      for (int i=0;i maxXStringWidth) {
	  int incr = (sw / val.length());
	  rm = (sw - maxXStringWidth) / incr;
	  if (rm == 0) {
	    rm = 1;
	  }
	  val = val.substring(0,val.length()-rm);
	  sw = m_labelMetrics.stringWidth(val);
	}
	if (i == 0) {
	  gx.drawString(val,(int)convertToPanelX(i),
			m_YaxisEnd+hf+m_tickSize);
	} else if (i == numValues -1) {
	  if ((i % 2) == 0) {
	    gx.drawString(val,
			  m_XaxisEnd-sw,
			  m_YaxisEnd+hf+m_tickSize);
	  } else {
	    gx.drawString(val,
			  m_XaxisEnd-sw,
			  m_YaxisEnd+(2*hf)+m_tickSize);
	  }
	} else {
	  if ((i % 2) == 0) {
	    gx.drawString(val,
			  (int)convertToPanelX(i)-(sw/2),
			  m_YaxisEnd+hf+m_tickSize);
	  } else {
	    gx.drawString(val,
			  (int)convertToPanelX(i)-(sw/2),
			  m_YaxisEnd+(2*hf)+m_tickSize);
	  }
	}
	gx.drawLine((int)convertToPanelX(i),
		    m_YaxisEnd,
		    (int)convertToPanelX(i),
		    m_YaxisEnd+m_tickSize);
      }
	
    }

    // draw the y axis
    if (m_plotInstances.attribute(m_yIndex).isNumeric()) {
      if (h > (2 * hf)) {
	gx.drawString(maxStringY, 
		      m_XaxisStart-mswy-m_tickSize,
		      m_YaxisStart+(hf));

	gx.drawString(minStringY,
		      (m_XaxisStart-mswy-m_tickSize),
		      m_YaxisEnd);

	// draw the middle value
	if (w > (3 * hf) && 
	    (m_plotInstances.attribute(m_yIndex).isNumeric())) {
	  double mid = m_minY+((m_maxY-m_minY)/2.0);
	  whole = (int)Math.abs(mid);
	  decimal = Math.abs(mid) - whole;
	  nondecimal = (whole > 0) 
	    ? (int)(Math.log(whole) / Math.log(10))
	    : 1;
	  precisionYmid = (decimal > 0) 
	    ? (int)Math.abs(((Math.log(Math.abs(mid)) / 
			      Math.log(10))))+2
	    : 1;
	  if (precisionYmid > VisualizeUtils.MAX_PRECISION) {
	    precisionYmid = 1;
	  }
	 
	  String maxString = Utils.doubleToString(mid,
						  nondecimal+1+precisionYmid,
						  precisionYmid);
	  int sw = m_labelMetrics.stringWidth(maxString);
	  double mx = m_YaxisStart+((double)(m_YaxisEnd-m_YaxisStart)/2.0);
	  gx.drawString(maxString,
			m_XaxisStart-sw-m_tickSize-1,
			(int)(mx+(((double)hf)/2.0)));
	  gx.drawLine(m_XaxisStart-m_tickSize,(int)mx,m_XaxisStart,(int)mx);
	}
      }
    } else {
      int numValues = m_plotInstances.attribute(m_yIndex).numValues();
      int div = ((numValues % 2) == 0) ? (numValues/2) : (numValues/2+1);
      int maxYStringHeight = (m_YaxisEnd - m_XaxisStart) / div;
      int sw = m_labelMetrics.stringWidth("M");
      for (int i=0;i= (2*hf)) {
	  String val = m_plotInstances.attribute(m_yIndex).value(i);
	  int numPrint = ((maxYStringHeight/hf) > val.length()) ?
	    val.length() :
	    (maxYStringHeight/hf);
	    
	  for (int j=0;j 0
	&& m_plotInstances.numAttributes() > 0) {
      if (m_plotCompanion != null) {
	m_plotCompanion.prePlot(gx);
      }

      m_JRand = new Random(m_JitterVal);
      paintAxis(gx);
      if (m_axisChanged || m_plotResize) {
	int x_range = m_XaxisEnd - m_XaxisStart;
	int y_range = m_YaxisEnd - m_YaxisStart;
	if (x_range < 10) {
	  x_range = 10;
	}
	if (y_range < 10) {
	  y_range = 10;
	}

	m_drawnPoints = new int[x_range + 1][y_range + 1];
	fillLookup();
	m_plotResize = false;
	m_axisChanged = false;
      }
      paintData(gx);
    }
  }

  protected static Color checkAgainstBackground(Color c, Color background) {
    if (background == null) {
      return c;
    }
    
    if (c.equals(background)) {
      int red = c.getRed();
      int blue = c.getBlue();
      int green = c.getGreen();
      red += (red < 128) ? (255 - red) / 2 : -(red / 2);
      blue += (blue < 128) ? (blue - red) / 2 : -(blue / 2);
      green += (green< 128) ? (255 - green) / 2 : -(green / 2);
      c = new Color(red, green, blue);
    }
    return c;
  }

  /**
   * Main method for testing this class
   * @param args arguments
   */
  public static void main(String [] args) {
    try {
      if (args.length < 1) {
	System.err.println(Messages.getInstance().getString("Plot2D_Main_Error_Text_First"));
	System.exit(1);
      }

      final javax.swing.JFrame jf = 
	new javax.swing.JFrame(Messages.getInstance().getString("Plot2D_Main_JFrame_Text"));
      jf.setSize(500,400);
      jf.getContentPane().setLayout(new BorderLayout());
      final Plot2D p2 = new Plot2D();
      jf.getContentPane().add(p2, BorderLayout.CENTER);
      jf.addWindowListener(new java.awt.event.WindowAdapter() {
	  public void windowClosing(java.awt.event.WindowEvent e) {
	    jf.dispose();
	    System.exit(0);
	  }
	});
      
      p2.addMouseListener(new MouseAdapter() {
	  public void mouseClicked(MouseEvent e) {
	    if ((e.getModifiers() & InputEvent.BUTTON1_MASK) ==
		InputEvent.BUTTON1_MASK) {
	      p2.searchPoints(e.getX(), e.getY(), false);
	    } else {
	      p2.searchPoints(e.getX(), e.getY(), true);
	    }
	  }
	});

      jf.setVisible(true);
      if (args.length >= 1) {
	for (int j = 0; j < args.length; j++) {
	  System.err.println(Messages.getInstance().getString("Plot2D_Main_Error_Text_Second") + args[j]);
	  java.io.Reader r = new java.io.BufferedReader(
			     new java.io.FileReader(args[j]));
	  Instances i = new Instances(r);
	  i.setClassIndex(i.numAttributes()-1);
	  PlotData2D pd1 = new PlotData2D(i);

	  if (j == 0) {
	    pd1.setPlotName(Messages.getInstance().getString("Plot2D_Main_Pd1_SetPlotName_Text_First"));
	    p2.setMasterPlot(pd1);
	    p2.setXindex(2);
	    p2.setYindex(3);
	    p2.setCindex(i.classIndex());
	  } else {
	    pd1.setPlotName(Messages.getInstance().getString("Plot2D_Main_Pd1_SetPlotName_Text_Second") + (j+1));
	    pd1.m_useCustomColour = true;
	    pd1.m_customColour = (j % 2 == 0) ? Color.red : Color.blue; 
	    p2.addPlot(pd1);
	  }
	}
      }
    } catch (Exception ex) {
      ex.printStackTrace();
      System.err.println(ex.getMessage());
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy