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