001 /* =========================================================== 002 * JFreeChart : a free chart library for the Java(tm) platform 003 * =========================================================== 004 * 005 * (C) Copyright 2000-2008, 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-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 047 package org.jfree.data.contour; 048 049 import java.util.Arrays; 050 import java.util.Date; 051 import java.util.Vector; 052 053 import org.jfree.chart.plot.XYPlot; 054 import org.jfree.chart.renderer.xy.XYBlockRenderer; 055 import org.jfree.data.Range; 056 import org.jfree.data.xy.AbstractXYZDataset; 057 import 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 */ 067 public 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 public int getItemCount(int series) { 222 if (series > 0) { 223 throw new IllegalArgumentException("Only one series for contour"); 224 } 225 return this.zValues.length; 226 } 227 228 /** 229 * Returns the maximum z-value. 230 * 231 * @return The maximum z-value. 232 */ 233 public double getMaxZValue() { 234 double zMax = -1.e20; 235 for (int k = 0; k < this.zValues.length; k++) { 236 if (this.zValues[k] != null) { 237 zMax = Math.max(zMax, this.zValues[k].doubleValue()); 238 } 239 } 240 return zMax; 241 } 242 243 /** 244 * Returns the minimum z-value. 245 * 246 * @return The minimum z-value. 247 */ 248 public double getMinZValue() { 249 double zMin = 1.e20; 250 for (int k = 0; k < this.zValues.length; k++) { 251 if (this.zValues[k] != null) { 252 zMin = Math.min(zMin, this.zValues[k].doubleValue()); 253 } 254 } 255 return zMin; 256 } 257 258 /** 259 * Returns the maximum z-value within visible region of plot. 260 * 261 * @param x the x range. 262 * @param y the y range. 263 * 264 * @return The z range. 265 */ 266 public Range getZValueRange(Range x, Range y) { 267 268 double minX = x.getLowerBound(); 269 double minY = y.getLowerBound(); 270 double maxX = x.getUpperBound(); 271 double maxY = y.getUpperBound(); 272 273 double zMin = 1.e20; 274 double zMax = -1.e20; 275 for (int k = 0; k < this.zValues.length; k++) { 276 if (this.xValues[k].doubleValue() >= minX 277 && this.xValues[k].doubleValue() <= maxX 278 && this.yValues[k].doubleValue() >= minY 279 && this.yValues[k].doubleValue() <= maxY) { 280 if (this.zValues[k] != null) { 281 zMin = Math.min(zMin, this.zValues[k].doubleValue()); 282 zMax = Math.max(zMax, this.zValues[k].doubleValue()); 283 } 284 } 285 } 286 287 return new Range(zMin, zMax); 288 } 289 290 /** 291 * Returns the minimum z-value. 292 * 293 * @param minX the minimum x value. 294 * @param minY the minimum y value. 295 * @param maxX the maximum x value. 296 * @param maxY the maximum y value. 297 * 298 * @return The minimum z-value. 299 */ 300 public double getMinZValue(double minX, 301 double minY, 302 double maxX, 303 double maxY) { 304 305 double zMin = 1.e20; 306 for (int k = 0; k < this.zValues.length; k++) { 307 if (this.zValues[k] != null) { 308 zMin = Math.min(zMin, this.zValues[k].doubleValue()); 309 } 310 } 311 return zMin; 312 313 } 314 315 /** 316 * Returns the number of series. 317 * <P> 318 * Required by XYDataset interface (this will always return 1) 319 * 320 * @return 1. 321 */ 322 public int getSeriesCount() { 323 return 1; 324 } 325 326 /** 327 * Returns the name of the specified series. 328 * 329 * Method provided to satisfy the XYDataset interface implementation 330 * 331 * @param series must be zero. 332 * 333 * @return The series name. 334 */ 335 public Comparable getSeriesKey(int series) { 336 if (series > 0) { 337 throw new IllegalArgumentException("Only one series for contour"); 338 } 339 return this.seriesKey; 340 } 341 342 /** 343 * Returns the index of the xvalues. 344 * 345 * @return The x values. 346 */ 347 public int[] getXIndices() { 348 return this.xIndex; 349 } 350 351 /** 352 * Returns the x values. 353 * 354 * @return The x values. 355 */ 356 public Number[] getXValues() { 357 return this.xValues; 358 } 359 360 /** 361 * Returns the x value for the specified series and index (zero-based 362 * indices). Required by the {@link XYDataset}. 363 * 364 * @param series must be zero; 365 * @param item the item index (zero-based). 366 * 367 * @return The x value. 368 */ 369 public Number getX(int series, int item) { 370 if (series > 0) { 371 throw new IllegalArgumentException("Only one series for contour"); 372 } 373 return this.xValues[item]; 374 } 375 376 /** 377 * Returns an x value. 378 * 379 * @param item the item index (zero-based). 380 * 381 * @return The X value. 382 */ 383 public Number getXValue(int item) { 384 return this.xValues[item]; 385 } 386 387 /** 388 * Returns a Number array containing all y values. 389 * 390 * @return The Y values. 391 */ 392 public Number[] getYValues() { 393 return this.yValues; 394 } 395 396 /** 397 * Returns the y value for the specified series and index (zero-based 398 * indices). Required by the {@link XYDataset}. 399 * 400 * @param series the series index (must be zero for this dataset). 401 * @param item the item index (zero-based). 402 * 403 * @return The Y value. 404 */ 405 public Number getY(int series, int item) { 406 if (series > 0) { 407 throw new IllegalArgumentException("Only one series for contour"); 408 } 409 return this.yValues[item]; 410 } 411 412 /** 413 * Returns a Number array containing all z values. 414 * 415 * @return The Z values. 416 */ 417 public Number[] getZValues() { 418 return this.zValues; 419 } 420 421 /** 422 * Returns the z value for the specified series and index (zero-based 423 * indices). Required by the {@link XYDataset} 424 * 425 * @param series the series index (must be zero for this dataset). 426 * @param item the item index (zero-based). 427 * 428 * @return The Z value. 429 */ 430 public Number getZ(int series, int item) { 431 if (series > 0) { 432 throw new IllegalArgumentException("Only one series for contour"); 433 } 434 return this.zValues[item]; 435 } 436 437 /** 438 * Returns an int array contain the index into the x values. 439 * 440 * @return The X values. 441 */ 442 public int[] indexX() { 443 int[] index = new int[this.xValues.length]; 444 for (int k = 0; k < index.length; k++) { 445 index[k] = indexX(k); 446 } 447 return index; 448 } 449 450 /** 451 * Given index k, returns the column index containing k. 452 * 453 * @param k index of interest. 454 * 455 * @return The column index. 456 */ 457 public int indexX(int k) { 458 int i = Arrays.binarySearch(this.xIndex, k); 459 if (i >= 0) { 460 return i; 461 } 462 else { 463 return -1 * i - 2; 464 } 465 } 466 467 468 /** 469 * Given index k, return the row index containing k. 470 * 471 * @param k index of interest. 472 * 473 * @return The row index. 474 */ 475 public int indexY(int k) { // this may be obsolete (not used anywhere) 476 return (k / this.xValues.length); 477 } 478 479 /** 480 * Given column and row indices, returns the k index. 481 * 482 * @param i index of along x-axis. 483 * @param j index of along y-axis. 484 * 485 * @return The Z index. 486 */ 487 public int indexZ(int i, int j) { 488 return this.xValues.length * j + i; 489 } 490 491 /** 492 * Returns true if axis are dates. 493 * 494 * @param axisNumber The axis where 0-x, 1-y, and 2-z. 495 * 496 * @return A boolean. 497 */ 498 public boolean isDateAxis(int axisNumber) { 499 if (axisNumber < 0 || axisNumber > 2) { 500 return false; // bad axisNumber 501 } 502 return this.dateAxis[axisNumber]; 503 } 504 505 /** 506 * Sets the names of the series in the data source. 507 * 508 * @param seriesKeys the keys of the series in the data source. 509 */ 510 public void setSeriesKeys(Comparable[] seriesKeys) { 511 if (seriesKeys.length > 1) { 512 throw new IllegalArgumentException( 513 "Contours only support one series"); 514 } 515 this.seriesKey = seriesKeys[0]; 516 fireDatasetChanged(); 517 } 518 519 }