Frames | No Frames |
1: /* =========================================================== 2: * JFreeChart : a free chart library for the Java(tm) platform 3: * =========================================================== 4: * 5: * (C) Copyright 2000-2005, 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: * SimpleHistogramDataset.java 29: * --------------------------- 30: * (C) Copyright 2005 by Object Refinery Limited and Contributors. 31: * 32: * Original Author: David Gilbert (for Object Refinery Limited); 33: * Contributor(s): -; 34: * 35: * $Id: SimpleHistogramDataset.java,v 1.7.2.1 2005/10/25 21:34:46 mungady Exp $ 36: * 37: * Changes 38: * ------- 39: * 10-Jan-2005 : Version 1 (DG); 40: * 41: */ 42: 43: package org.jfree.data.statistics; 44: 45: import java.io.Serializable; 46: import java.util.ArrayList; 47: import java.util.Collections; 48: import java.util.Iterator; 49: import java.util.List; 50: 51: import org.jfree.data.DomainOrder; 52: import org.jfree.data.general.DatasetChangeEvent; 53: import org.jfree.data.xy.AbstractIntervalXYDataset; 54: import org.jfree.data.xy.IntervalXYDataset; 55: import org.jfree.util.ObjectUtilities; 56: import org.jfree.util.PublicCloneable; 57: 58: /** 59: * A dataset used for creating simple histograms with custom defined bins. 60: * 61: * @see HistogramDataset 62: */ 63: public class SimpleHistogramDataset extends AbstractIntervalXYDataset 64: implements IntervalXYDataset, 65: Cloneable, PublicCloneable, 66: Serializable { 67: 68: /** For serialization. */ 69: private static final long serialVersionUID = 7997996479768018443L; 70: 71: /** The series key. */ 72: private Comparable key; 73: 74: /** The bins. */ 75: private List bins; 76: 77: /** 78: * A flag that controls whether or not the bin count is divided by the 79: * bin size. 80: */ 81: private boolean adjustForBinSize; 82: 83: /** 84: * Creates a new histogram dataset. 85: * 86: * @param key the series key. 87: */ 88: public SimpleHistogramDataset(Comparable key) { 89: this.key = key; 90: this.bins = new ArrayList(); 91: this.adjustForBinSize = true; 92: } 93: 94: /** 95: * Returns a flag that controls whether or not the bin count is divided by 96: * the bin size in the {@link #getXValue(int, int)} method. 97: * 98: * @return A boolean. 99: */ 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 166: = (SimpleHistogramBin) iterator.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.next(); 199: if (bin.accepts(value)) { 200: bin.setItemCount(bin.getItemCount() + 1); 201: placed = true; 202: } 203: } 204: if (!placed) { 205: throw new RuntimeException("No bin."); 206: } 207: if (notify) { 208: notifyListeners(new DatasetChangeEvent(this, this)); 209: } 210: } 211: 212: /** 213: * Adds a set of values to the dataset. 214: * 215: * @param values the values. 216: */ 217: public void addObservations(double[] values) { 218: for (int i = 0; i < values.length; i++) { 219: addObservation(values[i], false); 220: } 221: notifyListeners(new DatasetChangeEvent(this, this)); 222: } 223: 224: /** 225: * Returns the x-value for an item within a series. The x-values may or 226: * may not be returned in ascending order, that is up to the class 227: * implementing the interface. 228: * 229: * @param series the series index (zero-based). 230: * @param item the item index (zero-based). 231: * 232: * @return The x-value (never <code>null</code>). 233: */ 234: public Number getX(int series, int item) { 235: return new Double(getXValue(series, item)); 236: } 237: 238: /** 239: * Returns the x-value (as a double primitive) for an item within a series. 240: * 241: * @param series the series index (zero-based). 242: * @param item the item index (zero-based). 243: * 244: * @return The x-value. 245: */ 246: public double getXValue(int series, int item) { 247: SimpleHistogramBin bin = (SimpleHistogramBin) this.bins.get(item); 248: return (bin.getLowerBound() + bin.getUpperBound()) / 2.0; 249: } 250: 251: /** 252: * Returns the y-value for an item within a series. 253: * 254: * @param series the series index (zero-based). 255: * @param item the item index (zero-based). 256: * 257: * @return The y-value (possibly <code>null</code>). 258: */ 259: public Number getY(int series, int item) { 260: return new Double(getYValue(series, item)); 261: } 262: 263: /** 264: * Returns the y-value (as a double primitive) for an item within a series. 265: * 266: * @param series the series index (zero-based). 267: * @param item the item index (zero-based). 268: * 269: * @return The y-value. 270: */ 271: public double getYValue(int series, int item) { 272: SimpleHistogramBin bin = (SimpleHistogramBin) this.bins.get(item); 273: if (this.adjustForBinSize) { 274: return bin.getItemCount() 275: / (bin.getUpperBound() - bin.getLowerBound()); 276: } 277: else { 278: return bin.getItemCount(); 279: } 280: } 281: 282: /** 283: * Returns the starting X value for the specified series and item. 284: * 285: * @param series the series index (zero-based). 286: * @param item the item index (zero-based). 287: * 288: * @return The value. 289: */ 290: public Number getStartX(int series, int item) { 291: return new Double(getStartXValue(series, item)); 292: } 293: 294: /** 295: * Returns the start x-value (as a double primitive) for an item within a 296: * series. 297: * 298: * @param series the series (zero-based index). 299: * @param item the item (zero-based index). 300: * 301: * @return The start x-value. 302: */ 303: public double getStartXValue(int series, int item) { 304: SimpleHistogramBin bin = (SimpleHistogramBin) this.bins.get(item); 305: return bin.getLowerBound(); 306: } 307: 308: /** 309: * Returns the ending X value for the specified series and item. 310: * 311: * @param series the series index (zero-based). 312: * @param item the item index (zero-based). 313: * 314: * @return The value. 315: */ 316: public Number getEndX(int series, int item) { 317: return new Double(getEndXValue(series, item)); 318: } 319: 320: /** 321: * Returns the end x-value (as a double primitive) for an item within a 322: * series. 323: * 324: * @param series the series index (zero-based). 325: * @param item the item index (zero-based). 326: * 327: * @return The end x-value. 328: */ 329: public double getEndXValue(int series, int item) { 330: SimpleHistogramBin bin = (SimpleHistogramBin) this.bins.get(item); 331: return bin.getUpperBound(); 332: } 333: 334: /** 335: * Returns the starting Y value for the specified series and item. 336: * 337: * @param series the series index (zero-based). 338: * @param item the item index (zero-based). 339: * 340: * @return The value. 341: */ 342: public Number getStartY(int series, int item) { 343: return getY(series, item); 344: } 345: 346: /** 347: * Returns the start y-value (as a double primitive) for an item within a 348: * series. 349: * 350: * @param series the series index (zero-based). 351: * @param item the item index (zero-based). 352: * 353: * @return The start y-value. 354: */ 355: public double getStartYValue(int series, int item) { 356: return getYValue(series, item); 357: } 358: 359: /** 360: * Returns the ending Y value for the specified series and item. 361: * 362: * @param series the series index (zero-based). 363: * @param item the item index (zero-based). 364: * 365: * @return The value. 366: */ 367: public Number getEndY(int series, int item) { 368: return getY(series, item); 369: } 370: 371: /** 372: * Returns the end y-value (as a double primitive) for an item within a 373: * series. 374: * 375: * @param series the series index (zero-based). 376: * @param item the item index (zero-based). 377: * 378: * @return The end y-value. 379: */ 380: public double getEndYValue(int series, int item) { 381: return getYValue(series, item); 382: } 383: 384: /** 385: * Compares the dataset for equality with an arbitrary object. 386: * 387: * @param obj the object (<code>null</code> permitted). 388: * 389: * @return A boolean. 390: */ 391: public boolean equals(Object obj) { 392: if (obj == this) { 393: return true; 394: } 395: if (!(obj instanceof SimpleHistogramDataset)) { 396: return false; 397: } 398: SimpleHistogramDataset that = (SimpleHistogramDataset) obj; 399: if (!this.key.equals(that.key)) { 400: return false; 401: } 402: if (this.adjustForBinSize != that.adjustForBinSize) { 403: return false; 404: } 405: if (!this.bins.equals(that.bins)) { 406: return false; 407: } 408: return true; 409: } 410: 411: /** 412: * Returns a clone of the dataset. 413: * 414: * @return A clone. 415: * 416: * @throws CloneNotSupportedException not thrown by this class, but maybe 417: * by subclasses (if any). 418: */ 419: public Object clone() throws CloneNotSupportedException { 420: SimpleHistogramDataset clone = (SimpleHistogramDataset) super.clone(); 421: clone.bins = (List) ObjectUtilities.deepClone(this.bins); 422: return clone; 423: } 424: 425: }