001 /* ===========================================================
002 * JFreeChart : a free chart library for the Java(tm) platform
003 * ===========================================================
004 *
005 * (C) Copyright 2000-2007, 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-2005, 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 * $Id: DefaultContourDataset.java,v 1.6.2.3 2007/01/31 15:56:19 mungady Exp $
036 *
037 * Changes (from 23-Jan-2003)
038 * --------------------------
039 * 23-Jan-2003 : Added standard header (DG);
040 * 20-May-2003 : removed member vars numX and numY, which were never used (TM);
041 * 06-May-2004 : Now extends AbstractXYZDataset (DG);
042 * 15-Jul-2004 : Switched getX() with getXValue(), getY() with getYValue() and
043 * getZ() with getZValue() methods (DG);
044 * ------------- JFREECHART 1.0.x --------------------------------------------
045 * 31-Jan-2007 : Deprecated (DG);
046 *
047 */
048
049 package org.jfree.data.contour;
050
051 import java.util.Arrays;
052 import java.util.Date;
053 import java.util.Vector;
054
055 import org.jfree.chart.plot.XYPlot;
056 import org.jfree.chart.renderer.xy.XYBlockRenderer;
057 import org.jfree.data.Range;
058 import org.jfree.data.xy.AbstractXYZDataset;
059 import org.jfree.data.xy.XYDataset;
060
061 /**
062 * A convenience class that provides a default implementation of the
063 * {@link ContourDataset} interface.
064 *
065 * @deprecated This class is no longer supported. If you are creating
066 * contour plots, please try to use {@link XYPlot} and
067 * {@link XYBlockRenderer}.
068 */
069 public class DefaultContourDataset extends AbstractXYZDataset
070 implements ContourDataset {
071
072 /** The series name (this dataset supports only one series). */
073 protected Comparable seriesKey = null;
074
075 /** Storage for the x values. */
076 protected Number[] xValues = null;
077
078 /** Storage for the y values. */
079 protected Number[] yValues = null;
080
081 /** Storage for the z values. */
082 protected Number[] zValues = null;
083
084 /** The index for the start of each column in the data. */
085 protected int[] xIndex = null;
086
087 /** Flags that track whether x, y and z are dates. */
088 boolean[] dateAxis = new boolean[3];
089
090 /**
091 * Creates a new dataset, initially empty.
092 */
093 public DefaultContourDataset() {
094 super();
095 }
096
097 /**
098 * Constructs a new dataset with the given data.
099 *
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 }