📄 histogramdataset.java
字号:
/* ===========================================================
* JFreeChart : a free chart library for the Java(tm) platform
* ===========================================================
*
* (C) Copyright 2000-2004, by Object Refinery Limited and Contributors.
*
* Project Info: http://www.jfree.org/jfreechart/index.html
*
* This library is free software; you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Foundation;
* either version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with this
* library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307, USA.
*
* [Java is a trademark or registered trademark of Sun Microsystems, Inc.
* in the United States and other countries.]
*
* ---------------------
* HistogramDataset.java
* ---------------------
* (C) Copyright 2003, 2004, by Jelai Wang and Contributors.
*
* Original Author: Jelai Wang (jelaiw AT mindspring.com);
* Contributor(s): David Gilbert (for Object Refinery Limited);
*
* $Id: HistogramDataset.java,v 1.1 2004/08/31 15:32:24 mungady Exp $
*
* Changes
* -------
* 06-Jul-2003 : Version 1, contributed by Jelai Wang (DG);
* 07-Jul-2003 : Changed package and added Javadocs (DG);
* 15-Oct-2003 : Updated Javadocs and removed array sorting (JW);
* 09-Jan-2004 : Added fix by "Z." posted in the JFreeChart forum (DG);
* 01-Mar-2004 : Added equals() and clone() methods and implemented Serializable. Also added
* new addSeries() method (DG);
* 06-May-2004 : Now extends AbstractIntervalXYDataset (DG);
* 15-Jul-2004 : Switched getX() with getXValue() and getY() with getYValue() (DG);
*
*/
package org.jfree.data.statistics;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.jfree.data.general.DatasetChangeEvent;
import org.jfree.data.xy.AbstractIntervalXYDataset;
import org.jfree.data.xy.IntervalXYDataset;
import org.jfree.util.ObjectUtils;
/**
* A dataset that can be used for creating histograms.
* <p>
* See the <code>HistogramDemo.java</code> file in the JFreeChart distribution for an example.
*
* @author Jelai Wang, jelaiw AT mindspring.com
*/
public class HistogramDataset extends AbstractIntervalXYDataset
implements IntervalXYDataset, Cloneable, Serializable {
/** A list of maps. */
private List list;
/** The histogram type. */
private HistogramType type;
/**
* Creates a new (empty) dataset with a default type of {@link HistogramType}.FREQUENCY.
*/
public HistogramDataset() {
this.list = new ArrayList();
this.type = HistogramType.FREQUENCY;
}
/**
* Returns the histogram type.
*
* @return the type (never <code>null</code>).
*/
public HistogramType getType() {
return this.type;
}
/**
* Sets the histogram type and sends a {@link DatasetChangeEvent} to all registered
* listeners.
*
* @param type the type (<code>null</code> not permitted).
*/
public void setType(final HistogramType type) {
if (type == null) {
throw new IllegalArgumentException("Null 'type' argument");
}
this.type = type;
notifyListeners(new DatasetChangeEvent(this, this));
}
/**
* Adds a series to the dataset, using the specified number of bins.
*
* @param name the series name (<code>null</code> not permitted).
* @param values the values (<code>null</code> not permitted).
* @param bins the number of bins (must be at least 1).
*/
public void addSeries(final String name, final double[] values, final int bins) {
// defer argument checking...
final double minimum = getMinimum(values);
final double maximum = getMaximum(values);
addSeries(name, values, bins, minimum, maximum);
}
/**
* Adds a series to the dataset. Any data value falling on a bin boundary will be assigned to
* the lower value bin, with the exception of the lower bound of the bin range which is always
* assigned to the first bin.
*
* @param name the series name (<code>null</code> not permitted).
* @param values the raw observations.
* @param bins the number of bins.
* @param minimum the lower bound of the bin range.
* @param maximum the upper bound of the bin range.
*/
public void addSeries(final String name,
final double[] values,
final int bins,
final double minimum,
final double maximum) {
if (name == null) {
throw new IllegalArgumentException("Null 'name' argument.");
}
if (values == null) {
throw new IllegalArgumentException("Null 'values' argument.");
}
else if (bins < 1) {
throw new IllegalArgumentException("The 'bins' value must be at least 1.");
}
final double binWidth = (maximum - minimum) / bins;
double tmp = minimum;
final List binList = new ArrayList(bins);
for (int i = 0; i < bins; i++) {
final HistogramBin bin;
// make sure bins[bins.length]'s upper boundary ends at maximum
// to avoid the rounding issue. the bins[0] lower boundary is
// guaranteed start from min
if (i == bins - 1) {
bin = new HistogramBin(tmp, maximum);
}
else {
bin = new HistogramBin(tmp, tmp + binWidth);
}
tmp = tmp + binWidth;
binList.add(bin);
}
// fill the bins
for (int i = 0; i < values.length; i++) {
for (int j = 0; j < bins; j++) {
final HistogramBin currentBin = (HistogramBin) binList.get(j);
if (values[i] >= currentBin.getStartBoundary()
&& values[i] <= currentBin.getEndBoundary()) {
// note the greedy <=
currentBin.incrementCount();
break; // break out of inner loop
}
}
}
// generic map for each series
final Map map = new HashMap();
map.put("name", name);
map.put("bins", binList);
map.put("values.length", new Integer(values.length));
map.put("bin width", new Double(binWidth));
this.list.add(map);
}
/**
* Returns the minimum value in an array of values.
*
* @param values the values (<code>null</code> not permitted and zero-length array
* not permitted).
*
* @return the minimum value.
*/
private double getMinimum(final double[] values) {
if (values == null || values.length < 1) {
throw new IllegalArgumentException("Null or zero length 'values' argument.");
}
double min = Double.MAX_VALUE;
for (int i = 0; i < values.length; i++) {
if (values[i] < min) {
min = values[i];
}
}
return min;
}
/**
* Returns the maximum value in an array of values.
*
* @param values the values (<code>null</code> not permitted and zero-length array
* not permitted).
*
* @return the maximum value.
*/
private double getMaximum(final double[] values) {
if (values == null || values.length < 1) {
throw new IllegalArgumentException("Null or zero length 'values' argument.");
}
double max = -Double.MAX_VALUE;
for (int i = 0; i < values.length; i++) {
if (values[i] > max) {
max = values[i];
}
}
return max;
}
/**
* Returns the bins for a series.
*
* @param series the series index.
*
* @return An array of bins.
*/
List getBins(final int series) {
final Map map = (Map) this.list.get(series);
return (List) map.get("bins");
}
/**
* Returns the total number of observations for a series.
*
* @param series the series index.
*
* @return the total.
*/
private int getTotal(final int series) {
final Map map = (Map) this.list.get(series);
return ((Integer) map.get("values.length")).intValue();
}
/**
* Returns the bin width for a series.
*
* @param series the series index (zero based).
*
* @return the bin width.
*/
private double getBinWidth(final int series) {
final Map map = (Map) this.list.get(series);
return ((Double) map.get("bin width")).doubleValue();
}
/**
* Returns the number of series in the dataset.
*
* @return The series count.
*/
public int getSeriesCount() {
return this.list.size();
}
/**
* Returns the name for a series.
*
* @param series the series index (zero based).
*
* @return The series name.
*/
public String getSeriesName(final int series) {
final Map map = (Map) this.list.get(series);
return (String) map.get("name");
}
/**
* Returns the number of data items for a series.
*
* @param series the series index (zero based).
*
* @return the item count.
*/
public int getItemCount(final int series) {
return getBins(series).size();
}
/**
* Returns the X value for a bin.
* <p>
* This value won't be used for plotting histograms, since the renderer will ignore it.
* But other renderers can use it (for example, you could use the dataset to create a line
* chart).
*
* @param series the series index (zero based).
* @param item the item index (zero based).
*
* @return The start value.
*/
public Number getX(int series, int item) {
final List bins = getBins(series);
final HistogramBin bin = (HistogramBin) bins.get(item);
final double x = (bin.getStartBoundary() + bin.getEndBoundary()) / 2.;
return new Double(x);
}
/**
* Returns the y-value for a bin (calculated to take into account the histogram type).
*
* @param series the series index (zero based).
* @param item the item index (zero based).
*
* @return The y-value.
*/
public Number getY(int series, int item) {
final List bins = getBins(series);
final HistogramBin bin = (HistogramBin) bins.get(item);
final double total = getTotal(series);
final double binWidth = getBinWidth(series);
if (this.type == HistogramType.FREQUENCY) {
return new Double(bin.getCount());
}
else if (this.type == HistogramType.RELATIVE_FREQUENCY) {
return new Double(bin.getCount() / total);
}
else if (this.type == HistogramType.SCALE_AREA_TO_1) {
return new Double(bin.getCount() / (binWidth * total));
}
else { // pretty sure this shouldn't ever happen
throw new IllegalStateException();
}
}
/**
* Returns the start value for a bin.
*
* @param series the series index (zero based).
* @param item the item index (zero based).
*
* @return The start value.
*/
public Number getStartX(int series, int item) {
final List bins = getBins(series);
final HistogramBin bin = (HistogramBin) bins.get(item);
return new Double(bin.getStartBoundary());
}
/**
* Returns the end value for a bin.
*
* @param series the series index (zero based).
* @param item the item index (zero based).
*
* @return The end value.
*/
public Number getEndX(int series, int item) {
final List bins = getBins(series);
final HistogramBin bin = (HistogramBin) bins.get(item);
return new Double(bin.getEndBoundary());
}
/**
* Returns the start y-value for a bin (which is the same as the y-value, this method
* exists only to support the general form of the {@link IntervalXYDataset} interface).
*
* @param series the series index (zero based).
* @param item the item index (zero based).
*
* @return The y-value.
*/
public Number getStartY(int series, int item) {
return getY(series, item);
}
/**
* Returns the end y-value for a bin (which is the same as the y-value, this method
* exists only to support the general form of the {@link IntervalXYDataset} interface).
*
* @param series the series index (zero based).
* @param item the item index (zero based).
*
* @return The Y value.
*/
public Number getEndY(int series, int item) {
return getY(series, item);
}
/**
* Tests this dataset for equality with an arbitrary object.
*
* @param obj the object to test against (<code>null</code> permitted).
*
* @return A boolean.
*/
public boolean equals(final Object obj) {
if (obj == null) {
return false;
}
if (obj == this) {
return true;
}
if (obj instanceof HistogramDataset) {
final HistogramDataset dataset = (HistogramDataset) obj;
final boolean b0 = ObjectUtils.equal(dataset.type, this.type);
final boolean b1 = ObjectUtils.equal(dataset.list, this.list);
return b0 && b1;
}
return false;
}
/**
* Returns a clone of the dataset.
*
* @return A clone of the dataset.
*
* @throws CloneNotSupportedException if the object cannot be cloned.
*/
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -