Source for org.jfree.data.contour.DefaultContourDataset

   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: }