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: * SimpleHistogramDataset.java
029: * ---------------------------
030: * (C) Copyright 2005, 2007, by Object Refinery Limited and Contributors.
031: *
032: * Original Author: David Gilbert (for Object Refinery Limited);
033: * Contributor(s): Sergei Ivanov;
034: *
035: * $Id: SimpleHistogramDataset.java,v 1.7.2.2 2007/05/21 15:32:11 mungady Exp $
036: *
037: * Changes
038: * -------
039: * 10-Jan-2005 : Version 1 (DG);
040: * 21-May-2007 : Added clearObservations() and removeAllBins() (SI);
041: *
042: */
043:
044: package org.jfree.data.statistics;
045:
046: import java.io.Serializable;
047: import java.util.ArrayList;
048: import java.util.Collections;
049: import java.util.Iterator;
050: import java.util.List;
051:
052: import org.jfree.data.DomainOrder;
053: import org.jfree.data.general.DatasetChangeEvent;
054: import org.jfree.data.xy.AbstractIntervalXYDataset;
055: import org.jfree.data.xy.IntervalXYDataset;
056: import org.jfree.util.ObjectUtilities;
057: import org.jfree.util.PublicCloneable;
058:
059: /**
060: * A dataset used for creating simple histograms with custom defined bins.
061: *
062: * @see HistogramDataset
063: */
064: public class SimpleHistogramDataset extends AbstractIntervalXYDataset
065: implements IntervalXYDataset, Cloneable, PublicCloneable,
066: Serializable {
067:
068: /** For serialization. */
069: private static final long serialVersionUID = 7997996479768018443L;
070:
071: /** The series key. */
072: private Comparable key;
073:
074: /** The bins. */
075: private List bins;
076:
077: /**
078: * A flag that controls whether or not the bin count is divided by the
079: * bin size.
080: */
081: private boolean adjustForBinSize;
082:
083: /**
084: * Creates a new histogram dataset.
085: *
086: * @param key the series key.
087: */
088: public SimpleHistogramDataset(Comparable key) {
089: this .key = key;
090: this .bins = new ArrayList();
091: this .adjustForBinSize = true;
092: }
093:
094: /**
095: * Returns a flag that controls whether or not the bin count is divided by
096: * the bin size in the {@link #getXValue(int, int)} method.
097: *
098: * @return A boolean.
099: */
100: public boolean getAdjustForBinSize() {
101: return this .adjustForBinSize;
102: }
103:
104: /**
105: * Sets the flag that controls whether or not the bin count is divided by
106: * the bin size in the {@link #getXValue(int, int)} method.
107: *
108: * @param adjust the flag.
109: */
110: public void setAdjustForBinSize(boolean adjust) {
111: this .adjustForBinSize = adjust;
112: notifyListeners(new DatasetChangeEvent(this , this ));
113: }
114:
115: /**
116: * Returns the number of series in the dataset (always 1 for this dataset).
117: *
118: * @return The series count.
119: */
120: public int getSeriesCount() {
121: return 1;
122: }
123:
124: /**
125: * Returns the key for a series.
126: *
127: * @param series the series (zero-based index, ignored in this dataset).
128: *
129: * @return The key for the series.
130: */
131: public Comparable getSeriesKey(int series) {
132: return this .key;
133: }
134:
135: /**
136: * Returns the order of the domain (or X) values returned by the dataset.
137: *
138: * @return The order (never <code>null</code>).
139: */
140: public DomainOrder getDomainOrder() {
141: return DomainOrder.ASCENDING;
142: }
143:
144: /**
145: * Returns the number of items in a series.
146: *
147: * @param series the series index (zero-based, ignored in this dataset).
148: *
149: * @return The item count.
150: */
151: public int getItemCount(int series) {
152: return this .bins.size();
153: }
154:
155: /**
156: * Adds a bin to the dataset. An exception is thrown if the bin overlaps
157: * with any existing bin in the dataset.
158: *
159: * @param bin the bin (<code>null</code> not permitted).
160: */
161: public void addBin(SimpleHistogramBin bin) {
162: // check that the new bin doesn't overlap with any existing bin
163: Iterator iterator = this .bins.iterator();
164: while (iterator.hasNext()) {
165: SimpleHistogramBin existingBin = (SimpleHistogramBin) iterator
166: .next();
167: if (bin.overlapsWith(existingBin)) {
168: throw new RuntimeException("Overlapping bin");
169: }
170: }
171: this .bins.add(bin);
172: Collections.sort(this .bins);
173: }
174:
175: /**
176: * Adds an observation to the dataset (by incrementing the item count for
177: * the appropriate bin). A runtime exception is thrown if the value does
178: * not fit into any bin.
179: *
180: * @param value the value.
181: */
182: public void addObservation(double value) {
183: addObservation(value, true);
184: }
185:
186: /**
187: * Adds an observation to the dataset (by incrementing the item count for
188: * the appropriate bin). A runtime exception is thrown if the value does
189: * not fit into any bin.
190: *
191: * @param value the value.
192: * @param notify send {@link DatasetChangeEvent} to listeners?
193: */
194: public void addObservation(double value, boolean notify) {
195: boolean placed = false;
196: Iterator iterator = this .bins.iterator();
197: while (iterator.hasNext() && !placed) {
198: SimpleHistogramBin bin = (SimpleHistogramBin) iterator
199: .next();
200: if (bin.accepts(value)) {
201: bin.setItemCount(bin.getItemCount() + 1);
202: placed = true;
203: }
204: }
205: if (!placed) {
206: throw new RuntimeException("No bin.");
207: }
208: if (notify) {
209: notifyListeners(new DatasetChangeEvent(this , this ));
210: }
211: }
212:
213: /**
214: * Adds a set of values to the dataset.
215: *
216: * @param values the values (<code>null</code> not permitted).
217: */
218: public void addObservations(double[] values) {
219: for (int i = 0; i < values.length; i++) {
220: addObservation(values[i], false);
221: }
222: notifyListeners(new DatasetChangeEvent(this , this ));
223: }
224:
225: /**
226: * Removes all current observation data and sends a
227: * {@link DatasetChangeEvent} to all registered listeners.
228: *
229: * @since 1.0.6
230: */
231: public void clearObservations() {
232: Iterator iterator = this .bins.iterator();
233: while (iterator.hasNext()) {
234: SimpleHistogramBin bin = (SimpleHistogramBin) iterator
235: .next();
236: bin.setItemCount(0);
237: }
238: notifyListeners(new DatasetChangeEvent(this , this ));
239: }
240:
241: /**
242: * Removes all bins and sends a {@link DatasetChangeEvent} to all
243: * registered listeners.
244: *
245: * @since 1.0.6
246: */
247: public void removeAllBins() {
248: this .bins = new ArrayList();
249: notifyListeners(new DatasetChangeEvent(this , this ));
250: }
251:
252: /**
253: * Returns the x-value for an item within a series. The x-values may or
254: * may not be returned in ascending order, that is up to the class
255: * implementing the interface.
256: *
257: * @param series the series index (zero-based).
258: * @param item the item index (zero-based).
259: *
260: * @return The x-value (never <code>null</code>).
261: */
262: public Number getX(int series, int item) {
263: return new Double(getXValue(series, item));
264: }
265:
266: /**
267: * Returns the x-value (as a double primitive) for an item within a series.
268: *
269: * @param series the series index (zero-based).
270: * @param item the item index (zero-based).
271: *
272: * @return The x-value.
273: */
274: public double getXValue(int series, int item) {
275: SimpleHistogramBin bin = (SimpleHistogramBin) this .bins
276: .get(item);
277: return (bin.getLowerBound() + bin.getUpperBound()) / 2.0;
278: }
279:
280: /**
281: * Returns the y-value for an item within a series.
282: *
283: * @param series the series index (zero-based).
284: * @param item the item index (zero-based).
285: *
286: * @return The y-value (possibly <code>null</code>).
287: */
288: public Number getY(int series, int item) {
289: return new Double(getYValue(series, item));
290: }
291:
292: /**
293: * Returns the y-value (as a double primitive) for an item within a series.
294: *
295: * @param series the series index (zero-based).
296: * @param item the item index (zero-based).
297: *
298: * @return The y-value.
299: */
300: public double getYValue(int series, int item) {
301: SimpleHistogramBin bin = (SimpleHistogramBin) this .bins
302: .get(item);
303: if (this .adjustForBinSize) {
304: return bin.getItemCount()
305: / (bin.getUpperBound() - bin.getLowerBound());
306: } else {
307: return bin.getItemCount();
308: }
309: }
310:
311: /**
312: * Returns the starting X value for the specified series and item.
313: *
314: * @param series the series index (zero-based).
315: * @param item the item index (zero-based).
316: *
317: * @return The value.
318: */
319: public Number getStartX(int series, int item) {
320: return new Double(getStartXValue(series, item));
321: }
322:
323: /**
324: * Returns the start x-value (as a double primitive) for an item within a
325: * series.
326: *
327: * @param series the series (zero-based index).
328: * @param item the item (zero-based index).
329: *
330: * @return The start x-value.
331: */
332: public double getStartXValue(int series, int item) {
333: SimpleHistogramBin bin = (SimpleHistogramBin) this .bins
334: .get(item);
335: return bin.getLowerBound();
336: }
337:
338: /**
339: * Returns the ending X value for the specified series and item.
340: *
341: * @param series the series index (zero-based).
342: * @param item the item index (zero-based).
343: *
344: * @return The value.
345: */
346: public Number getEndX(int series, int item) {
347: return new Double(getEndXValue(series, item));
348: }
349:
350: /**
351: * Returns the end x-value (as a double primitive) for an item within a
352: * series.
353: *
354: * @param series the series index (zero-based).
355: * @param item the item index (zero-based).
356: *
357: * @return The end x-value.
358: */
359: public double getEndXValue(int series, int item) {
360: SimpleHistogramBin bin = (SimpleHistogramBin) this .bins
361: .get(item);
362: return bin.getUpperBound();
363: }
364:
365: /**
366: * Returns the starting Y value for the specified series and item.
367: *
368: * @param series the series index (zero-based).
369: * @param item the item index (zero-based).
370: *
371: * @return The value.
372: */
373: public Number getStartY(int series, int item) {
374: return getY(series, item);
375: }
376:
377: /**
378: * Returns the start y-value (as a double primitive) for an item within a
379: * series.
380: *
381: * @param series the series index (zero-based).
382: * @param item the item index (zero-based).
383: *
384: * @return The start y-value.
385: */
386: public double getStartYValue(int series, int item) {
387: return getYValue(series, item);
388: }
389:
390: /**
391: * Returns the ending Y value for the specified series and item.
392: *
393: * @param series the series index (zero-based).
394: * @param item the item index (zero-based).
395: *
396: * @return The value.
397: */
398: public Number getEndY(int series, int item) {
399: return getY(series, item);
400: }
401:
402: /**
403: * Returns the end y-value (as a double primitive) for an item within a
404: * series.
405: *
406: * @param series the series index (zero-based).
407: * @param item the item index (zero-based).
408: *
409: * @return The end y-value.
410: */
411: public double getEndYValue(int series, int item) {
412: return getYValue(series, item);
413: }
414:
415: /**
416: * Compares the dataset for equality with an arbitrary object.
417: *
418: * @param obj the object (<code>null</code> permitted).
419: *
420: * @return A boolean.
421: */
422: public boolean equals(Object obj) {
423: if (obj == this ) {
424: return true;
425: }
426: if (!(obj instanceof SimpleHistogramDataset)) {
427: return false;
428: }
429: SimpleHistogramDataset that = (SimpleHistogramDataset) obj;
430: if (!this .key.equals(that.key)) {
431: return false;
432: }
433: if (this .adjustForBinSize != that.adjustForBinSize) {
434: return false;
435: }
436: if (!this .bins.equals(that.bins)) {
437: return false;
438: }
439: return true;
440: }
441:
442: /**
443: * Returns a clone of the dataset.
444: *
445: * @return A clone.
446: *
447: * @throws CloneNotSupportedException not thrown by this class, but maybe
448: * by subclasses (if any).
449: */
450: public Object clone() throws CloneNotSupportedException {
451: SimpleHistogramDataset clone = (SimpleHistogramDataset) super
452: .clone();
453: clone.bins = (List) ObjectUtilities.deepClone(this.bins);
454: return clone;
455: }
456:
457: }
|