package uk.ac.leeds.ccg.widgets; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Point; import java.awt.Rectangle; import java.awt.event.MouseEvent; import java.awt.event.MouseMotionListener; import java.lang.Math; import java.util.Vector; import uk.ac.leeds.ccg.geotools.GeoData; import uk.ac.leeds.ccg.geotools.HighlightChangedEvent; import uk.ac.leeds.ccg.geotools.HighlightChangedListener; import uk.ac.leeds.ccg.geotools.HighlightManager; /** * This class creates a scatter plot based on data in a GeoData object * ******NOTE! In this class, geodata values < 0 are assumed to be * invalid. This may not be true for all Geodata that * will be plotted. Ensure the variable INVALID_VALUE is * changed accordingly * Changes to 1.1 over 1.0 by James Macgill
* Moved into widget package.
* As java 1.1 awt objects do not have getX and getY methods these have been removed. * As java 1.1 vector objects use elementAt and not get then these have been changed. * As java 1.1 vector objects use addElement and not add then these have been changed. * * @author Juliet Luiz * @version 1.1 */ public class ScatterPlot extends Component implements HighlightChangedListener, MouseMotionListener { //**********************CONSTANTS*********************************// // Represents invalid data values in the GeoData. (Values less than // this are invalid) private final int INVALID_VALUE = 0; // dimensions of oval (scatter plot point) private final int OVAL_RADIUS = 3; private final int OVAL_DIAMETER = OVAL_RADIUS * 2; // The max length of the axis - used to calculate the factor // by which to divide the data points private final int MAX_AXIS_LENGTH = 300; // added to axes and all points to offset the plot a bit from the edge of // the screen private final int OFFSET = 55; // added to x label so it is slightly below top of screen private final int X_LABEL_OFFSET = 10; // added to y label so it is slightly below bottom of y axis // TODO - rotate text!!!! private final int Y_LABEL_OFFSET = (OFFSET + 25); // The x and y coordinates where the plot description text should start private final int PLOT_DESCRIP_X = 10; private final int PLOT_DESCRIP_Y = MAX_AXIS_LENGTH + Y_LABEL_OFFSET + 30; // The number of markers desired on axis final int NUM_MARKERS = 5; // The size to repaint the ovals. Somehow 15 works well despite the fact that // the oval diameter is only 10 final int OVAL_REPAINT_SIZE = 15; //**********************END CONSTANTS*********************************// // Vector to hold set of points that make up scatter plot final Vector pointVector_ = new Vector(); // The graphics of this component private Graphics graphics_; // The GeoData that contains the info to plot. Must extract the desired // data private GeoData xData_; private GeoData yData_; // The highlight Manager used between the scatter plot and map private HighlightManager highlightManager_; //origin of the component private int xOrigin_; private int yOrigin_; // Column names from .dbf. To be used as labels for axes private String xLabel_; private String yLabel_; // The currently highlighted point private SPlotPoint currHilitePoint_; private SPlotPoint prevHilitePoint_ ; // Flag to indicate if previously hilited point should be repainted to // normal color private boolean resetColor_ = false; // The size of the Vector containint the scatterplot points private int xSize_; // The scaling factor used when plotting markers on axes private int xFactor_; private int yFactor_; // The max values in the GeoData, used to calculate the scaling factor private int maxX_; private int maxY_; /** * Default constructor */ public ScatterPlot() {} /** * Constructor with all params * * @param highlightManager - the highlight manager for this component * @param xGeoData - the GeoData object that holds all the data * from the .dbf to be plotted on the x axis * @param yGeoData - the GeoData object that holds all the data * from the .dbf to be plotted on the y axis * @param xLabel - the label for the x axis (Column name from .dbf) * @param yLabel - the label for the y axis (Column name from .dbf) */ public ScatterPlot(HighlightManager highlightManager, GeoData xGeoData, GeoData yGeoData, String xLabel, String yLabel) { xData_ = xGeoData; yData_ = yGeoData; highlightManager_ = highlightManager; xLabel_ = xLabel; yLabel_ = yLabel; highlightManager_.addHighlightChangedListener(this); // Set up the mouse motion listener addMouseMotionListener(this); // Get the size of the GeoData (assuming the size of the xGeoData // equals the size of the yGeoData xSize_ = xData_.getSize(); fillVector(); } /** * Fills the vector with scatterplot points * */ private void fillVector() { // The x and y coordinates of a point int xPoint; int yPoint; // The x and y coordinates of a point with the displacement of the plot // origin from the component origin taken into consideration int xPointOffset, yPointOffset; // The point to be stored in the vector SPlotPoint plotPoint; // Get the max of the data types to figure out how to scale plot maxX_ = (new Double(xData_.getMax())).intValue(); maxY_ = (new Double(yData_.getMax())).intValue(); // Want max axes to be max of 200. Need to calculate the scaling factor xFactor_ = maxX_/MAX_AXIS_LENGTH; yFactor_ = maxY_/MAX_AXIS_LENGTH; // Extract x and y values, generate SPlotPoints and store in vector for (int i = 0; i < xSize_; i++) { xPoint = (int)(xData_.getValue(i) / xFactor_); yPoint = (int)(yData_.getValue(i) / yFactor_); // The xy coordinates where to plot the point (after taking the // offset btn the plot origin and the component origin into account xPointOffset = xPoint+OFFSET; yPointOffset = yPoint+OFFSET; // Generate SPlotPoints and store in vector plotPoint = new SPlotPoint(xPointOffset, yPointOffset); // Set the id of the scatter plot point (corresponds to the row // number in the .dbf // Must add one to compensate for geodata starting at 1 and vector // index starting at 0 plotPoint.setId(i+1); pointVector_.addElement(plotPoint); } } /** * Paints the scatter plot on the component * * @param graphics - the graphics part of the ScatterPlot component */ public void paint (Graphics graphics) { graphics_ = graphics; SPlotPoint point; drawAxes(); // Plot the points, highlighting those who are set to be highlighted for (int i = 0; i 0) { // The -1 is there to compensate for vectors starting at index 0 thePoint = (SPlotPoint)pointVector_.elementAt(hiliteID -1); thePoint.setIsHilited(true); currHilitePoint_ = thePoint; // Get the x and y coordinates of the point x = (int)thePoint.x; y = (int)thePoint.y; // Only repaint the point if it has valid data (in this case >0) if ((x > INVALID_VALUE) || (y > INVALID_VALUE)) { repaint( ((int)(x) - (OVAL_RADIUS)), ((int)(y) - (OVAL_RADIUS)), OVAL_REPAINT_SIZE, OVAL_REPAINT_SIZE ); if (prevHilitePoint_ != null) { prevHilitePoint_.setIsHilited(false); repaint( ((int)prevHilitePoint_.x - (OVAL_RADIUS)), ((int)prevHilitePoint_.y - (OVAL_RADIUS)), OVAL_REPAINT_SIZE, OVAL_REPAINT_SIZE ); } } prevHilitePoint_ = currHilitePoint_; } // If cursor is over a state (and the corresponding plot point is // highlighted), and then the cursor leaves the map area and enters the // white area around it (with value -1 in this case), // we want the highlighted scatter plot point to return to its normal color. if (hiliteID < INVALID_VALUE) { // Unhighlight any highlighted scatter plot point when the cursor // leaves the map and enters the surrounding white area around it if (currHilitePoint_ != null) { currHilitePoint_.setIsHilited(false); repaint( ((int)currHilitePoint_.x - (OVAL_RADIUS)), ((int)currHilitePoint_.y - (OVAL_RADIUS)), OVAL_REPAINT_SIZE, OVAL_REPAINT_SIZE ); } } } } // EOC