Frames | No Frames |
1: /* =========================================================== 2: * JFreeChart : a free chart library for the Java(tm) platform 3: * =========================================================== 4: * 5: * (C) Copyright 2000-2007, by Object Refinery Limited and Contributors. 6: * 7: * Project Info: http://www.jfree.org/jfreechart/index.html 8: * 9: * This library is free software; you can redistribute it and/or modify it 10: * under the terms of the GNU Lesser General Public License as published by 11: * the Free Software Foundation; either version 2.1 of the License, or 12: * (at your option) any later version. 13: * 14: * This library is distributed in the hope that it will be useful, but 15: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 16: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 17: * License for more details. 18: * 19: * You should have received a copy of the GNU Lesser General Public 20: * License along with this library; if not, write to the Free Software 21: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 22: * USA. 23: * 24: * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 25: * in the United States and other countries.] 26: * 27: * -------------------------- 28: * DefaultContourDataset.java 29: * -------------------------- 30: * (C) Copyright 2002-2007, by David M. O'Donnell and Contributors. 31: * 32: * Original Author: David M. O'Donnell; 33: * Contributor(s): David Gilbert (for Object Refinery Limited); 34: * 35: * Changes (from 23-Jan-2003) 36: * -------------------------- 37: * 23-Jan-2003 : Added standard header (DG); 38: * 20-May-2003 : removed member vars numX and numY, which were never used (TM); 39: * 06-May-2004 : Now extends AbstractXYZDataset (DG); 40: * 15-Jul-2004 : Switched getX() with getXValue(), getY() with getYValue() and 41: * getZ() with getZValue() methods (DG); 42: * ------------- JFREECHART 1.0.x -------------------------------------------- 43: * 31-Jan-2007 : Deprecated (DG); 44: * 45: */ 46: 47: package org.jfree.data.contour; 48: 49: import java.util.Arrays; 50: import java.util.Date; 51: import java.util.Vector; 52: 53: import org.jfree.chart.plot.XYPlot; 54: import org.jfree.chart.renderer.xy.XYBlockRenderer; 55: import org.jfree.data.Range; 56: import org.jfree.data.xy.AbstractXYZDataset; 57: import org.jfree.data.xy.XYDataset; 58: 59: /** 60: * A convenience class that provides a default implementation of the 61: * {@link ContourDataset} interface. 62: * 63: * @deprecated This class is no longer supported (as of version 1.0.4). If 64: * you are creating contour plots, please try to use {@link XYPlot} and 65: * {@link XYBlockRenderer}. 66: */ 67: public class DefaultContourDataset extends AbstractXYZDataset 68: implements ContourDataset { 69: 70: /** The series name (this dataset supports only one series). */ 71: protected Comparable seriesKey = null; 72: 73: /** Storage for the x values. */ 74: protected Number[] xValues = null; 75: 76: /** Storage for the y values. */ 77: protected Number[] yValues = null; 78: 79: /** Storage for the z values. */ 80: protected Number[] zValues = null; 81: 82: /** The index for the start of each column in the data. */ 83: protected int[] xIndex = null; 84: 85: /** Flags that track whether x, y and z are dates. */ 86: boolean[] dateAxis = new boolean[3]; 87: 88: /** 89: * Creates a new dataset, initially empty. 90: */ 91: public DefaultContourDataset() { 92: super(); 93: } 94: 95: /** 96: * Constructs a new dataset with the given data. 97: * 98: * @param seriesKey the series key. 99: * @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: }