001/* =========================================================== 002 * JFreeChart : a free chart library for the Java(tm) platform 003 * =========================================================== 004 * 005 * (C) Copyright 2000-2013, by Object Refinery Limited and Contributors. 006 * 007 * Project Info: http://www.jfree.org/jfreechart/index.html 008 * 009 * This library is free software; you can redistribute it and/or modify it 010 * under the terms of the GNU Lesser General Public License as published by 011 * the Free Software Foundation; either version 2.1 of the License, or 012 * (at your option) any later version. 013 * 014 * This library is distributed in the hope that it will be useful, but 015 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 016 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 017 * License for more details. 018 * 019 * You should have received a copy of the GNU Lesser General Public 020 * License along with this library; if not, write to the Free Software 021 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 022 * USA. 023 * 024 * [Oracle and Java are registered trademarks of Oracle and/or its affiliates. 025 * Other names may be trademarks of their respective owners.] 026 * 027 * -------------------------- 028 * DefaultContourDataset.java 029 * -------------------------- 030 * (C) Copyright 2002-2008, by David M. O'Donnell and Contributors. 031 * 032 * Original Author: David M. O'Donnell; 033 * Contributor(s): David Gilbert (for Object Refinery Limited); 034 * 035 * Changes (from 23-Jan-2003) 036 * -------------------------- 037 * 23-Jan-2003 : Added standard header (DG); 038 * 20-May-2003 : removed member vars numX and numY, which were never used (TM); 039 * 06-May-2004 : Now extends AbstractXYZDataset (DG); 040 * 15-Jul-2004 : Switched getX() with getXValue(), getY() with getYValue() and 041 * getZ() with getZValue() methods (DG); 042 * ------------- JFREECHART 1.0.x -------------------------------------------- 043 * 31-Jan-2007 : Deprecated (DG); 044 * 045 */ 046 047package org.jfree.data.contour; 048 049import java.util.Arrays; 050import java.util.Date; 051import java.util.Vector; 052 053import org.jfree.chart.plot.XYPlot; 054import org.jfree.chart.renderer.xy.XYBlockRenderer; 055import org.jfree.data.Range; 056import org.jfree.data.xy.AbstractXYZDataset; 057import org.jfree.data.xy.XYDataset; 058 059/** 060 * A convenience class that provides a default implementation of the 061 * {@link ContourDataset} interface. 062 * 063 * @deprecated This class is no longer supported (as of version 1.0.4). If 064 * you are creating contour plots, please try to use {@link XYPlot} and 065 * {@link XYBlockRenderer}. 066 */ 067public class DefaultContourDataset extends AbstractXYZDataset 068 implements ContourDataset { 069 070 /** The series name (this dataset supports only one series). */ 071 protected Comparable seriesKey = null; 072 073 /** Storage for the x values. */ 074 protected Number[] xValues = null; 075 076 /** Storage for the y values. */ 077 protected Number[] yValues = null; 078 079 /** Storage for the z values. */ 080 protected Number[] zValues = null; 081 082 /** The index for the start of each column in the data. */ 083 protected int[] xIndex = null; 084 085 /** Flags that track whether x, y and z are dates. */ 086 boolean[] dateAxis = new boolean[3]; 087 088 /** 089 * Creates a new dataset, initially empty. 090 */ 091 public DefaultContourDataset() { 092 super(); 093 } 094 095 /** 096 * Constructs a new dataset with the given data. 097 * 098 * @param seriesKey the series key. 099 * @param xData the x values. 100 * @param yData the y values. 101 * @param zData the z values. 102 */ 103 public DefaultContourDataset(Comparable seriesKey, 104 Object[] xData, 105 Object[] yData, 106 Object[] zData) { 107 108 this.seriesKey = seriesKey; 109 initialize(xData, yData, zData); 110 } 111 112 /** 113 * Initialises the dataset. 114 * 115 * @param xData the x values. 116 * @param yData the y values. 117 * @param zData the z values. 118 */ 119 public void initialize(Object[] xData, 120 Object[] yData, 121 Object[] zData) { 122 123 this.xValues = new Double[xData.length]; 124 this.yValues = new Double[yData.length]; 125 this.zValues = new Double[zData.length]; 126 127 // We organise the data with the following assumption: 128 // 1) the data are sorted by x then y 129 // 2) that the data will be represented by a rectangle formed by 130 // using x[i+1], x, y[j+1], and y. 131 // 3) we march along the y-axis at the same value of x until a new 132 // value x is found at which point we will flag the index 133 // where x[i+1]<>x[i] 134 135 Vector tmpVector = new Vector(); //create a temporary vector 136 double x = 1.123452e31; // set x to some arbitary value (used below) 137 for (int k = 0; k < this.xValues.length; k++) { 138 if (xData[k] != null) { 139 Number xNumber; 140 if (xData[k] instanceof Number) { 141 xNumber = (Number) xData[k]; 142 } 143 else if (xData[k] instanceof Date) { 144 this.dateAxis[0] = true; 145 Date xDate = (Date) xData[k]; 146 xNumber = new Long(xDate.getTime()); //store data as Long 147 } 148 else { 149 xNumber = new Integer(0); 150 } 151 this.xValues[k] = new Double(xNumber.doubleValue()); 152 // store Number as Double 153 154 // check if starting new column 155 if (x != this.xValues[k].doubleValue()) { 156 tmpVector.add(new Integer(k)); //store index where new 157 //column starts 158 x = this.xValues[k].doubleValue(); 159 // set x to most recent value 160 } 161 } 162 } 163 164 Object[] inttmp = tmpVector.toArray(); 165 this.xIndex = new int[inttmp.length]; // create array xIndex to hold 166 // new column indices 167 168 for (int i = 0; i < inttmp.length; i++) { 169 this.xIndex[i] = ((Integer) inttmp[i]).intValue(); 170 } 171 for (int k = 0; k < this.yValues.length; k++) { // store y and z axes 172 // as Doubles 173 this.yValues[k] = (Double) yData[k]; 174 if (zData[k] != null) { 175 this.zValues[k] = (Double) zData[k]; 176 } 177 } 178 } 179 180 /** 181 * Creates an object array from an array of doubles. 182 * 183 * @param data the data. 184 * 185 * @return An array of <code>Double</code> objects. 186 */ 187 public static Object[][] formObjectArray(double[][] data) { 188 Object[][] object = new Double[data.length][data[0].length]; 189 190 for (int i = 0; i < object.length; i++) { 191 for (int j = 0; j < object[i].length; j++) { 192 object[i][j] = new Double(data[i][j]); 193 } 194 } 195 return object; 196 } 197 198 /** 199 * Creates an object array from an array of doubles. 200 * 201 * @param data the data. 202 * 203 * @return An array of <code>Double</code> objects. 204 */ 205 public static Object[] formObjectArray(double[] data) { 206 Object[] object = new Double[data.length]; 207 for (int i = 0; i < object.length; i++) { 208 object[i] = new Double(data[i]); 209 } 210 return object; 211 } 212 213 /** 214 * Returns the number of items in the specified series. This method 215 * is provided to satisfy the {@link XYDataset} interface implementation. 216 * 217 * @param series must be zero, as this dataset only supports one series. 218 * 219 * @return The item count. 220 */ 221 @Override 222 public int getItemCount(int series) { 223 if (series > 0) { 224 throw new IllegalArgumentException("Only one series for contour"); 225 } 226 return this.zValues.length; 227 } 228 229 /** 230 * Returns the maximum z-value. 231 * 232 * @return The maximum z-value. 233 */ 234 @Override 235 public double getMaxZValue() { 236 double zMax = -1.e20; 237 for (int k = 0; k < this.zValues.length; k++) { 238 if (this.zValues[k] != null) { 239 zMax = Math.max(zMax, this.zValues[k].doubleValue()); 240 } 241 } 242 return zMax; 243 } 244 245 /** 246 * Returns the minimum z-value. 247 * 248 * @return The minimum z-value. 249 */ 250 @Override 251 public double getMinZValue() { 252 double zMin = 1.e20; 253 for (int k = 0; k < this.zValues.length; k++) { 254 if (this.zValues[k] != null) { 255 zMin = Math.min(zMin, this.zValues[k].doubleValue()); 256 } 257 } 258 return zMin; 259 } 260 261 /** 262 * Returns the maximum z-value within visible region of plot. 263 * 264 * @param x the x range. 265 * @param y the y range. 266 * 267 * @return The z range. 268 */ 269 @Override 270 public Range getZValueRange(Range x, Range y) { 271 272 double minX = x.getLowerBound(); 273 double minY = y.getLowerBound(); 274 double maxX = x.getUpperBound(); 275 double maxY = y.getUpperBound(); 276 277 double zMin = 1.e20; 278 double zMax = -1.e20; 279 for (int k = 0; k < this.zValues.length; k++) { 280 if (this.xValues[k].doubleValue() >= minX 281 && this.xValues[k].doubleValue() <= maxX 282 && this.yValues[k].doubleValue() >= minY 283 && this.yValues[k].doubleValue() <= maxY) { 284 if (this.zValues[k] != null) { 285 zMin = Math.min(zMin, this.zValues[k].doubleValue()); 286 zMax = Math.max(zMax, this.zValues[k].doubleValue()); 287 } 288 } 289 } 290 291 return new Range(zMin, zMax); 292 } 293 294 /** 295 * Returns the minimum z-value. 296 * 297 * @param minX the minimum x value. 298 * @param minY the minimum y value. 299 * @param maxX the maximum x value. 300 * @param maxY the maximum y value. 301 * 302 * @return The minimum z-value. 303 */ 304 public double getMinZValue(double minX, 305 double minY, 306 double maxX, 307 double maxY) { 308 309 double zMin = 1.e20; 310 for (int k = 0; k < this.zValues.length; k++) { 311 if (this.zValues[k] != null) { 312 zMin = Math.min(zMin, this.zValues[k].doubleValue()); 313 } 314 } 315 return zMin; 316 317 } 318 319 /** 320 * Returns the number of series. 321 * <P> 322 * Required by XYDataset interface (this will always return 1) 323 * 324 * @return 1. 325 */ 326 @Override 327 public int getSeriesCount() { 328 return 1; 329 } 330 331 /** 332 * Returns the name of the specified series. 333 * 334 * Method provided to satisfy the XYDataset interface implementation 335 * 336 * @param series must be zero. 337 * 338 * @return The series name. 339 */ 340 @Override 341 public Comparable getSeriesKey(int series) { 342 if (series > 0) { 343 throw new IllegalArgumentException("Only one series for contour"); 344 } 345 return this.seriesKey; 346 } 347 348 /** 349 * Returns the index of the xvalues. 350 * 351 * @return The x values. 352 */ 353 @Override 354 public int[] getXIndices() { 355 return this.xIndex; 356 } 357 358 /** 359 * Returns the x values. 360 * 361 * @return The x values. 362 */ 363 @Override 364 public Number[] getXValues() { 365 return this.xValues; 366 } 367 368 /** 369 * Returns the x value for the specified series and index (zero-based 370 * indices). Required by the {@link XYDataset}. 371 * 372 * @param series must be zero; 373 * @param item the item index (zero-based). 374 * 375 * @return The x value. 376 */ 377 @Override 378 public Number getX(int series, int item) { 379 if (series > 0) { 380 throw new IllegalArgumentException("Only one series for contour"); 381 } 382 return this.xValues[item]; 383 } 384 385 /** 386 * Returns an x value. 387 * 388 * @param item the item index (zero-based). 389 * 390 * @return The X value. 391 */ 392 public Number getXValue(int item) { 393 return this.xValues[item]; 394 } 395 396 /** 397 * Returns a Number array containing all y values. 398 * 399 * @return The Y values. 400 */ 401 @Override 402 public Number[] getYValues() { 403 return this.yValues; 404 } 405 406 /** 407 * Returns the y value for the specified series and index (zero-based 408 * indices). Required by the {@link XYDataset}. 409 * 410 * @param series the series index (must be zero for this dataset). 411 * @param item the item index (zero-based). 412 * 413 * @return The Y value. 414 */ 415 @Override 416 public Number getY(int series, int item) { 417 if (series > 0) { 418 throw new IllegalArgumentException("Only one series for contour"); 419 } 420 return this.yValues[item]; 421 } 422 423 /** 424 * Returns a Number array containing all z values. 425 * 426 * @return The Z values. 427 */ 428 @Override 429 public Number[] getZValues() { 430 return this.zValues; 431 } 432 433 /** 434 * Returns the z value for the specified series and index (zero-based 435 * indices). Required by the {@link XYDataset} 436 * 437 * @param series the series index (must be zero for this dataset). 438 * @param item the item index (zero-based). 439 * 440 * @return The Z value. 441 */ 442 @Override 443 public Number getZ(int series, int item) { 444 if (series > 0) { 445 throw new IllegalArgumentException("Only one series for contour"); 446 } 447 return this.zValues[item]; 448 } 449 450 /** 451 * Returns an int array contain the index into the x values. 452 * 453 * @return The X values. 454 */ 455 @Override 456 public int[] indexX() { 457 int[] index = new int[this.xValues.length]; 458 for (int k = 0; k < index.length; k++) { 459 index[k] = indexX(k); 460 } 461 return index; 462 } 463 464 /** 465 * Given index k, returns the column index containing k. 466 * 467 * @param k index of interest. 468 * 469 * @return The column index. 470 */ 471 public int indexX(int k) { 472 int i = Arrays.binarySearch(this.xIndex, k); 473 if (i >= 0) { 474 return i; 475 } 476 else { 477 return -1 * i - 2; 478 } 479 } 480 481 482 /** 483 * Given index k, return the row index containing k. 484 * 485 * @param k index of interest. 486 * 487 * @return The row index. 488 */ 489 public int indexY(int k) { // this may be obsolete (not used anywhere) 490 return (k / this.xValues.length); 491 } 492 493 /** 494 * Given column and row indices, returns the k index. 495 * 496 * @param i index of along x-axis. 497 * @param j index of along y-axis. 498 * 499 * @return The Z index. 500 */ 501 public int indexZ(int i, int j) { 502 return this.xValues.length * j + i; 503 } 504 505 /** 506 * Returns true if axis are dates. 507 * 508 * @param axisNumber The axis where 0-x, 1-y, and 2-z. 509 * 510 * @return A boolean. 511 */ 512 @Override 513 public boolean isDateAxis(int axisNumber) { 514 if (axisNumber < 0 || axisNumber > 2) { 515 return false; // bad axisNumber 516 } 517 return this.dateAxis[axisNumber]; 518 } 519 520 /** 521 * Sets the names of the series in the data source. 522 * 523 * @param seriesKeys the keys of the series in the data source. 524 */ 525 public void setSeriesKeys(Comparable[] seriesKeys) { 526 if (seriesKeys.length > 1) { 527 throw new IllegalArgumentException( 528 "Contours only support one series"); 529 } 530 this.seriesKey = seriesKeys[0]; 531 fireDatasetChanged(); 532 } 533 534}