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