[29] | 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 | /* |
---|
| 18 | * Plot2D.java |
---|
| 19 | * Copyright (C) 2000 University of Waikato, Hamilton, New Zealand |
---|
| 20 | * |
---|
| 21 | */ |
---|
| 22 | |
---|
| 23 | package weka.gui.visualize; |
---|
| 24 | |
---|
| 25 | import weka.core.FastVector; |
---|
| 26 | import weka.core.Instance; |
---|
| 27 | import weka.core.Instances; |
---|
| 28 | import weka.core.Utils; |
---|
| 29 | |
---|
| 30 | import java.awt.BorderLayout; |
---|
| 31 | import java.awt.Color; |
---|
| 32 | import java.awt.Font; |
---|
| 33 | import java.awt.FontMetrics; |
---|
| 34 | import java.awt.Graphics; |
---|
| 35 | import java.awt.event.InputEvent; |
---|
| 36 | import java.awt.event.MouseAdapter; |
---|
| 37 | import java.awt.event.MouseEvent; |
---|
| 38 | import java.awt.event.WindowAdapter; |
---|
| 39 | import java.awt.event.WindowEvent; |
---|
| 40 | import java.util.Random; |
---|
| 41 | import java.util.Vector; |
---|
| 42 | |
---|
| 43 | import javax.swing.JFrame; |
---|
| 44 | import javax.swing.JPanel; |
---|
| 45 | |
---|
| 46 | /** |
---|
| 47 | * This class plots datasets in two dimensions. It can also plot |
---|
| 48 | * classifier errors and clusterer predictions. |
---|
| 49 | * |
---|
| 50 | * @author Mark Hall (mhall@cs.waikato.ac.nz) |
---|
| 51 | * @version $Revision: 5987 $ |
---|
| 52 | */ |
---|
| 53 | public class Plot2D |
---|
| 54 | extends JPanel { |
---|
| 55 | |
---|
| 56 | /** for serialization */ |
---|
| 57 | private static final long serialVersionUID = -1673162410856660442L; |
---|
| 58 | |
---|
| 59 | /* constants for shape types */ |
---|
| 60 | public static final int MAX_SHAPES = 5; |
---|
| 61 | public static final int ERROR_SHAPE = 1000; |
---|
| 62 | public static final int MISSING_SHAPE = 2000; |
---|
| 63 | public static final int CONST_AUTOMATIC_SHAPE = -1; |
---|
| 64 | public static final int X_SHAPE = 0; |
---|
| 65 | public static final int PLUS_SHAPE = 1; |
---|
| 66 | public static final int DIAMOND_SHAPE = 2; |
---|
| 67 | public static final int TRIANGLEUP_SHAPE = 3; |
---|
| 68 | public static final int TRIANGLEDOWN_SHAPE = 4; |
---|
| 69 | public static final int DEFAULT_SHAPE_SIZE = 2; |
---|
| 70 | |
---|
| 71 | /** Default colour for the axis */ |
---|
| 72 | protected Color m_axisColour = Color.green; |
---|
| 73 | |
---|
| 74 | /** Default colour for the plot background */ |
---|
| 75 | protected Color m_backgroundColour = Color.black; |
---|
| 76 | |
---|
| 77 | /** The plots to display */ |
---|
| 78 | protected FastVector m_plots = new FastVector(); |
---|
| 79 | |
---|
| 80 | /** The master plot */ |
---|
| 81 | protected PlotData2D m_masterPlot = null; |
---|
| 82 | |
---|
| 83 | /** The name of the master plot */ |
---|
| 84 | protected String m_masterName = "master plot"; |
---|
| 85 | |
---|
| 86 | /** The instances to be plotted */ |
---|
| 87 | protected Instances m_plotInstances=null; |
---|
| 88 | |
---|
| 89 | /** An optional "compainion" of the panel. If specified, this |
---|
| 90 | class will get to do its thing with our graphics context |
---|
| 91 | before we do any drawing. Eg. the visualize panel may need |
---|
| 92 | to draw polygons etc. before we draw plot axis and data points */ |
---|
| 93 | protected Plot2DCompanion m_plotCompanion=null; |
---|
| 94 | |
---|
| 95 | /** the class for displaying instance info. */ |
---|
| 96 | protected Class m_InstanceInfoFrameClass = null; |
---|
| 97 | |
---|
| 98 | /** For popping up text info on data points */ |
---|
| 99 | protected JFrame m_InstanceInfo = null; |
---|
| 100 | |
---|
| 101 | /** The list of the colors used */ |
---|
| 102 | protected FastVector m_colorList; |
---|
| 103 | |
---|
| 104 | /** default colours for colouring discrete class */ |
---|
| 105 | protected Color [] m_DefaultColors = {Color.blue, |
---|
| 106 | Color.red, |
---|
| 107 | Color.green, |
---|
| 108 | Color.cyan, |
---|
| 109 | Color.pink, |
---|
| 110 | new Color(255, 0, 255), |
---|
| 111 | Color.orange, |
---|
| 112 | new Color(255, 0, 0), |
---|
| 113 | new Color(0, 255, 0), |
---|
| 114 | Color.white}; |
---|
| 115 | |
---|
| 116 | /** Indexes of the attributes to go on the x and y axis and the attribute |
---|
| 117 | to use for colouring and the current shape for drawing */ |
---|
| 118 | protected int m_xIndex=0; |
---|
| 119 | protected int m_yIndex=0; |
---|
| 120 | protected int m_cIndex=0; |
---|
| 121 | protected int m_sIndex=0; |
---|
| 122 | |
---|
| 123 | /** Holds the min and max values of the x, y and colouring attributes |
---|
| 124 | over all plots */ |
---|
| 125 | protected double m_maxX; |
---|
| 126 | protected double m_minX; |
---|
| 127 | protected double m_maxY; |
---|
| 128 | protected double m_minY; |
---|
| 129 | protected double m_maxC; |
---|
| 130 | protected double m_minC; |
---|
| 131 | |
---|
| 132 | /** Axis padding */ |
---|
| 133 | protected final int m_axisPad = 5; |
---|
| 134 | |
---|
| 135 | /** Tick size */ |
---|
| 136 | protected final int m_tickSize = 5; |
---|
| 137 | |
---|
| 138 | /**the offsets of the axes once label metrics are calculated */ |
---|
| 139 | protected int m_XaxisStart=0; |
---|
| 140 | protected int m_YaxisStart=0; |
---|
| 141 | protected int m_XaxisEnd=0; |
---|
| 142 | protected int m_YaxisEnd=0; |
---|
| 143 | |
---|
| 144 | /** if the user resizes the window, or the attributes selected for |
---|
| 145 | the attributes change, then the lookup table for points needs |
---|
| 146 | to be recalculated */ |
---|
| 147 | protected boolean m_plotResize = true; |
---|
| 148 | |
---|
| 149 | /** if the user changes attribute assigned to an axis */ |
---|
| 150 | protected boolean m_axisChanged = false; |
---|
| 151 | |
---|
| 152 | /** An array used to show if a point is hidden or not. |
---|
| 153 | * This is used for speeding up the drawing of the plot panel |
---|
| 154 | * although I am not sure how much performance this grants over |
---|
| 155 | * not having it. |
---|
| 156 | */ |
---|
| 157 | protected int[][] m_drawnPoints; |
---|
| 158 | |
---|
| 159 | /** Font for labels */ |
---|
| 160 | protected Font m_labelFont; |
---|
| 161 | protected FontMetrics m_labelMetrics=null; |
---|
| 162 | |
---|
| 163 | /** the level of jitter */ |
---|
| 164 | protected int m_JitterVal=0; |
---|
| 165 | |
---|
| 166 | /** random values for perterbing the data points */ |
---|
| 167 | protected Random m_JRand = new Random(0); |
---|
| 168 | |
---|
| 169 | /** lookup table for plotted points */ |
---|
| 170 | protected double [][] m_pointLookup=null; |
---|
| 171 | |
---|
| 172 | /** Constructor */ |
---|
| 173 | public Plot2D() { |
---|
| 174 | super(); |
---|
| 175 | setProperties(); |
---|
| 176 | this.setBackground(m_backgroundColour); |
---|
| 177 | |
---|
| 178 | m_drawnPoints = new int[this.getWidth()][this.getHeight()]; |
---|
| 179 | |
---|
| 180 | /** Set up some default colours */ |
---|
| 181 | m_colorList = new FastVector(10); |
---|
| 182 | for (int noa = m_colorList.size(); noa < 10; noa++) { |
---|
| 183 | Color pc = m_DefaultColors[noa % 10]; |
---|
| 184 | int ija = noa / 10; |
---|
| 185 | ija *= 2; |
---|
| 186 | for (int j=0;j<ija;j++) { |
---|
| 187 | pc = pc.darker(); |
---|
| 188 | } |
---|
| 189 | |
---|
| 190 | m_colorList.addElement(pc); |
---|
| 191 | } |
---|
| 192 | } |
---|
| 193 | |
---|
| 194 | /** |
---|
| 195 | * Set the properties for Plot2D |
---|
| 196 | */ |
---|
| 197 | private void setProperties() { |
---|
| 198 | if (VisualizeUtils.VISUALIZE_PROPERTIES != null) { |
---|
| 199 | String thisClass = this.getClass().getName(); |
---|
| 200 | String axisKey = thisClass+".axisColour"; |
---|
| 201 | String backgroundKey = thisClass+".backgroundColour"; |
---|
| 202 | |
---|
| 203 | String axisColour = VisualizeUtils.VISUALIZE_PROPERTIES. |
---|
| 204 | getProperty(axisKey); |
---|
| 205 | if (axisColour == null) { |
---|
| 206 | /* |
---|
| 207 | System.err.println("Warning: no configuration property found in " |
---|
| 208 | +VisualizeUtils.PROPERTY_FILE |
---|
| 209 | +" for "+axisKey);*/ |
---|
| 210 | } else { |
---|
| 211 | //System.err.println("Setting axis colour to: "+axisColour); |
---|
| 212 | m_axisColour = VisualizeUtils.processColour(axisColour, m_axisColour); |
---|
| 213 | } |
---|
| 214 | |
---|
| 215 | String backgroundColour = |
---|
| 216 | VisualizeUtils.VISUALIZE_PROPERTIES.getProperty(backgroundKey); |
---|
| 217 | if (backgroundColour == null) { |
---|
| 218 | /* |
---|
| 219 | System.err.println("Warning: no configuration property found in " |
---|
| 220 | +VisualizeUtils.PROPERTY_FILE |
---|
| 221 | +" for "+backgroundKey);*/ |
---|
| 222 | } else { |
---|
| 223 | //System.err.println("Setting background colour to: "+backgroundColour); |
---|
| 224 | m_backgroundColour = VisualizeUtils.processColour(backgroundColour, |
---|
| 225 | m_backgroundColour); |
---|
| 226 | } |
---|
| 227 | |
---|
| 228 | try { |
---|
| 229 | m_InstanceInfoFrameClass = Class.forName(VisualizeUtils.VISUALIZE_PROPERTIES.getProperty(thisClass + ".instanceInfoFrame", "weka.gui.visualize.InstanceInfoFrame")); |
---|
| 230 | } |
---|
| 231 | catch (Exception e) { |
---|
| 232 | e.printStackTrace(); |
---|
| 233 | m_InstanceInfoFrameClass = InstanceInfoFrame.class; |
---|
| 234 | } |
---|
| 235 | } |
---|
| 236 | } |
---|
| 237 | |
---|
| 238 | /** |
---|
| 239 | * This will check the values of the screen points passed and make sure |
---|
| 240 | * that they land on the screen |
---|
| 241 | * @param x1 The x coord. |
---|
| 242 | * @param y1 The y coord. |
---|
| 243 | */ |
---|
| 244 | private boolean checkPoints(double x1, double y1) { |
---|
| 245 | if (x1 < 0 || x1 > this.getSize().width || y1 < 0 |
---|
| 246 | || y1 > this.getSize().height) { |
---|
| 247 | return false; |
---|
| 248 | } |
---|
| 249 | return true; |
---|
| 250 | } |
---|
| 251 | |
---|
| 252 | /** |
---|
| 253 | * Set a companion class. This is a class that might want |
---|
| 254 | * to render something on the plot before we do our thing. Eg, |
---|
| 255 | * Malcolm's shape drawing stuff needs to happen before we plot |
---|
| 256 | * axis and points |
---|
| 257 | * @param p a companion class |
---|
| 258 | */ |
---|
| 259 | public void setPlotCompanion(Plot2DCompanion p) { |
---|
| 260 | m_plotCompanion = p; |
---|
| 261 | } |
---|
| 262 | |
---|
| 263 | /** |
---|
| 264 | * Set level of jitter and repaint the plot using the new jitter value |
---|
| 265 | * @param j the level of jitter |
---|
| 266 | */ |
---|
| 267 | public void setJitter(int j) { |
---|
| 268 | if (m_plotInstances.numAttributes() > 0 |
---|
| 269 | && m_plotInstances.numInstances() > 0) { |
---|
| 270 | if (j >= 0) { |
---|
| 271 | m_JitterVal = j; |
---|
| 272 | m_JRand = new Random(m_JitterVal); |
---|
| 273 | // if (m_pointLookup != null) { |
---|
| 274 | m_drawnPoints = new int[m_XaxisEnd - m_XaxisStart + 1] |
---|
| 275 | [m_YaxisEnd - m_YaxisStart + 1]; |
---|
| 276 | updatePturb(); |
---|
| 277 | // } |
---|
| 278 | this.repaint(); |
---|
| 279 | } |
---|
| 280 | } |
---|
| 281 | } |
---|
| 282 | |
---|
| 283 | /** |
---|
| 284 | * Set a list of colours to use when colouring points according |
---|
| 285 | * to class values or cluster numbers |
---|
| 286 | * @param cols the list of colours to use |
---|
| 287 | */ |
---|
| 288 | public void setColours (FastVector cols) { |
---|
| 289 | m_colorList = cols; |
---|
| 290 | } |
---|
| 291 | |
---|
| 292 | /** |
---|
| 293 | * Set the index of the attribute to go on the x axis |
---|
| 294 | * @param x the index of the attribute to use on the x axis |
---|
| 295 | */ |
---|
| 296 | public void setXindex(int x) { |
---|
| 297 | m_xIndex = x; |
---|
| 298 | for (int i=0;i<m_plots.size();i++) { |
---|
| 299 | ((PlotData2D)m_plots.elementAt(i)).setXindex(m_xIndex); |
---|
| 300 | } |
---|
| 301 | determineBounds(); |
---|
| 302 | if (m_JitterVal != 0) { |
---|
| 303 | updatePturb(); |
---|
| 304 | } |
---|
| 305 | m_axisChanged = true; |
---|
| 306 | this.repaint(); |
---|
| 307 | } |
---|
| 308 | |
---|
| 309 | /** |
---|
| 310 | * Set the index of the attribute to go on the y axis |
---|
| 311 | * @param y the index of the attribute to use on the y axis |
---|
| 312 | */ |
---|
| 313 | public void setYindex(int y) { |
---|
| 314 | m_yIndex = y; |
---|
| 315 | for (int i=0;i<m_plots.size();i++) { |
---|
| 316 | ((PlotData2D)m_plots.elementAt(i)).setYindex(m_yIndex); |
---|
| 317 | } |
---|
| 318 | determineBounds(); |
---|
| 319 | if (m_JitterVal != 0) { |
---|
| 320 | updatePturb(); |
---|
| 321 | } |
---|
| 322 | m_axisChanged = true; |
---|
| 323 | this.repaint(); |
---|
| 324 | } |
---|
| 325 | |
---|
| 326 | /** |
---|
| 327 | * Set the index of the attribute to use for colouring |
---|
| 328 | * @param c the index of the attribute to use for colouring |
---|
| 329 | */ |
---|
| 330 | public void setCindex(int c) { |
---|
| 331 | m_cIndex = c; |
---|
| 332 | for (int i=0;i<m_plots.size();i++) { |
---|
| 333 | ((PlotData2D)m_plots.elementAt(i)).setCindex(m_cIndex); |
---|
| 334 | } |
---|
| 335 | determineBounds(); |
---|
| 336 | m_axisChanged = true; |
---|
| 337 | this.repaint(); |
---|
| 338 | } |
---|
| 339 | |
---|
| 340 | /** |
---|
| 341 | * Return the list of plots |
---|
| 342 | * @return the list of plots |
---|
| 343 | */ |
---|
| 344 | public FastVector getPlots() { |
---|
| 345 | return m_plots; |
---|
| 346 | } |
---|
| 347 | |
---|
| 348 | /** |
---|
| 349 | * Get the master plot |
---|
| 350 | * @return the master plot |
---|
| 351 | */ |
---|
| 352 | public PlotData2D getMasterPlot() { |
---|
| 353 | return m_masterPlot; |
---|
| 354 | } |
---|
| 355 | |
---|
| 356 | /** |
---|
| 357 | * Return the current max value of the attribute plotted on the x axis |
---|
| 358 | * @return the max x value |
---|
| 359 | */ |
---|
| 360 | public double getMaxX() { |
---|
| 361 | return m_maxX; |
---|
| 362 | } |
---|
| 363 | |
---|
| 364 | /** |
---|
| 365 | * Return the current max value of the attribute plotted on the y axis |
---|
| 366 | * @return the max y value |
---|
| 367 | */ |
---|
| 368 | public double getMaxY() { |
---|
| 369 | return m_maxY; |
---|
| 370 | } |
---|
| 371 | |
---|
| 372 | /** |
---|
| 373 | * Return the current min value of the attribute plotted on the x axis |
---|
| 374 | * @return the min x value |
---|
| 375 | */ |
---|
| 376 | public double getMinX() { |
---|
| 377 | return m_minX; |
---|
| 378 | } |
---|
| 379 | |
---|
| 380 | /** |
---|
| 381 | * Return the current min value of the attribute plotted on the y axis |
---|
| 382 | * @return the min y value |
---|
| 383 | */ |
---|
| 384 | public double getMinY() { |
---|
| 385 | return m_minY; |
---|
| 386 | } |
---|
| 387 | |
---|
| 388 | /** |
---|
| 389 | * Return the current max value of the colouring attribute |
---|
| 390 | * @return the max colour value |
---|
| 391 | */ |
---|
| 392 | public double getMaxC() { |
---|
| 393 | return m_maxC; |
---|
| 394 | } |
---|
| 395 | |
---|
| 396 | /** |
---|
| 397 | * Return the current min value of the colouring attribute |
---|
| 398 | * @return the min colour value |
---|
| 399 | */ |
---|
| 400 | public double getMinC() { |
---|
| 401 | return m_minC; |
---|
| 402 | } |
---|
| 403 | |
---|
| 404 | /** |
---|
| 405 | * Sets the master plot from a set of instances |
---|
| 406 | * @param inst the instances |
---|
| 407 | * @exception Exception if instances could not be set |
---|
| 408 | */ |
---|
| 409 | public void setInstances(Instances inst) throws Exception { |
---|
| 410 | //System.err.println("Setting Instances"); |
---|
| 411 | PlotData2D tempPlot = new PlotData2D(inst); |
---|
| 412 | tempPlot.setPlotName("master plot"); |
---|
| 413 | setMasterPlot(tempPlot); |
---|
| 414 | } |
---|
| 415 | |
---|
| 416 | /** |
---|
| 417 | * Set the master plot. |
---|
| 418 | * @param master the plot to make the master plot |
---|
| 419 | * @exception Exception if the plot could not be set. |
---|
| 420 | */ |
---|
| 421 | public void setMasterPlot(PlotData2D master) throws Exception { |
---|
| 422 | if (master.m_plotInstances == null) { |
---|
| 423 | throw new Exception("No instances in plot data!"); |
---|
| 424 | } |
---|
| 425 | removeAllPlots(); |
---|
| 426 | m_masterPlot = master; |
---|
| 427 | m_plots.addElement(m_masterPlot); |
---|
| 428 | m_plotInstances = m_masterPlot.m_plotInstances; |
---|
| 429 | |
---|
| 430 | m_xIndex=0; |
---|
| 431 | m_yIndex=0; |
---|
| 432 | m_cIndex=0; |
---|
| 433 | |
---|
| 434 | determineBounds(); |
---|
| 435 | } |
---|
| 436 | |
---|
| 437 | /** |
---|
| 438 | * Clears all plots |
---|
| 439 | */ |
---|
| 440 | public void removeAllPlots() { |
---|
| 441 | m_masterPlot = null; |
---|
| 442 | m_plotInstances = null; |
---|
| 443 | m_plots = new FastVector(); |
---|
| 444 | m_xIndex = 0; m_yIndex = 0; m_cIndex = 0; |
---|
| 445 | } |
---|
| 446 | |
---|
| 447 | /** |
---|
| 448 | * Add a plot to the list of plots to display |
---|
| 449 | * @param newPlot the new plot to add |
---|
| 450 | * @exception Exception if the plot could not be added |
---|
| 451 | */ |
---|
| 452 | public void addPlot(PlotData2D newPlot) throws Exception { |
---|
| 453 | if (newPlot.m_plotInstances == null) { |
---|
| 454 | throw new Exception("No instances in plot data!"); |
---|
| 455 | } |
---|
| 456 | |
---|
| 457 | if (m_masterPlot != null) { |
---|
| 458 | if (m_masterPlot.m_plotInstances. |
---|
| 459 | equalHeaders(newPlot.m_plotInstances) == false) { |
---|
| 460 | throw new Exception("Plot2D :Plot data's instances are incompatable " |
---|
| 461 | +" with master plot"); |
---|
| 462 | } |
---|
| 463 | } else { |
---|
| 464 | m_masterPlot = newPlot; |
---|
| 465 | m_plotInstances = m_masterPlot.m_plotInstances; |
---|
| 466 | } |
---|
| 467 | m_plots.addElement(newPlot); |
---|
| 468 | setXindex(m_xIndex); |
---|
| 469 | setYindex(m_yIndex); |
---|
| 470 | setCindex(m_cIndex); |
---|
| 471 | } |
---|
| 472 | |
---|
| 473 | /** |
---|
| 474 | * Set up fonts and font metrics |
---|
| 475 | * @param gx the graphics context |
---|
| 476 | */ |
---|
| 477 | private void setFonts(Graphics gx) { |
---|
| 478 | if (m_labelMetrics == null) { |
---|
| 479 | m_labelFont = new Font("Monospaced", Font.PLAIN, 12); |
---|
| 480 | m_labelMetrics = gx.getFontMetrics(m_labelFont); |
---|
| 481 | } |
---|
| 482 | gx.setFont(m_labelFont); |
---|
| 483 | } |
---|
| 484 | |
---|
| 485 | /** |
---|
| 486 | * Pops up a window displaying attribute information on any instances |
---|
| 487 | * at a point+-plotting_point_size (in panel coordinates) |
---|
| 488 | * |
---|
| 489 | * @param x the x value of the clicked point |
---|
| 490 | * @param y the y value of the clicked point |
---|
| 491 | * @param newFrame true if instance info is to be displayed in a |
---|
| 492 | * new frame. |
---|
| 493 | */ |
---|
| 494 | public void searchPoints(int x, int y, final boolean newFrame) { |
---|
| 495 | if (m_masterPlot.m_plotInstances != null) { |
---|
| 496 | int longest=0; |
---|
| 497 | for (int j=0;j<m_masterPlot.m_plotInstances.numAttributes();j++) { |
---|
| 498 | if (m_masterPlot.m_plotInstances.attribute(j).name().length() > |
---|
| 499 | longest) { |
---|
| 500 | longest = m_masterPlot.m_plotInstances.attribute(j).name().length(); |
---|
| 501 | } |
---|
| 502 | } |
---|
| 503 | |
---|
| 504 | StringBuffer insts = new StringBuffer(); |
---|
| 505 | Vector<Instances> data = new Vector<Instances>(); |
---|
| 506 | for (int jj=0;jj<m_plots.size();jj++) { |
---|
| 507 | PlotData2D temp_plot = (PlotData2D)(m_plots.elementAt(jj)); |
---|
| 508 | data.add(new Instances(temp_plot.m_plotInstances, 0)); |
---|
| 509 | |
---|
| 510 | for (int i=0;i<temp_plot.m_plotInstances.numInstances();i++) { |
---|
| 511 | if (temp_plot.m_pointLookup[i][0] != Double.NEGATIVE_INFINITY) { |
---|
| 512 | double px = temp_plot.m_pointLookup[i][0] + |
---|
| 513 | temp_plot.m_pointLookup[i][2]; |
---|
| 514 | double py = temp_plot.m_pointLookup[i][1] + |
---|
| 515 | temp_plot.m_pointLookup[i][3]; |
---|
| 516 | // double size = temp_plot.m_pointLookup[i][2]; |
---|
| 517 | double size = temp_plot.m_shapeSize[i]; |
---|
| 518 | if ((x >= px-size) && (x <= px+size) && |
---|
| 519 | (y >= py-size) && (y <= py+size)) { |
---|
| 520 | { |
---|
| 521 | data.get(jj).add((Instance)temp_plot.m_plotInstances.instance(i).copy()); |
---|
| 522 | insts.append("\nPlot : "+temp_plot.m_plotName |
---|
| 523 | + "\nInstance: " + (i + 1 ) + "\n"); |
---|
| 524 | for (int j=0;j<temp_plot.m_plotInstances.numAttributes();j++) { |
---|
| 525 | for (int k = 0;k < |
---|
| 526 | (longest-temp_plot.m_plotInstances. |
---|
| 527 | attribute(j).name().length()); k++) { |
---|
| 528 | insts.append(" "); |
---|
| 529 | } |
---|
| 530 | insts.append(temp_plot.m_plotInstances.attribute(j).name()); |
---|
| 531 | insts.append(" : "); |
---|
| 532 | |
---|
| 533 | if (temp_plot.m_plotInstances.instance(i).isMissing(j)) { |
---|
| 534 | insts.append("Missing"); |
---|
| 535 | } else if (temp_plot.m_plotInstances.attribute(j). |
---|
| 536 | isNominal()) { |
---|
| 537 | insts.append(temp_plot.m_plotInstances. |
---|
| 538 | attribute(j). |
---|
| 539 | value((int)temp_plot.m_plotInstances. |
---|
| 540 | instance(i).value(j))); |
---|
| 541 | } else { |
---|
| 542 | insts.append(temp_plot.m_plotInstances. |
---|
| 543 | instance(i).value(j)); |
---|
| 544 | } |
---|
| 545 | insts.append("\n"); |
---|
| 546 | } |
---|
| 547 | } |
---|
| 548 | } |
---|
| 549 | } |
---|
| 550 | } |
---|
| 551 | } |
---|
| 552 | // remove datasets that contain no instances |
---|
| 553 | int i = 0; |
---|
| 554 | while (data.size() > i) { |
---|
| 555 | if (data.get(i).numInstances() == 0) |
---|
| 556 | data.remove(i); |
---|
| 557 | else |
---|
| 558 | i++; |
---|
| 559 | } |
---|
| 560 | |
---|
| 561 | if (insts.length() > 0) { |
---|
| 562 | // Pop up a new frame |
---|
| 563 | if (newFrame || m_InstanceInfo == null) { |
---|
| 564 | try { |
---|
| 565 | final JFrame jf = (JFrame) m_InstanceInfoFrameClass.newInstance(); |
---|
| 566 | ((InstanceInfo) jf).setInfoText(insts.toString()); |
---|
| 567 | ((InstanceInfo) jf).setInfoData(data); |
---|
| 568 | final JFrame testf = m_InstanceInfo; |
---|
| 569 | jf.addWindowListener(new WindowAdapter() { |
---|
| 570 | public void windowClosing(WindowEvent e) { |
---|
| 571 | if (!newFrame || testf == null) { |
---|
| 572 | m_InstanceInfo = null; |
---|
| 573 | } |
---|
| 574 | jf.dispose(); |
---|
| 575 | } |
---|
| 576 | }); |
---|
| 577 | jf.setVisible(true); |
---|
| 578 | if (m_InstanceInfo == null) |
---|
| 579 | m_InstanceInfo = jf; |
---|
| 580 | } |
---|
| 581 | catch (Exception e) { |
---|
| 582 | e.printStackTrace(); |
---|
| 583 | } |
---|
| 584 | } |
---|
| 585 | else { |
---|
| 586 | // Overwrite info in existing frame |
---|
| 587 | ((InstanceInfo) m_InstanceInfo).setInfoText(insts.toString()); |
---|
| 588 | ((InstanceInfo) m_InstanceInfo).setInfoData(data); |
---|
| 589 | } |
---|
| 590 | } |
---|
| 591 | } |
---|
| 592 | } |
---|
| 593 | |
---|
| 594 | |
---|
| 595 | /** |
---|
| 596 | * Determine the min and max values for axis and colouring attributes |
---|
| 597 | */ |
---|
| 598 | public void determineBounds() { |
---|
| 599 | double value,min,max; |
---|
| 600 | |
---|
| 601 | // find maximums minimums over all plots |
---|
| 602 | m_minX = ((PlotData2D)m_plots.elementAt(0)).m_minX; |
---|
| 603 | m_maxX = ((PlotData2D)m_plots.elementAt(0)).m_maxX; |
---|
| 604 | m_minY = ((PlotData2D)m_plots.elementAt(0)).m_minY; |
---|
| 605 | m_maxY = ((PlotData2D)m_plots.elementAt(0)).m_maxY; |
---|
| 606 | m_minC = ((PlotData2D)m_plots.elementAt(0)).m_minC; |
---|
| 607 | m_maxC = ((PlotData2D)m_plots.elementAt(0)).m_maxC; |
---|
| 608 | for (int i=1;i<m_plots.size();i++) { |
---|
| 609 | value = ((PlotData2D)m_plots.elementAt(i)).m_minX; |
---|
| 610 | if (value < m_minX) { |
---|
| 611 | m_minX = value; |
---|
| 612 | } |
---|
| 613 | value = ((PlotData2D)m_plots.elementAt(i)).m_maxX; |
---|
| 614 | if (value > m_maxX) { |
---|
| 615 | m_maxX = value; |
---|
| 616 | } |
---|
| 617 | value = ((PlotData2D)m_plots.elementAt(i)).m_minY; |
---|
| 618 | if (value < m_minY) { |
---|
| 619 | m_minY= value; |
---|
| 620 | } |
---|
| 621 | value = ((PlotData2D)m_plots.elementAt(i)).m_maxY; |
---|
| 622 | if (value > m_maxY) { |
---|
| 623 | m_maxY = value; |
---|
| 624 | } |
---|
| 625 | value = ((PlotData2D)m_plots.elementAt(i)).m_minC; |
---|
| 626 | if (value < m_minC) { |
---|
| 627 | m_minC = value; |
---|
| 628 | } |
---|
| 629 | value = ((PlotData2D)m_plots.elementAt(i)).m_maxC; |
---|
| 630 | if (value > m_maxC) { |
---|
| 631 | m_maxC = value; |
---|
| 632 | } |
---|
| 633 | } |
---|
| 634 | |
---|
| 635 | fillLookup(); |
---|
| 636 | this.repaint(); |
---|
| 637 | } |
---|
| 638 | |
---|
| 639 | |
---|
| 640 | //to convert screen coords to attrib values |
---|
| 641 | // note that I use a double to avoid accuracy |
---|
| 642 | //headaches with ints |
---|
| 643 | /** |
---|
| 644 | * convert a Panel x coordinate to a raw x value. |
---|
| 645 | * @param scx The Panel x coordinate |
---|
| 646 | * @return A raw x value. |
---|
| 647 | */ |
---|
| 648 | public double convertToAttribX(double scx) { |
---|
| 649 | double temp = m_XaxisEnd - m_XaxisStart; |
---|
| 650 | double temp2 = ((scx - m_XaxisStart) * (m_maxX - m_minX)) / temp; |
---|
| 651 | |
---|
| 652 | temp2 = temp2 + m_minX; |
---|
| 653 | |
---|
| 654 | return temp2; |
---|
| 655 | } |
---|
| 656 | |
---|
| 657 | /** |
---|
| 658 | * convert a Panel y coordinate to a raw y value. |
---|
| 659 | * @param scy The Panel y coordinate |
---|
| 660 | * @return A raw y value. |
---|
| 661 | */ |
---|
| 662 | public double convertToAttribY(double scy) { |
---|
| 663 | double temp = m_YaxisEnd - m_YaxisStart; |
---|
| 664 | double temp2 = ((scy - m_YaxisEnd) * (m_maxY - m_minY)) / temp; |
---|
| 665 | |
---|
| 666 | temp2 = -(temp2 - m_minY); |
---|
| 667 | |
---|
| 668 | return temp2; |
---|
| 669 | } |
---|
| 670 | ////// |
---|
| 671 | |
---|
| 672 | /** |
---|
| 673 | * returns a value by which an x value can be peturbed. Makes sure |
---|
| 674 | * that the x value+pturb stays within the plot bounds |
---|
| 675 | * @param xvalP the x coordinate to be peturbed |
---|
| 676 | * @param xj a random number to use in calculating a peturb value |
---|
| 677 | * @return a peturb value |
---|
| 678 | */ |
---|
| 679 | int pturbX(double xvalP, double xj) { |
---|
| 680 | int xpturb = 0; |
---|
| 681 | if (m_JitterVal > 0) { |
---|
| 682 | xpturb = (int)((double)m_JitterVal * (xj / 2.0)); |
---|
| 683 | if (((xvalP + xpturb) < m_XaxisStart) || |
---|
| 684 | ((xvalP + xpturb) > m_XaxisEnd)) { |
---|
| 685 | xpturb *= -1; |
---|
| 686 | } |
---|
| 687 | } |
---|
| 688 | return xpturb; |
---|
| 689 | } |
---|
| 690 | |
---|
| 691 | /** |
---|
| 692 | * Convert an raw x value to Panel x coordinate. |
---|
| 693 | * @param xval the raw x value |
---|
| 694 | * @return an x value for plotting in the panel. |
---|
| 695 | */ |
---|
| 696 | public double convertToPanelX(double xval) { |
---|
| 697 | double temp = (xval - m_minX)/(m_maxX - m_minX); |
---|
| 698 | double temp2 = temp * (m_XaxisEnd - m_XaxisStart); |
---|
| 699 | |
---|
| 700 | temp2 = temp2 + m_XaxisStart; |
---|
| 701 | |
---|
| 702 | return temp2; |
---|
| 703 | } |
---|
| 704 | |
---|
| 705 | /** |
---|
| 706 | * returns a value by which a y value can be peturbed. Makes sure |
---|
| 707 | * that the y value+pturb stays within the plot bounds |
---|
| 708 | * @param yvalP the y coordinate to be peturbed |
---|
| 709 | * @param yj a random number to use in calculating a peturb value |
---|
| 710 | * @return a peturb value |
---|
| 711 | */ |
---|
| 712 | int pturbY(double yvalP, double yj) { |
---|
| 713 | int ypturb = 0; |
---|
| 714 | if (m_JitterVal > 0) { |
---|
| 715 | ypturb = (int)((double)m_JitterVal * (yj / 2.0)); |
---|
| 716 | if (((yvalP + ypturb) < m_YaxisStart) || |
---|
| 717 | ((yvalP + ypturb) > m_YaxisEnd)) { |
---|
| 718 | ypturb *= -1; |
---|
| 719 | } |
---|
| 720 | } |
---|
| 721 | return ypturb; |
---|
| 722 | } |
---|
| 723 | |
---|
| 724 | /** |
---|
| 725 | * Convert an raw y value to Panel y coordinate. |
---|
| 726 | * @param yval the raw y value |
---|
| 727 | * @return an y value for plotting in the panel. |
---|
| 728 | */ |
---|
| 729 | public double convertToPanelY(double yval) { |
---|
| 730 | double temp = (yval - m_minY)/(m_maxY - m_minY); |
---|
| 731 | double temp2 = temp * (m_YaxisEnd - m_YaxisStart); |
---|
| 732 | |
---|
| 733 | temp2 = m_YaxisEnd - temp2; |
---|
| 734 | |
---|
| 735 | return temp2; |
---|
| 736 | } |
---|
| 737 | |
---|
| 738 | /** |
---|
| 739 | * Draws an X. |
---|
| 740 | * @param gx the graphics context |
---|
| 741 | * @param x the x coord |
---|
| 742 | * @param y the y coord |
---|
| 743 | * @param size the size of the shape |
---|
| 744 | */ |
---|
| 745 | private static void drawX(Graphics gx, double x, double y, int size) { |
---|
| 746 | gx.drawLine((int)(x-size),(int)(y-size), |
---|
| 747 | (int)(x+size),(int)(y+size)); |
---|
| 748 | |
---|
| 749 | gx.drawLine((int)(x+size),(int)(y-size), |
---|
| 750 | (int)(x-size),(int)(y+size)); |
---|
| 751 | } |
---|
| 752 | |
---|
| 753 | /** |
---|
| 754 | * Draws a plus. |
---|
| 755 | * @param gx the graphics context |
---|
| 756 | * @param x the x coord |
---|
| 757 | * @param y the y coord |
---|
| 758 | * @param size the size of the shape |
---|
| 759 | */ |
---|
| 760 | private static void drawPlus(Graphics gx, double x, double y, int size) { |
---|
| 761 | gx.drawLine((int)(x-size),(int)(y), |
---|
| 762 | (int)(x+size),(int)(y)); |
---|
| 763 | |
---|
| 764 | gx.drawLine((int)(x),(int)(y-size), |
---|
| 765 | (int)(x),(int)(y+size)); |
---|
| 766 | } |
---|
| 767 | |
---|
| 768 | /** |
---|
| 769 | * Draws a diamond. |
---|
| 770 | * @param gx the graphics context |
---|
| 771 | * @param x the x coord |
---|
| 772 | * @param y the y coord |
---|
| 773 | * @param size the size of the shape |
---|
| 774 | */ |
---|
| 775 | private static void drawDiamond(Graphics gx, double x, double y, int size) { |
---|
| 776 | gx.drawLine((int)(x-size),(int)(y), |
---|
| 777 | (int)(x),(int)(y-size)); |
---|
| 778 | |
---|
| 779 | gx.drawLine((int)(x),(int)(y-size), |
---|
| 780 | (int)(x+size),(int)(y)); |
---|
| 781 | |
---|
| 782 | gx.drawLine((int)(x+size),(int)(y), |
---|
| 783 | (int)(x),(int)(y+size)); |
---|
| 784 | |
---|
| 785 | gx.drawLine((int)(x),(int)(y+size), |
---|
| 786 | (int)(x-size),(int)(y)); |
---|
| 787 | } |
---|
| 788 | |
---|
| 789 | /** |
---|
| 790 | * Draws an triangle (point at top). |
---|
| 791 | * @param gx the graphics context |
---|
| 792 | * @param x the x coord |
---|
| 793 | * @param y the y coord |
---|
| 794 | * @param size the size of the shape |
---|
| 795 | */ |
---|
| 796 | private static void drawTriangleUp(Graphics gx, double x, |
---|
| 797 | double y, int size) { |
---|
| 798 | gx.drawLine((int)(x),(int)(y-size), |
---|
| 799 | (int)(x-size),(int)(y+size)); |
---|
| 800 | |
---|
| 801 | gx.drawLine((int)(x-size),(int)(y+size), |
---|
| 802 | (int)(x+size),(int)(y+size)); |
---|
| 803 | |
---|
| 804 | gx.drawLine((int)(x+size),(int)(y+size), |
---|
| 805 | (int)(x),(int)(y-size)); |
---|
| 806 | |
---|
| 807 | } |
---|
| 808 | |
---|
| 809 | /** |
---|
| 810 | * Draws an triangle (point at bottom). |
---|
| 811 | * @param gx the graphics context |
---|
| 812 | * @param x the x coord |
---|
| 813 | * @param y the y coord |
---|
| 814 | * @param size the size of the shape |
---|
| 815 | */ |
---|
| 816 | private static void drawTriangleDown(Graphics gx, double x, |
---|
| 817 | double y, int size) { |
---|
| 818 | gx.drawLine((int)(x),(int)(y+size), |
---|
| 819 | (int)(x-size),(int)(y-size)); |
---|
| 820 | |
---|
| 821 | gx.drawLine((int)(x-size),(int)(y-size), |
---|
| 822 | (int)(x+size),(int)(y-size)); |
---|
| 823 | |
---|
| 824 | gx.drawLine((int)(x+size),(int)(y-size), |
---|
| 825 | (int)(x),(int)(y+size)); |
---|
| 826 | |
---|
| 827 | } |
---|
| 828 | |
---|
| 829 | /** |
---|
| 830 | * Draws a data point at a given set of panel coordinates at a given |
---|
| 831 | * size and connects a line to the previous point. |
---|
| 832 | * @param x the x coord |
---|
| 833 | * @param y the y coord |
---|
| 834 | * @param xprev the x coord of the previous point |
---|
| 835 | * @param yprev the y coord of the previous point |
---|
| 836 | * @param size the size of the point |
---|
| 837 | * @param shape the shape of the data point (square is reserved for nominal |
---|
| 838 | * error data points). Shapes: 0=x, 1=plus, 2=diamond, 3=triangle(up), |
---|
| 839 | * 4 = triangle (down). |
---|
| 840 | * @param gx the graphics context |
---|
| 841 | */ |
---|
| 842 | protected static void drawDataPoint(double x, |
---|
| 843 | double y, |
---|
| 844 | double xprev, |
---|
| 845 | double yprev, |
---|
| 846 | int size, |
---|
| 847 | int shape, |
---|
| 848 | Graphics gx) { |
---|
| 849 | |
---|
| 850 | drawDataPoint(x,y,size,shape,gx); |
---|
| 851 | |
---|
| 852 | // connect a line to the previous point |
---|
| 853 | gx.drawLine((int)x, (int)y, (int)xprev, (int)yprev); |
---|
| 854 | } |
---|
| 855 | |
---|
| 856 | /** |
---|
| 857 | * Draws a data point at a given set of panel coordinates at a given |
---|
| 858 | * size. |
---|
| 859 | * @param x the x coord |
---|
| 860 | * @param y the y coord |
---|
| 861 | * @param size the size of the point |
---|
| 862 | * @param shape the shape of the data point (square is reserved for nominal |
---|
| 863 | * error data points). Shapes: 0=x, 1=plus, 2=diamond, 3=triangle(up), |
---|
| 864 | * 4 = triangle (down). |
---|
| 865 | * @param gx the graphics context |
---|
| 866 | */ |
---|
| 867 | protected static void drawDataPoint(double x, |
---|
| 868 | double y, |
---|
| 869 | int size, |
---|
| 870 | int shape, |
---|
| 871 | Graphics gx) { |
---|
| 872 | |
---|
| 873 | Font lf = new Font("Monospaced", Font.PLAIN, 12); |
---|
| 874 | FontMetrics fm = gx.getFontMetrics(lf); |
---|
| 875 | |
---|
| 876 | if (size == 0) { |
---|
| 877 | size = 1; |
---|
| 878 | } |
---|
| 879 | |
---|
| 880 | if (shape != ERROR_SHAPE && shape != MISSING_SHAPE) { |
---|
| 881 | shape = shape % 5; |
---|
| 882 | } |
---|
| 883 | |
---|
| 884 | switch (shape) { |
---|
| 885 | case X_SHAPE: |
---|
| 886 | drawX(gx, x, y, size); |
---|
| 887 | break; |
---|
| 888 | case PLUS_SHAPE: |
---|
| 889 | drawPlus(gx, x, y, size); |
---|
| 890 | break; |
---|
| 891 | case DIAMOND_SHAPE: |
---|
| 892 | drawDiamond(gx, x, y, size); |
---|
| 893 | break; |
---|
| 894 | case TRIANGLEUP_SHAPE: |
---|
| 895 | drawTriangleUp(gx, x, y, size); |
---|
| 896 | break; |
---|
| 897 | case TRIANGLEDOWN_SHAPE: |
---|
| 898 | drawTriangleDown(gx, x, y, size); |
---|
| 899 | break; |
---|
| 900 | case ERROR_SHAPE: // draws the nominal error shape |
---|
| 901 | gx.drawRect((int)(x-size),(int)(y-size),(size*2),(size*2)); |
---|
| 902 | break; |
---|
| 903 | case MISSING_SHAPE: |
---|
| 904 | int hf = fm.getAscent(); |
---|
| 905 | int width = fm.stringWidth("M"); |
---|
| 906 | gx.drawString("M",(int)(x-(width / 2)), (int)(y+(hf / 2))); |
---|
| 907 | break; |
---|
| 908 | } |
---|
| 909 | } |
---|
| 910 | |
---|
| 911 | /** |
---|
| 912 | * Updates the perturbed values for the plots when the jitter value is |
---|
| 913 | * changed |
---|
| 914 | */ |
---|
| 915 | private void updatePturb() { |
---|
| 916 | double xj=0; |
---|
| 917 | double yj=0; |
---|
| 918 | for (int j=0;j<m_plots.size();j++) { |
---|
| 919 | PlotData2D temp_plot = (PlotData2D)(m_plots.elementAt(j)); |
---|
| 920 | for (int i=0;i<temp_plot.m_plotInstances.numInstances();i++) { |
---|
| 921 | if (temp_plot.m_plotInstances.instance(i).isMissing(m_xIndex) || |
---|
| 922 | temp_plot.m_plotInstances.instance(i).isMissing(m_yIndex)) { |
---|
| 923 | } else { |
---|
| 924 | if (m_JitterVal > 0) { |
---|
| 925 | xj = m_JRand.nextGaussian(); |
---|
| 926 | yj = m_JRand.nextGaussian(); |
---|
| 927 | } |
---|
| 928 | temp_plot.m_pointLookup[i][2] = |
---|
| 929 | pturbX(temp_plot.m_pointLookup[i][0],xj); |
---|
| 930 | temp_plot.m_pointLookup[i][3] = |
---|
| 931 | pturbY(temp_plot.m_pointLookup[i][1],yj); |
---|
| 932 | } |
---|
| 933 | } |
---|
| 934 | } |
---|
| 935 | } |
---|
| 936 | |
---|
| 937 | /** |
---|
| 938 | * Fills the lookup caches for the plots. Also calculates errors for |
---|
| 939 | * numeric predictions (if any) in plots |
---|
| 940 | */ |
---|
| 941 | private void fillLookup() { |
---|
| 942 | |
---|
| 943 | for (int j=0;j<m_plots.size();j++) { |
---|
| 944 | PlotData2D temp_plot = (PlotData2D)(m_plots.elementAt(j)); |
---|
| 945 | |
---|
| 946 | if (temp_plot.m_plotInstances.numInstances() > 0 && |
---|
| 947 | temp_plot.m_plotInstances.numAttributes() > 0) { |
---|
| 948 | for (int i=0;i<temp_plot.m_plotInstances.numInstances();i++) { |
---|
| 949 | if (temp_plot.m_plotInstances.instance(i).isMissing(m_xIndex) || |
---|
| 950 | temp_plot.m_plotInstances.instance(i).isMissing(m_yIndex)) { |
---|
| 951 | temp_plot.m_pointLookup[i][0] = Double.NEGATIVE_INFINITY; |
---|
| 952 | temp_plot.m_pointLookup[i][1] = Double.NEGATIVE_INFINITY; |
---|
| 953 | } else { |
---|
| 954 | double x = convertToPanelX(temp_plot.m_plotInstances. |
---|
| 955 | instance(i).value(m_xIndex)); |
---|
| 956 | double y = convertToPanelY(temp_plot.m_plotInstances. |
---|
| 957 | instance(i).value(m_yIndex)); |
---|
| 958 | temp_plot.m_pointLookup[i][0] = x; |
---|
| 959 | temp_plot.m_pointLookup[i][1] = y; |
---|
| 960 | } |
---|
| 961 | } |
---|
| 962 | } |
---|
| 963 | } |
---|
| 964 | } |
---|
| 965 | |
---|
| 966 | /** |
---|
| 967 | * Draws the data points and predictions (if provided). |
---|
| 968 | * @param gx the graphics context |
---|
| 969 | */ |
---|
| 970 | private void paintData(Graphics gx) { |
---|
| 971 | |
---|
| 972 | for (int j=0;j<m_plots.size();j++) { |
---|
| 973 | PlotData2D temp_plot = (PlotData2D)(m_plots.elementAt(j)); |
---|
| 974 | |
---|
| 975 | for (int i=0;i<temp_plot.m_plotInstances.numInstances();i++) { |
---|
| 976 | if (temp_plot.m_plotInstances.instance(i).isMissing(m_xIndex) || |
---|
| 977 | temp_plot.m_plotInstances.instance(i).isMissing(m_yIndex)) { |
---|
| 978 | } else { |
---|
| 979 | double x = (temp_plot.m_pointLookup[i][0] + |
---|
| 980 | temp_plot.m_pointLookup[i][2]); |
---|
| 981 | double y = (temp_plot.m_pointLookup[i][1] + |
---|
| 982 | temp_plot.m_pointLookup[i][3]); |
---|
| 983 | |
---|
| 984 | double prevx = 0; |
---|
| 985 | double prevy = 0; |
---|
| 986 | if (i > 0) { |
---|
| 987 | prevx = (temp_plot.m_pointLookup[i - 1][0] + |
---|
| 988 | temp_plot.m_pointLookup[i - 1][2]); |
---|
| 989 | prevy = (temp_plot.m_pointLookup[i - 1][1] + |
---|
| 990 | temp_plot.m_pointLookup[i - 1][3]); |
---|
| 991 | } |
---|
| 992 | |
---|
| 993 | int x_range = (int)x - m_XaxisStart; |
---|
| 994 | int y_range = (int)y - m_YaxisStart; |
---|
| 995 | |
---|
| 996 | if (x_range >= 0 && y_range >= 0) { |
---|
| 997 | if (m_drawnPoints[x_range][y_range] == i |
---|
| 998 | || m_drawnPoints[x_range][y_range] == 0 |
---|
| 999 | || temp_plot.m_shapeSize[i] == temp_plot.m_alwaysDisplayPointsOfThisSize |
---|
| 1000 | || temp_plot.m_displayAllPoints == true) { |
---|
| 1001 | m_drawnPoints[x_range][y_range] = i; |
---|
| 1002 | if (temp_plot.m_plotInstances.attribute(m_cIndex).isNominal()) { |
---|
| 1003 | if (temp_plot.m_plotInstances.attribute(m_cIndex).numValues() > |
---|
| 1004 | m_colorList.size() && |
---|
| 1005 | !temp_plot.m_useCustomColour) { |
---|
| 1006 | extendColourMap(temp_plot.m_plotInstances. |
---|
| 1007 | attribute(m_cIndex).numValues()); |
---|
| 1008 | } |
---|
| 1009 | |
---|
| 1010 | Color ci; |
---|
| 1011 | if (temp_plot.m_plotInstances.instance(i). |
---|
| 1012 | isMissing(m_cIndex)) { |
---|
| 1013 | ci = Color.gray; |
---|
| 1014 | } else { |
---|
| 1015 | int ind = (int)temp_plot.m_plotInstances.instance(i). |
---|
| 1016 | value(m_cIndex); |
---|
| 1017 | ci = (Color)m_colorList.elementAt(ind); |
---|
| 1018 | } |
---|
| 1019 | |
---|
| 1020 | if (!temp_plot.m_useCustomColour) { |
---|
| 1021 | gx.setColor(ci); |
---|
| 1022 | } else { |
---|
| 1023 | gx.setColor(temp_plot.m_customColour); |
---|
| 1024 | } |
---|
| 1025 | |
---|
| 1026 | if (temp_plot.m_plotInstances.instance(i). |
---|
| 1027 | isMissing(m_cIndex)) { |
---|
| 1028 | if (temp_plot.m_connectPoints[i] == true) { |
---|
| 1029 | drawDataPoint(x,y,prevx,prevy,temp_plot.m_shapeSize[i], |
---|
| 1030 | MISSING_SHAPE,gx); |
---|
| 1031 | } else { |
---|
| 1032 | drawDataPoint(x,y,temp_plot.m_shapeSize[i], |
---|
| 1033 | MISSING_SHAPE,gx); |
---|
| 1034 | } |
---|
| 1035 | } else { |
---|
| 1036 | if (temp_plot.m_shapeType[i] == CONST_AUTOMATIC_SHAPE) { |
---|
| 1037 | if (temp_plot.m_connectPoints[i] == true) { |
---|
| 1038 | drawDataPoint(x,y,prevx,prevy, |
---|
| 1039 | temp_plot.m_shapeSize[i],j,gx); |
---|
| 1040 | } else { |
---|
| 1041 | drawDataPoint(x,y,temp_plot.m_shapeSize[i],j,gx); |
---|
| 1042 | } |
---|
| 1043 | } else { |
---|
| 1044 | if (temp_plot.m_connectPoints[i] == true) { |
---|
| 1045 | drawDataPoint(x,y,prevx,prevy,temp_plot.m_shapeSize[i], |
---|
| 1046 | temp_plot.m_shapeType[i],gx); |
---|
| 1047 | } else { |
---|
| 1048 | drawDataPoint(x,y,temp_plot.m_shapeSize[i], |
---|
| 1049 | temp_plot.m_shapeType[i],gx); |
---|
| 1050 | } |
---|
| 1051 | } |
---|
| 1052 | } |
---|
| 1053 | } else { |
---|
| 1054 | double r; |
---|
| 1055 | Color ci = null; |
---|
| 1056 | if (!temp_plot.m_plotInstances.instance(i). |
---|
| 1057 | isMissing(m_cIndex)) { |
---|
| 1058 | r = (temp_plot.m_plotInstances.instance(i). |
---|
| 1059 | value(m_cIndex) - m_minC) / (m_maxC - m_minC); |
---|
| 1060 | r = (r * 240) + 15; |
---|
| 1061 | ci = new Color((int)r,150,(int)(255-r)); |
---|
| 1062 | } else { |
---|
| 1063 | ci = Color.gray; |
---|
| 1064 | } |
---|
| 1065 | if (!temp_plot.m_useCustomColour) { |
---|
| 1066 | gx.setColor(ci); |
---|
| 1067 | } else { |
---|
| 1068 | gx.setColor(temp_plot.m_customColour); |
---|
| 1069 | } |
---|
| 1070 | if (temp_plot.m_plotInstances.instance(i). |
---|
| 1071 | isMissing(m_cIndex)) { |
---|
| 1072 | if (temp_plot.m_connectPoints[i] == true) { |
---|
| 1073 | drawDataPoint(x,y,prevx,prevy,temp_plot.m_shapeSize[i], |
---|
| 1074 | MISSING_SHAPE,gx); |
---|
| 1075 | } else { |
---|
| 1076 | drawDataPoint(x,y,temp_plot.m_shapeSize[i], |
---|
| 1077 | MISSING_SHAPE,gx); |
---|
| 1078 | } |
---|
| 1079 | } else { |
---|
| 1080 | if (temp_plot.m_shapeType[i] == CONST_AUTOMATIC_SHAPE) { |
---|
| 1081 | if (temp_plot.m_connectPoints[i] == true) { |
---|
| 1082 | drawDataPoint(x,y,prevx,prevy, |
---|
| 1083 | temp_plot.m_shapeSize[i],j,gx); |
---|
| 1084 | } else { |
---|
| 1085 | drawDataPoint(x,y,temp_plot.m_shapeSize[i],j,gx); |
---|
| 1086 | } |
---|
| 1087 | } else { |
---|
| 1088 | if (temp_plot.m_connectPoints[i] == true) { |
---|
| 1089 | drawDataPoint(x,y,prevx,prevy,temp_plot.m_shapeSize[i], |
---|
| 1090 | temp_plot.m_shapeType[i],gx); |
---|
| 1091 | } else { |
---|
| 1092 | drawDataPoint(x,y,temp_plot.m_shapeSize[i], |
---|
| 1093 | temp_plot.m_shapeType[i],gx); |
---|
| 1094 | } |
---|
| 1095 | } |
---|
| 1096 | } |
---|
| 1097 | } |
---|
| 1098 | } |
---|
| 1099 | } |
---|
| 1100 | } |
---|
| 1101 | } |
---|
| 1102 | } |
---|
| 1103 | } |
---|
| 1104 | |
---|
| 1105 | /* |
---|
| 1106 | public void determineAxisPositions(Graphics gx) { |
---|
| 1107 | setFonts(gx); |
---|
| 1108 | int mxs = m_XaxisStart; |
---|
| 1109 | int mxe = m_XaxisEnd; |
---|
| 1110 | int mys = m_YaxisStart; |
---|
| 1111 | int mye = m_YaxisEnd; |
---|
| 1112 | m_axisChanged = false; |
---|
| 1113 | |
---|
| 1114 | int h = this.getHeight(); |
---|
| 1115 | int w = this.getWidth(); |
---|
| 1116 | int hf = m_labelMetrics.getAscent(); |
---|
| 1117 | int mswx=0; |
---|
| 1118 | int mswy=0; |
---|
| 1119 | |
---|
| 1120 | // determineBounds(); |
---|
| 1121 | int fieldWidthX = (int)((Math.log(m_maxX)/Math.log(10)))+1; |
---|
| 1122 | int precisionX = 1; |
---|
| 1123 | if ((Math.abs(m_maxX-m_minX) < 1) && ((m_maxY-m_minX) != 0)) { |
---|
| 1124 | precisionX = (int)Math.abs(((Math.log(Math.abs(m_maxX-m_minX)) / |
---|
| 1125 | Math.log(10))))+1; |
---|
| 1126 | } |
---|
| 1127 | String maxStringX = Utils.doubleToString(m_maxX, |
---|
| 1128 | fieldWidthX+1+precisionX |
---|
| 1129 | ,precisionX); |
---|
| 1130 | mswx = m_labelMetrics.stringWidth(maxStringX); |
---|
| 1131 | int fieldWidthY = (int)((Math.log(m_maxY)/Math.log(10)))+1; |
---|
| 1132 | int precisionY = 1; |
---|
| 1133 | if (Math.abs((m_maxY-m_minY)) < 1 && ((m_maxY-m_minY) != 0)) { |
---|
| 1134 | precisionY = (int)Math.abs(((Math.log(Math.abs(m_maxY-m_minY)) / |
---|
| 1135 | Math.log(10))))+1; |
---|
| 1136 | } |
---|
| 1137 | String maxStringY = Utils.doubleToString(m_maxY, |
---|
| 1138 | fieldWidthY+1+precisionY |
---|
| 1139 | ,precisionY); |
---|
| 1140 | String minStringY = Utils.doubleToString(m_minY, |
---|
| 1141 | fieldWidthY+1+precisionY |
---|
| 1142 | ,precisionY); |
---|
| 1143 | |
---|
| 1144 | if (m_plotInstances.attribute(m_yIndex).isNumeric()) { |
---|
| 1145 | mswy = (m_labelMetrics.stringWidth(maxStringY) > |
---|
| 1146 | m_labelMetrics.stringWidth(minStringY)) |
---|
| 1147 | ? m_labelMetrics.stringWidth(maxStringY) |
---|
| 1148 | : m_labelMetrics.stringWidth(minStringY); |
---|
| 1149 | } else { |
---|
| 1150 | mswy = m_labelMetrics.stringWidth("MM"); |
---|
| 1151 | } |
---|
| 1152 | |
---|
| 1153 | m_YaxisStart = m_axisPad; |
---|
| 1154 | m_XaxisStart = 0+m_axisPad+m_tickSize+mswy; |
---|
| 1155 | |
---|
| 1156 | m_XaxisEnd = w-m_axisPad-(mswx/2); |
---|
| 1157 | |
---|
| 1158 | m_YaxisEnd = h-m_axisPad-(2 * hf)-m_tickSize; |
---|
| 1159 | } */ |
---|
| 1160 | |
---|
| 1161 | /** |
---|
| 1162 | * Draws the axis and a spectrum if the colouring attribute is numeric |
---|
| 1163 | * @param gx the graphics context |
---|
| 1164 | */ |
---|
| 1165 | private void paintAxis(Graphics gx) { |
---|
| 1166 | setFonts(gx); |
---|
| 1167 | int mxs = m_XaxisStart; |
---|
| 1168 | int mxe = m_XaxisEnd; |
---|
| 1169 | int mys = m_YaxisStart; |
---|
| 1170 | int mye = m_YaxisEnd; |
---|
| 1171 | m_plotResize = false; |
---|
| 1172 | |
---|
| 1173 | int h = this.getHeight(); |
---|
| 1174 | int w = this.getWidth(); |
---|
| 1175 | int hf = m_labelMetrics.getAscent(); |
---|
| 1176 | int mswx=0; |
---|
| 1177 | int mswy=0; |
---|
| 1178 | |
---|
| 1179 | // determineBounds(); |
---|
| 1180 | int precisionXmax = 1; |
---|
| 1181 | int precisionXmin = 1; |
---|
| 1182 | int precisionXmid = 1; |
---|
| 1183 | /*if ((Math.abs(m_maxX-m_minX) < 1) && ((m_maxY-m_minX) != 0)) { |
---|
| 1184 | precisionX = (int)Math.abs(((Math.log(Math.abs(m_maxX-m_minX)) / |
---|
| 1185 | Math.log(10))))+1; |
---|
| 1186 | } */ |
---|
| 1187 | int whole = (int)Math.abs(m_maxX); |
---|
| 1188 | double decimal = Math.abs(m_maxX) - whole; |
---|
| 1189 | int nondecimal; |
---|
| 1190 | nondecimal = (whole > 0) |
---|
| 1191 | ? (int)(Math.log(whole) / Math.log(10)) |
---|
| 1192 | : 1; |
---|
| 1193 | |
---|
| 1194 | precisionXmax = (decimal > 0) |
---|
| 1195 | ? (int)Math.abs(((Math.log(Math.abs(m_maxX)) / |
---|
| 1196 | Math.log(10))))+2 |
---|
| 1197 | : 1; |
---|
| 1198 | if (precisionXmax > VisualizeUtils.MAX_PRECISION) { |
---|
| 1199 | precisionXmax = 1; |
---|
| 1200 | } |
---|
| 1201 | |
---|
| 1202 | String maxStringX = Utils.doubleToString(m_maxX, |
---|
| 1203 | nondecimal+1+precisionXmax |
---|
| 1204 | ,precisionXmax); |
---|
| 1205 | |
---|
| 1206 | whole = (int)Math.abs(m_minX); |
---|
| 1207 | decimal = Math.abs(m_minX) - whole; |
---|
| 1208 | nondecimal = (whole > 0) |
---|
| 1209 | ? (int)(Math.log(whole) / Math.log(10)) |
---|
| 1210 | : 1; |
---|
| 1211 | precisionXmin = (decimal > 0) |
---|
| 1212 | ? (int)Math.abs(((Math.log(Math.abs(m_minX)) / |
---|
| 1213 | Math.log(10))))+2 |
---|
| 1214 | : 1; |
---|
| 1215 | if (precisionXmin > VisualizeUtils.MAX_PRECISION) { |
---|
| 1216 | precisionXmin = 1; |
---|
| 1217 | } |
---|
| 1218 | |
---|
| 1219 | String minStringX = Utils.doubleToString(m_minX, |
---|
| 1220 | nondecimal+1+precisionXmin, |
---|
| 1221 | precisionXmin); |
---|
| 1222 | |
---|
| 1223 | mswx = m_labelMetrics.stringWidth(maxStringX); |
---|
| 1224 | |
---|
| 1225 | int precisionYmax = 1; |
---|
| 1226 | int precisionYmin = 1; |
---|
| 1227 | int precisionYmid = 1; |
---|
| 1228 | whole = (int)Math.abs(m_maxY); |
---|
| 1229 | decimal = Math.abs(m_maxY) - whole; |
---|
| 1230 | nondecimal = (whole > 0) |
---|
| 1231 | ? (int)(Math.log(whole) / Math.log(10)) |
---|
| 1232 | : 1; |
---|
| 1233 | precisionYmax = (decimal > 0) |
---|
| 1234 | ? (int)Math.abs(((Math.log(Math.abs(m_maxY)) / |
---|
| 1235 | Math.log(10))))+2 |
---|
| 1236 | : 1; |
---|
| 1237 | if (precisionYmax > VisualizeUtils.MAX_PRECISION) { |
---|
| 1238 | precisionYmax = 1; |
---|
| 1239 | } |
---|
| 1240 | |
---|
| 1241 | String maxStringY = Utils.doubleToString(m_maxY, |
---|
| 1242 | nondecimal+1+precisionYmax |
---|
| 1243 | ,precisionYmax); |
---|
| 1244 | |
---|
| 1245 | |
---|
| 1246 | whole = (int)Math.abs(m_minY); |
---|
| 1247 | decimal = Math.abs(m_minY) - whole; |
---|
| 1248 | nondecimal = (whole > 0) |
---|
| 1249 | ? (int)(Math.log(whole) / Math.log(10)) |
---|
| 1250 | : 1; |
---|
| 1251 | precisionYmin = (decimal > 0) |
---|
| 1252 | ? (int)Math.abs(((Math.log(Math.abs(m_minY)) / |
---|
| 1253 | Math.log(10))))+2 |
---|
| 1254 | : 1; |
---|
| 1255 | if (precisionYmin > VisualizeUtils.MAX_PRECISION) { |
---|
| 1256 | precisionYmin = 1; |
---|
| 1257 | } |
---|
| 1258 | |
---|
| 1259 | String minStringY = Utils.doubleToString(m_minY, |
---|
| 1260 | nondecimal+1+precisionYmin |
---|
| 1261 | ,precisionYmin); |
---|
| 1262 | |
---|
| 1263 | if (m_plotInstances.attribute(m_yIndex).isNumeric()) { |
---|
| 1264 | mswy = (m_labelMetrics.stringWidth(maxStringY) > |
---|
| 1265 | m_labelMetrics.stringWidth(minStringY)) |
---|
| 1266 | ? m_labelMetrics.stringWidth(maxStringY) |
---|
| 1267 | : m_labelMetrics.stringWidth(minStringY); |
---|
| 1268 | mswy += m_labelMetrics.stringWidth("M"); |
---|
| 1269 | } else { |
---|
| 1270 | mswy = m_labelMetrics.stringWidth("MM"); |
---|
| 1271 | } |
---|
| 1272 | |
---|
| 1273 | m_YaxisStart = m_axisPad; |
---|
| 1274 | m_XaxisStart = 0+m_axisPad+m_tickSize+mswy; |
---|
| 1275 | |
---|
| 1276 | m_XaxisEnd = w-m_axisPad-(mswx/2); |
---|
| 1277 | |
---|
| 1278 | m_YaxisEnd = h-m_axisPad-(2 * hf)-m_tickSize; |
---|
| 1279 | |
---|
| 1280 | // draw axis |
---|
| 1281 | gx.setColor(m_axisColour); |
---|
| 1282 | if (m_plotInstances.attribute(m_xIndex).isNumeric()) { |
---|
| 1283 | if (w > (2 * mswx)) { |
---|
| 1284 | |
---|
| 1285 | gx.drawString(maxStringX, |
---|
| 1286 | m_XaxisEnd-(mswx/2), |
---|
| 1287 | m_YaxisEnd+hf+m_tickSize); |
---|
| 1288 | |
---|
| 1289 | mswx = m_labelMetrics.stringWidth(minStringX); |
---|
| 1290 | gx.drawString(minStringX, |
---|
| 1291 | (m_XaxisStart-(mswx/2)), |
---|
| 1292 | m_YaxisEnd+hf+m_tickSize); |
---|
| 1293 | |
---|
| 1294 | // draw the middle value |
---|
| 1295 | if (w > (3 * mswx) && |
---|
| 1296 | (m_plotInstances.attribute(m_xIndex).isNumeric())) { |
---|
| 1297 | double mid = m_minX+((m_maxX-m_minX)/2.0); |
---|
| 1298 | whole = (int)Math.abs(mid); |
---|
| 1299 | decimal = Math.abs(mid) - whole; |
---|
| 1300 | nondecimal = (whole > 0) |
---|
| 1301 | ? (int)(Math.log(whole) / Math.log(10)) |
---|
| 1302 | : 1; |
---|
| 1303 | precisionXmid = (decimal > 0) |
---|
| 1304 | ? (int)Math.abs(((Math.log(Math.abs(mid)) / |
---|
| 1305 | Math.log(10))))+2 |
---|
| 1306 | : 1; |
---|
| 1307 | if (precisionXmid > VisualizeUtils.MAX_PRECISION) { |
---|
| 1308 | precisionXmid = 1; |
---|
| 1309 | } |
---|
| 1310 | |
---|
| 1311 | String maxString = Utils.doubleToString(mid, |
---|
| 1312 | nondecimal+1+precisionXmid, |
---|
| 1313 | precisionXmid); |
---|
| 1314 | int sw = m_labelMetrics.stringWidth(maxString); |
---|
| 1315 | double mx = m_XaxisStart+((double)(m_XaxisEnd-m_XaxisStart)/2.0); |
---|
| 1316 | gx.drawString(maxString, |
---|
| 1317 | (int)(mx-(((double)sw)/2.0)), |
---|
| 1318 | m_YaxisEnd+hf+m_tickSize); |
---|
| 1319 | gx.drawLine((int)mx,m_YaxisEnd,(int)mx,m_YaxisEnd+m_tickSize); |
---|
| 1320 | } |
---|
| 1321 | } |
---|
| 1322 | } else { |
---|
| 1323 | int numValues = m_plotInstances.attribute(m_xIndex).numValues(); |
---|
| 1324 | int div = (numValues % 2 > 0) ? (numValues/2)+1 : (numValues/2); |
---|
| 1325 | int maxXStringWidth = (m_XaxisEnd - m_XaxisStart) / numValues; |
---|
| 1326 | |
---|
| 1327 | for (int i=0;i<numValues;i++) { |
---|
| 1328 | String val = m_plotInstances.attribute(m_xIndex).value(i); |
---|
| 1329 | int sw = m_labelMetrics.stringWidth(val); |
---|
| 1330 | int rm; |
---|
| 1331 | // truncate string if necessary |
---|
| 1332 | if (sw > maxXStringWidth) { |
---|
| 1333 | int incr = (sw / val.length()); |
---|
| 1334 | rm = (sw - maxXStringWidth) / incr; |
---|
| 1335 | if (rm == 0) { |
---|
| 1336 | rm = 1; |
---|
| 1337 | } |
---|
| 1338 | val = val.substring(0,val.length()-rm); |
---|
| 1339 | sw = m_labelMetrics.stringWidth(val); |
---|
| 1340 | } |
---|
| 1341 | if (i == 0) { |
---|
| 1342 | gx.drawString(val,(int)convertToPanelX(i), |
---|
| 1343 | m_YaxisEnd+hf+m_tickSize); |
---|
| 1344 | } else if (i == numValues -1) { |
---|
| 1345 | if ((i % 2) == 0) { |
---|
| 1346 | gx.drawString(val, |
---|
| 1347 | m_XaxisEnd-sw, |
---|
| 1348 | m_YaxisEnd+hf+m_tickSize); |
---|
| 1349 | } else { |
---|
| 1350 | gx.drawString(val, |
---|
| 1351 | m_XaxisEnd-sw, |
---|
| 1352 | m_YaxisEnd+(2*hf)+m_tickSize); |
---|
| 1353 | } |
---|
| 1354 | } else { |
---|
| 1355 | if ((i % 2) == 0) { |
---|
| 1356 | gx.drawString(val, |
---|
| 1357 | (int)convertToPanelX(i)-(sw/2), |
---|
| 1358 | m_YaxisEnd+hf+m_tickSize); |
---|
| 1359 | } else { |
---|
| 1360 | gx.drawString(val, |
---|
| 1361 | (int)convertToPanelX(i)-(sw/2), |
---|
| 1362 | m_YaxisEnd+(2*hf)+m_tickSize); |
---|
| 1363 | } |
---|
| 1364 | } |
---|
| 1365 | gx.drawLine((int)convertToPanelX(i), |
---|
| 1366 | m_YaxisEnd, |
---|
| 1367 | (int)convertToPanelX(i), |
---|
| 1368 | m_YaxisEnd+m_tickSize); |
---|
| 1369 | } |
---|
| 1370 | |
---|
| 1371 | } |
---|
| 1372 | |
---|
| 1373 | // draw the y axis |
---|
| 1374 | if (m_plotInstances.attribute(m_yIndex).isNumeric()) { |
---|
| 1375 | if (h > (2 * hf)) { |
---|
| 1376 | gx.drawString(maxStringY, |
---|
| 1377 | m_XaxisStart-mswy-m_tickSize, |
---|
| 1378 | m_YaxisStart+(hf)); |
---|
| 1379 | |
---|
| 1380 | gx.drawString(minStringY, |
---|
| 1381 | (m_XaxisStart-mswy-m_tickSize), |
---|
| 1382 | m_YaxisEnd); |
---|
| 1383 | |
---|
| 1384 | // draw the middle value |
---|
| 1385 | if (w > (3 * hf) && |
---|
| 1386 | (m_plotInstances.attribute(m_yIndex).isNumeric())) { |
---|
| 1387 | double mid = m_minY+((m_maxY-m_minY)/2.0); |
---|
| 1388 | whole = (int)Math.abs(mid); |
---|
| 1389 | decimal = Math.abs(mid) - whole; |
---|
| 1390 | nondecimal = (whole > 0) |
---|
| 1391 | ? (int)(Math.log(whole) / Math.log(10)) |
---|
| 1392 | : 1; |
---|
| 1393 | precisionYmid = (decimal > 0) |
---|
| 1394 | ? (int)Math.abs(((Math.log(Math.abs(mid)) / |
---|
| 1395 | Math.log(10))))+2 |
---|
| 1396 | : 1; |
---|
| 1397 | if (precisionYmid > VisualizeUtils.MAX_PRECISION) { |
---|
| 1398 | precisionYmid = 1; |
---|
| 1399 | } |
---|
| 1400 | |
---|
| 1401 | String maxString = Utils.doubleToString(mid, |
---|
| 1402 | nondecimal+1+precisionYmid, |
---|
| 1403 | precisionYmid); |
---|
| 1404 | int sw = m_labelMetrics.stringWidth(maxString); |
---|
| 1405 | double mx = m_YaxisStart+((double)(m_YaxisEnd-m_YaxisStart)/2.0); |
---|
| 1406 | gx.drawString(maxString, |
---|
| 1407 | m_XaxisStart-sw-m_tickSize-1, |
---|
| 1408 | (int)(mx+(((double)hf)/2.0))); |
---|
| 1409 | gx.drawLine(m_XaxisStart-m_tickSize,(int)mx,m_XaxisStart,(int)mx); |
---|
| 1410 | } |
---|
| 1411 | } |
---|
| 1412 | } else { |
---|
| 1413 | int numValues = m_plotInstances.attribute(m_yIndex).numValues(); |
---|
| 1414 | int div = ((numValues % 2) == 0) ? (numValues/2) : (numValues/2+1); |
---|
| 1415 | int maxYStringHeight = (m_YaxisEnd - m_XaxisStart) / div; |
---|
| 1416 | int sw = m_labelMetrics.stringWidth("M"); |
---|
| 1417 | for (int i=0;i<numValues;i++) { |
---|
| 1418 | // can we at least print 2 characters |
---|
| 1419 | if (maxYStringHeight >= (2*hf)) { |
---|
| 1420 | String val = m_plotInstances.attribute(m_yIndex).value(i); |
---|
| 1421 | int numPrint = ((maxYStringHeight/hf) > val.length()) ? |
---|
| 1422 | val.length() : |
---|
| 1423 | (maxYStringHeight/hf); |
---|
| 1424 | |
---|
| 1425 | for (int j=0;j<numPrint;j++) { |
---|
| 1426 | String ll = val.substring(j,j+1); |
---|
| 1427 | if (val.charAt(j) == '_' || val.charAt(j) == '-') { |
---|
| 1428 | ll = "|"; |
---|
| 1429 | } |
---|
| 1430 | if (i == 0) { |
---|
| 1431 | gx.drawString(ll,m_XaxisStart-sw-m_tickSize-1, |
---|
| 1432 | (int)convertToPanelY(i) |
---|
| 1433 | -((numPrint-1)*hf) |
---|
| 1434 | +(j*hf) |
---|
| 1435 | +(hf/2)); |
---|
| 1436 | } else if (i == (numValues-1)) { |
---|
| 1437 | if ((i % 2) == 0) { |
---|
| 1438 | gx.drawString(ll,m_XaxisStart-sw-m_tickSize-1, |
---|
| 1439 | (int)convertToPanelY(i) |
---|
| 1440 | +(j*hf) |
---|
| 1441 | +(hf/2)); |
---|
| 1442 | } else { |
---|
| 1443 | gx.drawString(ll,m_XaxisStart-(2*sw)-m_tickSize-1, |
---|
| 1444 | (int)convertToPanelY(i) |
---|
| 1445 | +(j*hf) |
---|
| 1446 | +(hf/2)); |
---|
| 1447 | } |
---|
| 1448 | } else { |
---|
| 1449 | if ((i % 2) == 0) { |
---|
| 1450 | gx.drawString(ll,m_XaxisStart-sw-m_tickSize-1, |
---|
| 1451 | (int)convertToPanelY(i) |
---|
| 1452 | -(((numPrint-1)*hf)/2) |
---|
| 1453 | +(j*hf) |
---|
| 1454 | +(hf/2)); |
---|
| 1455 | } else { |
---|
| 1456 | gx.drawString(ll,m_XaxisStart-(2*sw)-m_tickSize-1, |
---|
| 1457 | (int)convertToPanelY(i) |
---|
| 1458 | -(((numPrint-1)*hf)/2) |
---|
| 1459 | +(j*hf) |
---|
| 1460 | +(hf/2)); |
---|
| 1461 | } |
---|
| 1462 | } |
---|
| 1463 | } |
---|
| 1464 | } |
---|
| 1465 | gx.drawLine(m_XaxisStart-m_tickSize, |
---|
| 1466 | (int)convertToPanelY(i), |
---|
| 1467 | m_XaxisStart, |
---|
| 1468 | (int)convertToPanelY(i)); |
---|
| 1469 | } |
---|
| 1470 | } |
---|
| 1471 | |
---|
| 1472 | gx.drawLine(m_XaxisStart, |
---|
| 1473 | m_YaxisStart, |
---|
| 1474 | m_XaxisStart, |
---|
| 1475 | m_YaxisEnd); |
---|
| 1476 | gx.drawLine(m_XaxisStart, |
---|
| 1477 | m_YaxisEnd, |
---|
| 1478 | m_XaxisEnd, |
---|
| 1479 | m_YaxisEnd); |
---|
| 1480 | |
---|
| 1481 | if (m_XaxisStart != mxs || m_XaxisEnd != mxe || |
---|
| 1482 | m_YaxisStart != mys || m_YaxisEnd != mye) { |
---|
| 1483 | m_plotResize = true; |
---|
| 1484 | } |
---|
| 1485 | } |
---|
| 1486 | |
---|
| 1487 | /** |
---|
| 1488 | * Add more colours to the colour map |
---|
| 1489 | */ |
---|
| 1490 | private void extendColourMap(int highest) { |
---|
| 1491 | //System.err.println("Extending colour map"); |
---|
| 1492 | for (int i = m_colorList.size(); i < highest; i++) { |
---|
| 1493 | Color pc = m_DefaultColors[i % 10]; |
---|
| 1494 | int ija = i / 10; |
---|
| 1495 | ija *= 2; |
---|
| 1496 | for (int j=0;j<ija;j++) { |
---|
| 1497 | pc = pc.brighter(); |
---|
| 1498 | } |
---|
| 1499 | |
---|
| 1500 | m_colorList.addElement(pc); |
---|
| 1501 | } |
---|
| 1502 | } |
---|
| 1503 | |
---|
| 1504 | /** |
---|
| 1505 | * Renders this component |
---|
| 1506 | * @param gx the graphics context |
---|
| 1507 | */ |
---|
| 1508 | public void paintComponent(Graphics gx) { |
---|
| 1509 | super.paintComponent(gx); |
---|
| 1510 | if (m_plotInstances != null |
---|
| 1511 | && m_plotInstances.numInstances() > 0 |
---|
| 1512 | && m_plotInstances.numAttributes() > 0) { |
---|
| 1513 | if (m_plotCompanion != null) { |
---|
| 1514 | m_plotCompanion.prePlot(gx); |
---|
| 1515 | } |
---|
| 1516 | |
---|
| 1517 | m_JRand = new Random(m_JitterVal); |
---|
| 1518 | paintAxis(gx); |
---|
| 1519 | if (m_axisChanged || m_plotResize) { |
---|
| 1520 | int x_range = m_XaxisEnd - m_XaxisStart; |
---|
| 1521 | int y_range = m_YaxisEnd - m_YaxisStart; |
---|
| 1522 | if (x_range < 10) { |
---|
| 1523 | x_range = 10; |
---|
| 1524 | } |
---|
| 1525 | if (y_range < 10) { |
---|
| 1526 | y_range = 10; |
---|
| 1527 | } |
---|
| 1528 | |
---|
| 1529 | m_drawnPoints = new int[x_range + 1][y_range + 1]; |
---|
| 1530 | fillLookup(); |
---|
| 1531 | m_plotResize = false; |
---|
| 1532 | m_axisChanged = false; |
---|
| 1533 | } |
---|
| 1534 | paintData(gx); |
---|
| 1535 | } |
---|
| 1536 | } |
---|
| 1537 | |
---|
| 1538 | protected static Color checkAgainstBackground(Color c, Color background) { |
---|
| 1539 | if (background == null) { |
---|
| 1540 | return c; |
---|
| 1541 | } |
---|
| 1542 | |
---|
| 1543 | if (c.equals(background)) { |
---|
| 1544 | int red = c.getRed(); |
---|
| 1545 | int blue = c.getBlue(); |
---|
| 1546 | int green = c.getGreen(); |
---|
| 1547 | red += (red < 128) ? (255 - red) / 2 : -(red / 2); |
---|
| 1548 | blue += (blue < 128) ? (blue - red) / 2 : -(blue / 2); |
---|
| 1549 | green += (green< 128) ? (255 - green) / 2 : -(green / 2); |
---|
| 1550 | c = new Color(red, green, blue); |
---|
| 1551 | } |
---|
| 1552 | return c; |
---|
| 1553 | } |
---|
| 1554 | |
---|
| 1555 | /** |
---|
| 1556 | * Main method for testing this class |
---|
| 1557 | * @param args arguments |
---|
| 1558 | */ |
---|
| 1559 | public static void main(String [] args) { |
---|
| 1560 | try { |
---|
| 1561 | if (args.length < 1) { |
---|
| 1562 | System.err.println("Usage : weka.gui.visualize.Plot2D " |
---|
| 1563 | +"<dataset> [<dataset> <dataset>...]"); |
---|
| 1564 | System.exit(1); |
---|
| 1565 | } |
---|
| 1566 | |
---|
| 1567 | final javax.swing.JFrame jf = |
---|
| 1568 | new javax.swing.JFrame("Weka Explorer: Visualize"); |
---|
| 1569 | jf.setSize(500,400); |
---|
| 1570 | jf.getContentPane().setLayout(new BorderLayout()); |
---|
| 1571 | final Plot2D p2 = new Plot2D(); |
---|
| 1572 | jf.getContentPane().add(p2, BorderLayout.CENTER); |
---|
| 1573 | jf.addWindowListener(new java.awt.event.WindowAdapter() { |
---|
| 1574 | public void windowClosing(java.awt.event.WindowEvent e) { |
---|
| 1575 | jf.dispose(); |
---|
| 1576 | System.exit(0); |
---|
| 1577 | } |
---|
| 1578 | }); |
---|
| 1579 | |
---|
| 1580 | p2.addMouseListener(new MouseAdapter() { |
---|
| 1581 | public void mouseClicked(MouseEvent e) { |
---|
| 1582 | if ((e.getModifiers() & InputEvent.BUTTON1_MASK) == |
---|
| 1583 | InputEvent.BUTTON1_MASK) { |
---|
| 1584 | p2.searchPoints(e.getX(), e.getY(), false); |
---|
| 1585 | } else { |
---|
| 1586 | p2.searchPoints(e.getX(), e.getY(), true); |
---|
| 1587 | } |
---|
| 1588 | } |
---|
| 1589 | }); |
---|
| 1590 | |
---|
| 1591 | jf.setVisible(true); |
---|
| 1592 | if (args.length >= 1) { |
---|
| 1593 | for (int j = 0; j < args.length; j++) { |
---|
| 1594 | System.err.println("Loading instances from " + args[j]); |
---|
| 1595 | java.io.Reader r = new java.io.BufferedReader( |
---|
| 1596 | new java.io.FileReader(args[j])); |
---|
| 1597 | Instances i = new Instances(r); |
---|
| 1598 | i.setClassIndex(i.numAttributes()-1); |
---|
| 1599 | PlotData2D pd1 = new PlotData2D(i); |
---|
| 1600 | |
---|
| 1601 | if (j == 0) { |
---|
| 1602 | pd1.setPlotName("Master plot"); |
---|
| 1603 | p2.setMasterPlot(pd1); |
---|
| 1604 | p2.setXindex(2); |
---|
| 1605 | p2.setYindex(3); |
---|
| 1606 | p2.setCindex(i.classIndex()); |
---|
| 1607 | } else { |
---|
| 1608 | pd1.setPlotName("Plot "+(j+1)); |
---|
| 1609 | pd1.m_useCustomColour = true; |
---|
| 1610 | pd1.m_customColour = (j % 2 == 0) ? Color.red : Color.blue; |
---|
| 1611 | p2.addPlot(pd1); |
---|
| 1612 | } |
---|
| 1613 | } |
---|
| 1614 | } |
---|
| 1615 | } catch (Exception ex) { |
---|
| 1616 | ex.printStackTrace(); |
---|
| 1617 | System.err.println(ex.getMessage()); |
---|
| 1618 | } |
---|
| 1619 | } |
---|
| 1620 | } |
---|