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-2005, 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: * $Id: DefaultContourDataset.java,v 1.6.2.3 2007/01/31 15:56:19 mungady Exp $ 36: * 37: * Changes (from 23-Jan-2003) 38: * -------------------------- 39: * 23-Jan-2003 : Added standard header (DG); 40: * 20-May-2003 : removed member vars numX and numY, which were never used (TM); 41: * 06-May-2004 : Now extends AbstractXYZDataset (DG); 42: * 15-Jul-2004 : Switched getX() with getXValue(), getY() with getYValue() and 43: * getZ() with getZValue() methods (DG); 44: * ------------- JFREECHART 1.0.x -------------------------------------------- 45: * 31-Jan-2007 : Deprecated (DG); 46: * 47: */ 48: 49: package org.jfree.data.contour; 50: 51: import java.util.Arrays; 52: import java.util.Date; 53: import java.util.Vector; 54: 55: import org.jfree.chart.plot.XYPlot; 56: import org.jfree.chart.renderer.xy.XYBlockRenderer; 57: import org.jfree.data.Range; 58: import org.jfree.data.xy.AbstractXYZDataset; 59: import org.jfree.data.xy.XYDataset; 60: 61: /** 62: * A convenience class that provides a default implementation of the 63: * {@link ContourDataset} interface. 64: * 65: * @deprecated This class is no longer supported. If you are creating 66: * contour plots, please try to use {@link XYPlot} and 67: * {@link XYBlockRenderer}. 68: */ 69: public class DefaultContourDataset extends AbstractXYZDataset 70: implements ContourDataset { 71: 72: /** The series name (this dataset supports only one series). */ 73: protected Comparable seriesKey = null; 74: 75: /** Storage for the x values. */ 76: protected Number[] xValues = null; 77: 78: /** Storage for the y values. */ 79: protected Number[] yValues = null; 80: 81: /** Storage for the z values. */ 82: protected Number[] zValues = null; 83: 84: /** The index for the start of each column in the data. */ 85: protected int[] xIndex = null; 86: 87: /** Flags that track whether x, y and z are dates. */ 88: boolean[] dateAxis = new boolean[3]; 89: 90: /** 91: * Creates a new dataset, initially empty. 92: */ 93: public DefaultContourDataset() { 94: super(); 95: } 96: 97: /** 98: * Constructs a new dataset with the given data. 99: * 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: }