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