/**
* Copyright (C) DataMelt project. The jHPLot package by S.Chekanov and Work.ORG
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation; either
* version 3 of the License, or any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program;
* if not, see .
*
* Additional permission under GNU GPL version 3 section 7:
* If you have received this program as a library with written permission from the DataMelt team,
* you can link or combine this library with your non-GPL project to convey the resulting work.
* In this case, this library should be considered as released under the terms of
* GNU Lesser public license (see ),
* provided you include this license notice and a URL through which recipients can access the
* Corresponding Source.
**/
package jhplot;
import cern.jet.random.AbstractDistribution;
import root.Converter;
import java.io.*;
import java.util.*;
import hep.aida.*;
import hep.aida.ref.histogram.*;
import java.text.DecimalFormat;
import jhplot.gui.HelpBrowser;
import jhplot.utils.SHisto;
import hep.io.root.interfaces.*;
import jplot.LinePars;
/**
* Histogram in one dimension (1D).
* A histogram can be serialized to a file, plotted using HPlot, HPlotJa canvases.
* Many methods to manipulate with histogram and access its statistics are also available.
*
* @author S.Chekanov
*
*/
public class H1D extends DrawOptions implements Serializable {
private static final long serialVersionUID = 1L;
private Histogram1D h1;
private IAxis axis;
private double min;
private double max;
private int bins;
private double[] edges;
/**
* Build 1D histogram. Default constructor. Does not do anything.
*/
public H1D() {
setType(LinePars.H1D);
this.title = "NOT SET";
}
/**
* Build 1D histogram
*
* @param title
* Title
* @param bins
* Number of bins
* @param min
* Minimum value
* @param max
* Maximum value
*/
public H1D(String title, int bins, double min, double max) {
setType(LinePars.H1D);
setStyle("h");
setTitle(title);
this.bins = bins;
this.min = min;
this.max = max;
axis = new FixedAxis(this.bins, this.min, this.max);
h1 = new Histogram1D(this.title, this.title, axis);
}
/**
* Create 1D histogram with variable bin size.
*
* @param title
* Title of histogram.
* @param edges
* edges
*/
public H1D(String title, double[] edges) {
setType(LinePars.H1D);
setStyle("h");
setTitle(title);
this.edges = edges;
this.bins = edges.length - 1;
this.min = edges[0];
this.max = edges[edges.length - 1];
axis = new VariableAxis(edges);
h1 = new Histogram1D(this.title, this.title, axis);
}
/**
* Create 1D histogram with variable bin size.
*
* @param title
* Title of histogram.
* @param edges
* edges
*/
public H1D(String title, IAxis axis) {
setType(LinePars.H1D);
setStyle("h");
setTitle(title);
this.axis = axis;
min = axis.lowerEdge();
max = axis.upperEdge();
bins = axis.bins();
h1 = new Histogram1D(this.title, this.title, axis);
}
/**
* Create H1D histogram from JAIDA Histogram1D class.
*
* @param h1
* Histogram1D histogram from JAIDA
*/
public H1D(Histogram1D h1) {
setType(LinePars.H1D);
setStyle("h");
this.h1 = h1;
this.axis = h1.axis();
this.min = axis.lowerEdge();
this.max = axis.upperEdge();
this.bins = axis.bins();
}
/**
* Create H1D histogram from JAIDA Cloud1D class.
* Min and Max values re determined automatically.
*
* @param c1d
* Cloud1D histogram from JAIDA
* @param bins
* Number of bins for plotting.
*/
public H1D(Cloud1D c1d, int bins) {
setType(LinePars.H1D);
setStyle("h");
setTitle(c1d.title());
this.min = c1d.lowerEdge();
this.max = c1d.upperEdge();
this.bins = bins;
axis = new FixedAxis(this.bins, this.min, this.max);
h1 = new Histogram1D(this.title, this.title, axis);
fill(c1d);
}
/**
* Create H1D histogram from JAIDA IHistogram1D class
*
* @param h1
* IHistogram1D histogram from JAIDA
*/
public H1D(IHistogram1D h1) {
setType(LinePars.H1D);
setStyle("h");
this.h1 = (Histogram1D) h1;
this.title = h1.title();
this.axis = h1.axis();
this.min = axis.lowerEdge();
this.max = axis.upperEdge();
this.bins = axis.bins();
}
/**
* Create H1D from another instance.
*
* @param title
* new title
*
* @param h1d
* input H1D
*/
public H1D(String title, H1D h1d) {
LinePars lnew = copyLinePars(h1d.getLineParm());
setDrawOption(lnew);
this.title = title;
this.axis = h1d.getAxis();
this.min = axis.lowerEdge();
this.max = axis.upperEdge();
this.bins = axis.bins();
this.h1 = h1d.get();
}
/**
* Print histogram on screen
*
*/
public void print() {
DecimalFormat dfb = new DecimalFormat("##.#####E00");
Date dat = new Date();
String today = String.valueOf(dat);
IAxis axis = h1.axis();
System.out.println("");
System.out.println("# DataMelt: output from H1D: " + this.title);
System.out.println("# DataMelt: created at " + today);
System.out.println("# x, y, error(upper), error(lower)");
System.out.println("#");
for (int i = 0; i < axis.bins(); i++) {
String x = dfb.format(h1.binMean(i)); // The weighted mean of a
// bin.
String y = dfb.format(h1.binHeight(i));
String y1 = dfb.format(h1.binError(i));
String y2 = dfb.format(h1.binError(i));
System.out.println(x + " " + y + " " + y1 + " " + y2);
}
}
/**
* Convert the histogram to a string
*
* @return string representing a histogram
*/
public String toString() {
String tmp = "";
DecimalFormat dfb = new DecimalFormat("##.#####E00");
Date dat = new Date();
String today = String.valueOf(dat);
IAxis axis = h1.axis();
tmp = tmp + "# DataMelt: output from H1D: " + this.title + "\n";
tmp = tmp + "# DataMelt: created at " + today + "\n";
tmp = tmp + "# x, y, error(upper), error(lower)\n";
for (int i = 0; i < axis.bins(); i++) {
String x = dfb.format(h1.binMean(i)); // The weighted mean of a
// bin.
String y = dfb.format(h1.binHeight(i));
String y1 = dfb.format(h1.binError(i));
String y2 = dfb.format(h1.binError(i));
tmp = tmp + x + " " + y + " " + y1 + " " + y2 + "\n";
}
return tmp;
}
/**
* Print a H1D histogram to a Table in a separate frame. The numbers are
* formatted to scientific format. One can sort and search the data in this
* table (cannot be modified).
*/
public void toTable() {
new HTable(this);
}
/**
* Fill histogram from P0D array
*
* @param p0d
* input P0D array
*/
public void fill(P0D p0d) {
for (int i = 0; i < p0d.size(); i++)
h1.fill(p0d.getQuick(i));
}
/**
* Fill the histogram with random numbers.
* Random generators are taken from cern.jet.random.*.
* Examples: Beta, Binominal, Poisson, BreitWigner,ChiSquare,Empirical
* Exponential, Gamma, Hyperbolic, Logarithmic, Normal, NegativeBinomial
*
* @param TotNumber number generated events
* @param random generator
*/
public void fill(int TotNumber, AbstractDistribution random) {
for (int i = 0; i < TotNumber; i++)
h1.fill(random.nextDouble());
}
/** Fill the histogram with random numbers from Gaussian (Normal) distribution.
* Seed is taken from time.
* @param TotNumber number generated events
* @param mean mean of the gaussian
* @param sd standard deviation
*/
public void fillGauss(int TotNumber, double mean, double sd) {
java.util.Random random = new java.util.Random();
for (int i = 0; i < TotNumber; i++)
h1.fill(sd*random.nextGaussian()+mean);
}
/** Fill the histogram with random numbers from a flat distribution.
* Seed is taken from time.
* Using mean=0 and width=1 will give a flat distribution between 0 and 1.
* @param TotNumber number generated events
* @param mean mean of the distribution
* @param width width of the distribution
*/
public void fillRnd(int TotNumber, double mean, double width) {
java.util.Random random = new java.util.Random();
for (int i = 0; i < TotNumber; i++)
h1.fill(width*random.nextDouble()+mean);
}
/**
* Fill histogram from P0I array
*
* @param p0i
* input P0I array
*/
public void fill(P0I p0i) {
for (int i = 0; i < p0i.size(); i++)
h1.fill((double)p0i.get(i));
}
/**
* Get histogram Axis class.
*
* @return Axis used for this histogram.
*/
public IAxis getAxis() {
axis= h1.axis();
return axis;
}
/**
* Get bin centres.
*
* @param index
* bin index
* @return bin centre.
*/
public double binCenter(int index) {
axis= h1.axis();
return axis.binCenter(index);
}
/**
* Get all bin centers in form of array
*
* @return double[] array of bin centers
*/
public double[] binCenters() {
axis= h1.axis();
double[] tmp = new double[bins];
for (int i = 0; i < bins; i++)
tmp[i] = axis.binCenter(i);
return tmp;
}
/**
* Get bin lower edge.
*
* @param index
* bin index
* @return lower edge
*/
public double binLowerEdge(int index) {
axis= h1.axis();
return axis.binLowerEdge(index);
}
/**
* Get all lower edges in form of array
*
* @return double[] array of low edges
*/
public double[] binLowerEdges() {
axis= h1.axis();
double[] tmp = new double[bins];
for (int i = 0; i < bins; i++)
tmp[i] = axis.binLowerEdge(i);
return tmp;
}
/**
* Get bin upper edge.
*
* @param index
* bin index
* @return upper edge
*/
public double binUpperEdge(int index) {
axis= h1.axis();
return axis.binUpperEdge(index);
}
/**
* Get all upper edges in form of array
*
* @return double[] array of upper edges
*/
public double[] binUpperEdges() {
axis= h1.axis();
double[] tmp = new double[bins];
for (int i = 0; i < bins; i++)
tmp[i] = axis.binUpperEdge(i);
return tmp;
}
/**
* Write the H1D histogram to a file
*
* @param name
* File name
*/
public void toFile(String name) {
DecimalFormat dfb = new DecimalFormat("##.#####E00");
Date dat = new Date();
String today = String.valueOf(dat);
IAxis axis = h1.axis();
try {
FileOutputStream f1 = new FileOutputStream(new File(name));
PrintStream tx = new PrintStream(f1);
tx.println("# DataMelt: output from H1D " + this.title);
tx.println("# DataMelt: created at " + today);
tx.println("# x, y, error(upper), error(lower)");
tx.println("#");
for (int i = 0; i < axis.bins(); i++) {
String x = dfb.format(h1.binMean(i)); // The weighted mean of
// a bin.
String y = dfb.format(h1.binHeight(i));
String y1 = dfb.format(h1.binError(i));
String y2 = dfb.format(h1.binError(i));
tx.println(x + " " + y + " " + y1 + " " + y2);
}
f1.close();
} catch (IOException e) {
ErrorMessage("Error in the output file");
e.printStackTrace();
}
}
/**
* Create H1D histogram from JAIDA TH1 histogram class
*
* @param h1t
* TH1 histogram from JAIDA
*/
public H1D(TH1 h1t) {
this.title = h1t.getTitle();
setTitle(this.title);
TAxis axis = h1t.getXaxis();
this.min = axis.getXmin();
this.max = axis.getXmax();
h1 = Converter.convert(h1t, this.title);
}
/**
* Sets the content of H1D histogram (heights).
* Keep errors the same. RMS and Mean will be wrong!.
*
* @param values
* array with values in Y (dimension: bins + 2)
*/
public void setHeights(double[] values) {
int ibins = bins + 2;
double[] newHeights = new double[ibins];
double[] newErrors = new double[ibins];
double[] newMeans = new double[ibins];
double[] newRmss = new double[ibins];
int[] newEntries = new int[ibins];
newHeights[0] = getUnderflowHeight();
newHeights[ibins - 1] = getOverflowlowHeight();
for (int i = 0; i < ibins - 1; i++) {
newHeights[i + 1] = values[i]; // h1.binHeight(i);
newErrors[i + 1] = h1.binError(i);
newEntries[i + 1] = h1.binEntries(i);
newMeans[i + 1] = h1.binMean(i);
newRmss[i + 1] = h1.binRms(i);
}
setContents(newHeights, newErrors, newEntries, newMeans, newRmss);
setMeanAndRms(h1.mean(), h1.rms());
}
/**
* Sets errors of H1D histogram (for heights).
* Keep values the same
*
* @param errors
* array with errors in Y (dimension: bins + 2)
*/
public void setErrors(double[] errors) {
int ibins = bins + 2;
double[] newHeights = new double[ibins];
double[] newErrors = new double[ibins];
double[] newMeans = new double[ibins];
double[] newRmss = new double[ibins];
int[] newEntries = new int[ibins];
newHeights[0] = getUnderflowHeight();
newHeights[ibins - 1] = getOverflowlowHeight();
for (int i = 0; i < ibins - 1; i++) {
newHeights[i + 1] = h1.binHeight(i);
newErrors[i + 1] = errors[i]; // h1.binError(i);
newEntries[i + 1] = h1.binEntries(i);
newMeans[i + 1] = h1.binMean(i);
newRmss[i + 1] = h1.binRms(i);
}
setContents(newHeights, newErrors, newEntries, newMeans, newRmss);
setMeanAndRms(h1.mean(), h1.rms());
}
/**
* Sets the content of H1D histogram. Start from 1 to bins+2.
*
* @param values
* array with values in Y (dimension: bins + 2)
* @param errors
* array with errors on Y (dimension: bins + 2)
*/
public void setContents(double[] values, double[] errors) {
h1.setContents(values, errors, null, null, null);
}
/**
* Set the content of the whole Histogram at once. This is a convenience
* method for saving/restoring Histograms. Of the arguments below the
* heights array cannot be null. The errors array should in general be
* non-null, but this depends on the specific binner. The entries array can
* be null, in which case the entry of a bin is taken to be the integer part
* of the height. If the means array is null, the mean is defaulted to the
* geometric center of the bin. If the rms array is null, the rms is taken
* to be the bin width over the root of 12.
*
* @param heights
* The bins heights
* @param errors
* The bins errors
* @param entries
* The bin entries.
* @param means
* The means of the bins.
* @param rmss
* The rmss of the bins
*
*/
public void setContents(double[] heights, double[] errors, int[] entries,
double[] means, double[] rmss) {
h1.setContents(heights, errors, entries, means, rmss);
}
/**
* Sets the Mean and RMS of H1D histogram
*
* @param mean
* mean of the histogram
* @param rms
* RMS to be set
*/
public void setMeanAndRms(double mean, double rms) {
h1.setMeanAndRms(mean, rms);
}
/**
* Sets number of entries of H1D histogram.
*
* @param entries
* Number of entries
*/
public void setNEntries(int entries) {
h1.setNEntries(entries);
}
/**
* Sets number of valid entries.
*
* @param entries
* Number of valid entries
*/
public void setValidEntries(int entries) {
h1.setValidEntries(entries);
}
/**
* Get JAIDA histogram
*
* @return JAIDA Histogram1D histogram
*/
public Histogram1D get() {
return h1;
}
/**
* Set Min value of axis
*
* @param min
* Minimum value of axis
*/
public void setMin(double min) {
this.min = min;
}
/**
* Get Minimum value of the axis
*
* @return Minimum value of the axis
*/
public double getMin() {
return this.min;
}
/**
* Set Maximum value of axis
*
* @param max
* Maximum value of axis
*/
public void setMax(double max) {
this.max = max;
}
/**
* Get Maximum value of axis
*
* @return Maximum value of axis
*/
public double getMax() {
return this.max;
}
/**
* Sets the number of bins
*
* @param bins
* Number of bins
*/
public void setBins(int bins) {
this.bins = bins;
}
/**
* Get the number of bins
*
* @return Number of bins
*/
public int getBins() {
this.bins = h1.axis().bins();
return this.bins;
}
/**
* Get bin width in case of fixed-size bins.
*
* @return bin width (max-min) /bins
**/
public double getBinSize() {
axis = h1.axis();
bins=axis.bins();
min=axis.lowerEdge();
max=axis.upperEdge();
return (max - min) / bins;
}
/**
* Get bin width for index i
*
* @param index of this bin
*
* @return bin width at index
**/
public double getBinSize(int index) {
axis = h1.axis();
return axis.binWidth(index);
}
/**
* Shift all bins by some value
*
* @param d
* parameter used to shift bins
*/
public void shift(double d) {
int ibins = h1.axis().bins() + 2;
double[] newHeights = new double[ibins];
double[] newErrors = new double[ibins];
double[] newMeans = new double[ibins];
double[] newRmss = new double[ibins];
int[] newEntries = new int[ibins];
newHeights[0] = getUnderflowHeight();
newHeights[ibins - 1] = getOverflowlowHeight();
for (int i = 0; i < ibins - 1; i++) {
newHeights[i + 1] = h1.binHeight(i);
newErrors[i + 1] = h1.binError(i);
newEntries[i + 1] = h1.binEntries(i);
newMeans[i + 1] = h1.binMean(i) + d; // shift by d
newRmss[i + 1] = h1.binRms(i);
}
if (axis.isFixedBinning()) {
axis = new FixedAxis(this.bins, min + d, max + d);
} else {
for (int i = 0; i < edges.length; i++) {
edges[i] = edges[i] + d;
axis = new VariableAxis(edges);
}
}
// set it back with new binning
double m = h1.mean() + d;
double r = h1.rms();
h1 = new Histogram1D(this.title, this.title, axis);
h1.setContents(newHeights, newErrors, newEntries, newMeans, newRmss);
setMeanAndRms(m, r);
}
/**
* Return true if bins have constant bin width
*
* @return true if bin width is fixed
*/
public boolean isFixedBinning() {
return axis.isFixedBinning();
}
/**
* Fill histogram with a value
*
* @param value
* Value to be filled
*/
public void fill(double value) {
h1.fill(value);
}
/**
* Fill histogram with values from a PND array. This means that every entry
* from PND contributes to histogram. All weights are 1.
*
* @param pnd
* PND used to fill histogram
**/
public void fill(PND pnd) {
for (int i = 0; i < pnd.size(); i++) {
double[] tt = (double[]) pnd.get(i);
for (int j = 0; j < tt.length; j++)
h1.fill(tt[j]);
}
}
/**
* Fill histograms with values from PND array. Also specify weigths in a
* form of PND. Make sure that both arrays has the size size and dimension.
*
* @param pnd
* input value
* @param weigths
* PND with weights
* */
public void fill(PND pnd, PND weigths) {
if (pnd.size() != weigths.size()) {
System.out
.println("Sizes of input and weight arrays are different!");
return;
}
for (int i = 0; i < pnd.size(); i++) {
double[] tt = (double[]) pnd.get(i);
double[] ww = (double[]) weigths.get(i);
for (int j = 0; j < tt.length; j++)
h1.fill(tt[j], ww[j]);
}
}
/**
* Fill histogram with array of double values
*
* @param values
* array of double values
*/
public void fill(double[] values) {
for (int i = 0; i < values.length; i++)
h1.fill(values[i]);
}
/**
* Fill histogram with array of double values
*
* @param values
* array of double values
*/
public void fill(Cloud1D c1d) {
for (int i = 0; i < c1d.entries(); i++)
h1.fill(c1d.value(i), c1d.weight(i));
}
/**
* Fill histogram with array of double values. Take into account weights.
*
* @param values
* array of double values
* @param weights
* array of double weights
*/
public void fill(double[] values, double[] weights) {
for (int i = 0; i < values.length; i++)
h1.fill(values[i], weights[i]);
}
/**
* Fill histogram with array of integer values
*
* @param values
* array of integer values
*/
public void fill(int[] values) {
for (int i = 0; i < values.length; i++)
h1.fill((double) values[i]);
}
/**
* Fill histogram a with weight
*
* @param value
* Value to be filled
* @param weight
* Weight of the value
*/
public void fill(double value, double weight) {
h1.fill(value, weight);
}
/**
* Get mean of the histogram
*
* @return Mean of histogram
*/
public double mean() {
return h1.mean();
}
/**
* Calculate complete statistics for this histogram.
* Unlike other methods (like mean or rms), it performs calculations
* on the existing histogram, thus the method is somewhat slow.
* It return mean, error on the mean, RMS, variance, standard deviation.
* The key for the output map are: mean, error, rms, variance, stddev etc. Print the keys of this
* map to get the full access to statistics.
*
* @return map representing histogram statistics
*/
public Map getStat(){
Map tmp= new HashMap();
IAxis axis = h1.axis();
Histogram1D h=get();
double sum1=0;
double sum2=0;
double sum3=0;
for (int i = 0; i < axis.bins(); i++) {
double x = h.binMean(i); // Find the midpoint of each interval range.
double y = h.binHeight(i);
sum1=sum1+y; // calculate the total weight or the total number of points
sum2=sum2+x*y; // sum of the data
sum3=sum3+x*x*y; // estimated sum-of-the-squares of the data.
}
double mean=sum2/sum1;
double mean_square=sum3/sum1;
double rms=Math.sqrt(sum3/sum1);
double variance = mean_square - mean*mean;
double stddev=Math.sqrt(variance);
tmp.put("mean", mean);
tmp.put("mean_error", stddev / Math.sqrt(sum1));
tmp.put("rms", rms);
tmp.put("variance", variance);
tmp.put("standardDeviation", stddev);
tmp.put("maxBinHeight", h1.maxBinHeight());
tmp.put("minBinHeight", h1.minBinHeight());
tmp.put("allEntries", (double)h1.allEntries());
tmp.put("entries", (double)h1.entries());
tmp.put("underflowBin", (double)h1.binEntries(IAxis.UNDERFLOW_BIN));
tmp.put("underflowHeight", h1.binHeight(IAxis.UNDERFLOW_BIN));
tmp.put("overflowBin", (double)h1.binEntries(IAxis.OVERFLOW_BIN));
tmp.put("overflowHeight", h1.binHeight(IAxis.OVERFLOW_BIN));
return tmp;
}
/**
* Get RMS of histogram
*
* @return RMS of histogram
*/
public double rms() {
return h1.rms();
}
/**
* Get number of all entries
*
* @return Number of all entries
*/
public int allEntries() {
return h1.allEntries();
}
/**
* Number of under and overflow entries in the histogram.
*
* @return Number of under and overflow entries
*/
public int extraEntries() {
return h1.extraEntries();
}
/**
* Number of in-range entries in the histogram
*
* @return Number of in-range entries
*/
public int entries() {
return h1.entries();
}
/**
* Number of underflow entries
*
* @return Number of underflow
*/
public int getUnderflow() {
return h1.binEntries(IAxis.UNDERFLOW_BIN);
}
/**
* Underflow height
*
* @return height of underflow
*/
public double getUnderflowHeight() {
return h1.binHeight(IAxis.UNDERFLOW_BIN);
}
/**
* Overflow height
*
* @return Height of underflow
*/
public double getOverflowlowHeight() {
return h1.binHeight(IAxis.OVERFLOW_BIN);
}
/**
* Number of overflow entries
*
* @return Number of overflow entries
*/
public int getOverflow() {
return h1.binEntries(IAxis.OVERFLOW_BIN);
}
/**
* Fill histogram with a value, weighting it by inverse of bin size. Should
* be useful for histograms with irregular binning.
*
* @param value
* Value to filled histogram with.
*/
public void fillInvBinSizeWeight(double value) {
int binNum = h1.axis().coordToIndex(value);
h1.fill(value, 1.0 / h1.axis().binWidth(binNum));
}
/**
* Scale the histogram.
*
* @param title
* New title
* @param scaleFactor
* Scale factor
*/
public void scale(String title, double scaleFactor) {
this.title = title;
h1.scale(scaleFactor);
}
/**
* Scale the histogram and return scaled object.
*
* @param title
* New title
* @param scaleFactor
* Scale factor
**/
public H1D operScale(String title, double scaleFactor) {
scale(title, scaleFactor);
return this;
}
/**
* Scale the histogram.
*
* @param scaleFactor
* Scale factor
*/
public void scale(double scaleFactor) {
h1.scale(scaleFactor);
}
/**
* Smooth the histogram.
*
* Each band of the histogram is smoothed by averaging over a moving window
* of a size specified by the method parameter: if the value of the
* parameter is k then the width of the window is 2*k + 1. If
* the window runs off the end of the histogram only those values which
* intersect the histogram are taken into consideration. The smoothing may
* optionally be weighted to favor the central value using a "triangular"
* weighting. For example, for a value of k equal to 2 the central
* bin would have weight 1/3, the adjacent bins 2/9, and the next adjacent
* bins 1/9. Errors are kept the same as before.
*
* @param isWeighted
* Whether bins will be weighted using a triangular weighting
* scheme favoring bins near the central bin.
* @param k
* The smoothing parameter which must be non-negative. If zero,
* the histogram object will be returned with no smoothing
* applied.
* @return A smoothed version of the histogram.
*/
public H1D operSmooth(boolean isWeighted, int k) {
SHisto sh = new SHisto(bins, min, max, 1);
double[] hh = binHeights();
double[] ee = binErrors();
sh.setBins(hh);
sh = sh.getSmoothed(isWeighted, k);
double[] hh1 = new double[bins + 2];
double[] ee1 = new double[bins + 2];
hh1[0] = getUnderflowHeight();
hh1[bins - 1] = getOverflowlowHeight();
for (int i = 1; i < bins + 1; i++) {
hh1[i] = sh.getBinsFirstBand(i - 1);
ee1[i] = ee[i - 1];
// System.out.println(hh1[i]+ " " + ee1[i]);
}
h1.setContents(hh1, ee1, null, null, null);
return this;
}
/**
* Computes a Gaussian smoothed version of the histogram.
*
*
* Each band of the histogram is smoothed by discrete convolution with a
* kernel approximating a Gaussian impulse response with the specified
* standard deviation.
*
* @param standardDeviation
* The standard deviation of the Gaussian smoothing kernel which
* must be non-negative or an
* IllegalArgumentException will be thrown. If zero,
* the histogram object will be returned with no smoothing
* applied.
* @return A Gaussian smoothed version of the histogram.
*
*/
public H1D operSmoothGauss(double standardDeviation) {
SHisto sh = new SHisto(bins, min, max, 1);
double[] hh = binHeights();
double[] ee = binErrors();
sh.setBins(hh);
sh = sh.getGaussianSmoothed(standardDeviation);
double[] hh1 = new double[bins + 2];
double[] ee1 = new double[bins + 2];
hh1[0] = getUnderflowHeight();
hh1[bins - 1] = getOverflowlowHeight();
for (int i = 1; i < bins + 1; i++) {
hh1[i] = sh.getBinsFirstBand(i - 1);
ee1[i] = ee[i - 1];
// System.out.println(hh1[i]+ " " + ee1[i]);
}
h1.setContents(hh1, ee1, null, null, null);
return this;
}
/**
* Returns the entropy of the histogram.
*
*
* The entropy is defined to be the negation of the sum of the products of
* the probability associated with each bin with the base-2 log of the
* probability.
*
* @return The entropy of the histogram.
*
*/
public double getEntropy() {
SHisto sh = new SHisto(bins, min, max, 1);
double[] hh = binHeights();
sh.setBins(hh);
double s[] = sh.getEntropy();
return s[0];
}
/**
* Make a copy of the data holder
*
* @return New data holder
*/
public H1D copy() {
return copy(this.title);
}
/**
* Make a copy of the data holder
*
* @return New data holder
*/
public void clear() {
h1.reset();
}
/**
* Rebin a histogram with constant bin width. This function
* returns a new histogram with the rebinned contents.
* The bin errors are recomputed during the rebinning.
* @param ngroup indicates how many bins of this have to me merged
* into one bin of hnew
* @return a new histogram with rebinned content.
*/
public H1D rebin(int ngroup) {
this.axis = h1.axis();
if (!axis.isFixedBinning()) {
ErrorMessage("Cannot rebin histogram with variable bins");
}
int nbins= (int) ( ( (1.0*axis.bins())/ngroup));
// System.out.println(nbins);
H1D hnew = new H1D(getTitle(),nbins,min,max);
int ibins = nbins + 2;
double[] newHeights = new double[ibins];
double[] newErrors = new double[ibins];
double[] newMeans = new double[ibins];
double[] newRmss = new double[ibins];
int[] newEntries = new int[ibins];
newHeights[0] = getUnderflowHeight();
newHeights[ibins - 1] = getOverflowlowHeight();
for (int i = 0; i < ibins-2; i++) {
double h=0;
double e2=0;
int t=0;
double m=0;
double rms=0;
int start=i*ngroup;
for (int j=start; j<(start+ngroup); j++) {
h += h1.binHeight(j);
t += h1.binEntries(j);
e2 += h1.binError(j)*h1.binError(j);
m += h1.binMean(j);
rms+= h1.binRms(j)*h1.binRms(j);
// System.out.println(j);
}
h=h/ngroup;
e2=Math.sqrt(e2/ngroup);
rms=Math.sqrt(rms/ngroup);
m=m/ngroup;
// System.out.println(h);
newHeights[i + 1] = h;
newErrors[i + 1] = e2;
newEntries[i + 1] = t;
newMeans[i + 1] = m;
newRmss[i + 1] = rms;
}
hnew.setContents(newHeights, newErrors, newEntries, newMeans, newRmss);
hnew.setMeanAndRms(h1.mean(), h1.rms());
// get copy
LinePars lnew = copyLinePars(lpp);
hnew.setDrawOption(lnew);
hnew.setNEntries(entries());
return hnew;
};
/**
* Get exact copy of the current histogram. This makes a new
* object.
*
* @param newtitle
* New title
* @return a new copy of the histogram
*/
public H1D copy(String newtitle) {
int ibins = bins + 2;
double[] newHeights = new double[ibins];
double[] newErrors = new double[ibins];
double[] newMeans = new double[ibins];
double[] newRmss = new double[ibins];
int[] newEntries = new int[ibins];
newHeights[0] = getUnderflowHeight();
newHeights[ibins - 1] = getOverflowlowHeight();
for (int i = 0; i < ibins - 1; i++) {
newHeights[i + 1] = h1.binHeight(i);
newErrors[i + 1] = h1.binError(i);
newEntries[i + 1] = h1.binEntries(i);
newMeans[i + 1] = h1.binMean(i);
newRmss[i + 1] = h1.binRms(i);
}
H1D hnew = new H1D(newtitle, axis);
hnew.setContents(newHeights, newErrors, newEntries, newMeans, newRmss);
hnew.setMeanAndRms(h1.mean(), h1.rms());
// get copy
LinePars lnew = copyLinePars(lpp);
hnew.setDrawOption(lnew);
hnew.setNEntries(entries());
return hnew;
}
/**
* Rescale errors by a some factor.
* This will return a new object.
*
* @param scale
* scale factor used to multiply errors
* @return a new copy of the histogram with rescaled errors on bin content.
*/
public H1D scaleErrors(double scale) {
IAxis a=h1.axis();
int ibins=a.bins()+2;
double[] newHeights = new double[ibins];
double[] newErrors = new double[ibins];
double[] newMeans = new double[ibins];
double[] newRmss = new double[ibins];
int[] newEntries = new int[ibins];
newHeights[0] = getUnderflowHeight();
newHeights[ibins - 1] = getOverflowlowHeight();
for (int i = 0; i < ibins-2; i++) {
newHeights[i + 1] = h1.binHeight(i);
newErrors[i + 1] = h1.binError(i)*scale;
newEntries[i + 1] = h1.binEntries(i);
newMeans[i + 1] = h1.binMean(i);
newRmss[i + 1] = h1.binRms(i);
}
H1D hnew = new H1D(getTitle(), axis);
hnew.setContents(newHeights, newErrors, newEntries, newMeans, newRmss);
hnew.setMeanAndRms(h1.mean(), h1.rms());
// get copy
LinePars lnew = copyLinePars(lpp);
hnew.setDrawOption(lnew);
hnew.setNEntries(entries());
hnew.setMeanAndRms(mean(), rms());
return hnew;
}
/**
* Number of entries in a bin with index i
*
* @param index
* Bin index
* @return Number of entries
*/
public int binEntries(int index) {
return (int) h1.binEntries(index);
}
/**
* Get all entries of the histogram as an array
*
* @return array with histogram entries.
*/
public int[] binEntries() {
int[] hh = new int[bins];
for (int i = 0; i < bins; i++)
hh[i] = (int) h1.binEntries(i);
return hh;
}
/**
* Error on the bin with index i
*
* @param index
* Bin index
* @return Error
*/
public double binError(int index) {
return h1.binError(index);
}
/**
* Height of the corresponding bin
*
* @param index
* Bin index
* @return Bin Height
*/
public double binHeight(int index) {
return h1.binHeight(index);
}
/**
* Get all heights of the histogram as an array
*
* @return array with histogram heights.
*/
public double[] binHeights() {
bins = h1.axis().bins();
double[] hh = new double[bins];
for (int i = 0; i < bins; i++)
hh[i] = h1.binHeight(i);
return hh;
}
/**
* Get all bin errors of the histogram as an array
*
* @return array with histogram errors.
*/
public double[] binErrors() {
bins = h1.axis().bins();
double[] hh = new double[bins];
for (int i = 0; i < bins; i++)
hh[i] = h1.binError(i);
return hh;
}
/**
* Mean in a single bin with index
*
* @param index
* Bin index
* @return Mean value inside of this bin
*/
public double binMean(int index) {
return h1.binMean(index);
}
/**
* RMS of a single bin with index
*
* @param index
* Bin index
* @return RMS of this bin
*/
public double binRms(int index) {
return h1.binRms(index);
}
/**
* Max value of all bins
*
* @return Max value
*/
public double maxBinHeight() {
return h1.maxBinHeight();
}
/**
* Min value of all bins
*
* @return Min value
*/
public double minBinHeight() {
return h1.minBinHeight();
}
/**
* Sum of all heights
*
* @return Sum of all Heights
*/
public double sumAllBinHeights() {
return h1.sumAllBinHeights();
}
/**
* Sum of all heights multiplied by the bin size.
*
* @return Sum of all heights times bin size.
*/
public double integral() {
IAxis a=h1.axis();
int Nbins = a.bins();
return integral(1,Nbins, true);
}
/**
* Convert a coordinate on the axis to a bin number
*
* @param x
* coordinate on axis
* @return index of the corresponding bin
*/
public int findBin(double x) {
return h1.axis().coordToIndex(x);
}
/**
* Integrate a histogram between two bin indices (between 1 and max number)
* The integral is computed as the sum of bin contents in the range
* if the last parameter is false. If it is true, the integral is the sum of
* the bin contents multiplied by the bin width in x.
*
*
* @param BinMin
* Min index for integration starting from 1 (included to
* integration)
* @param BinMax
* Max index for integration (start from 1, included to integration)
* @param timesBinWidth
* If true, the integral is the sum of
* the bin contents multiplied by the bin width in x.
*
* @return integral (sum of all heights)
*/
public double integral(int BinMin, int BinMax, boolean timesBinWidth) {
IAxis a=h1.axis();
int Nbins = a.bins();
if (BinMin > BinMax) {
ErrorMessage("Wrong bin number!");
return -1;
}
if (BinMin < 1 || BinMax > Nbins) {
ErrorMessage("Wrong bin number!");
return -1;
}
double sum = 0.0;
if (timesBinWidth == false){
for (int i = BinMin - 1; i < BinMax; i++) {
sum += h1.binHeight(i);
}
} else {
for (int i = BinMin - 1; i < BinMax; i++) {
double w=a.binUpperEdge(i)-a.binLowerEdge(i);
sum += h1.binHeight(i)*w;
}
}
return sum;
}
/**
* Integrate a histogram between two bin indices (between 1 and max number)
* By default the integral is computed as the sum of bin contents in the range.
*
*
* @param BinMin
* Min index for integration starting from 1 (included to
* integration)
* @param BinMax
* Max index for integration (included to integration)
* @return integral (sum of all heights)
*/
public double integral(int BinMin, int BinMax) {
return integral(BinMin, BinMax,false);
}
/**
* Integrate histogram in a region between Xmin and Xmax.
* This will sum up all bin content between the regions.
*
* @param Xmin
* Min index for integration
* @param Xmax
* Max index for integration
* @param timesBinWidth
* if true, multiply by the bin width.
* @return integral (sum of all heights)
*/
public double integralRegion(double xmin, double xmax, boolean timesBinWidth) {
int Nbins = h1.axis().bins();
int xmi = h1.axis().coordToIndex(xmin);
int xma = h1.axis().coordToIndex(xmax);
if (xmi > xma) {
ErrorMessage("Wrong bin number!");
return -1;
}
if (xmi < 1 || xma > Nbins) {
ErrorMessage("Wrong bin number!");
return -1;
}
return integral(xmi, xma, timesBinWidth);
}
/**
* Integrate histogram in a region between Xmin and Xmax.
* This will sum up all bin content between the regions.
*
* @param Xmin
* Min index for integration
* @param Xmax
* Max index for integration
* @return integral (sum of all heights)
*/
public double integralRegion(double xmin, double xmax) {
return integralRegion(xmin, xmax, false);
}
/**
* Return q probability distribution derived from a histogram.
* The histogram is scaled by the sum of all contents.
* @return probability distribution
*/
public H1D getProbability() {
H1D h1d=this.copy();
h1d.scale(1.0/h1d.sumAllBinHeights());
return h1d;
}
/**
* Divide heights of each bin by the bin width.
* Variable bin sizes are supported. Statistics of the histogram
* should be treated with care.
* @return new histogram after the division by bin width.
*/
public H1D getDividedByBinWidth() {
IAxis a=h1.axis();
int ibins=a.bins()+2;
double[] newHeights = new double[ibins];
double[] newErrors = new double[ibins];
double[] newMeans = new double[ibins];
double[] newRmss = new double[ibins];
int[] newEntries = new int[ibins];
newHeights[0] = getUnderflowHeight();
newHeights[ibins - 1] = getOverflowlowHeight();
// double sum=sumAllBinHeights();
for (int i = 0; i < ibins-2; i++) {
double w=(a.binUpperEdge(i)-a.binLowerEdge(i));
newHeights[i + 1] = h1.binHeight(i)/w;
newErrors[i + 1] = h1.binError(i)/w;
newEntries[i + 1] = h1.binEntries(i);
newMeans[i + 1] = h1.binMean(i);
newRmss[i + 1] = h1.binRms(i);
// System.out.println(i);
// System.out.println(h1.binHeight(i)/w);
// System.out.println(w);
}
H1D hnew = new H1D(getTitle(), axis);
hnew.setContents(newHeights, newErrors, newEntries, newMeans, newRmss);
hnew.setMeanAndRms(h1.mean(), h1.rms());
// get copy
LinePars lnew = copyLinePars(lpp);
hnew.setDrawOption(lnew);
hnew.setNEntries(entries());
hnew.setMeanAndRms(mean(), rms());
return hnew;
}
/**
* Get a density distribution dividing each bin of the histogram
* by the bin width and the total number of heights for all bins.
* Variable bin sizes are supported. Statistics of the histogram
* should be treated with care. This disreibution is normalized to 1.
* @return new histogram with density distribution
*/
public H1D getDensity() {
IAxis a=h1.axis();
int ibins=a.bins()+2;
double[] newHeights = new double[ibins];
double[] newErrors = new double[ibins];
double[] newMeans = new double[ibins];
double[] newRmss = new double[ibins];
int[] newEntries = new int[ibins];
newHeights[0] = getUnderflowHeight();
newHeights[ibins - 1] = getOverflowlowHeight();
double sum=sumAllBinHeights();
for (int i = 0; i < ibins-2; i++) {
double w=sum*(a.binUpperEdge(i)-a.binLowerEdge(i));
newHeights[i + 1] = h1.binHeight(i)/w;
newErrors[i + 1] = h1.binError(i)/w;
newEntries[i + 1] = h1.binEntries(i);
newMeans[i + 1] = h1.binMean(i);
newRmss[i + 1] = h1.binRms(i);
// System.out.println(i);
// System.out.println(h1.binHeight(i)/w);
// System.out.println(w);
}
H1D hnew = new H1D(getTitle(), axis);
hnew.setContents(newHeights, newErrors, newEntries, newMeans, newRmss);
hnew.setMeanAndRms(h1.mean(), h1.rms());
// get copy
LinePars lnew = copyLinePars(lpp);
hnew.setDrawOption(lnew);
hnew.setNEntries(entries());
hnew.setMeanAndRms(mean(), rms());
return hnew;
}
/**
* Compare the histogram with a function. The comparison tests hypotheses that
* the histogram represent identical distribution with a function using Pearson's chi-squared test.
* The number chi2/ndf gives the estimate (values close to 1 indicates
* similarity between 2 histograms.). the function and histogram are identical if chi2=0.
* Chi2/ndf and p-value probability is 1. Maken sure that statistical errors are included correctly.
* Data with zero errors will be ignored.
* @param f1
* function to compare to.
* @return map with the result. It gives Chi2, gives number
* of degrees of freedom (ndf), probability
* ("quality", or p-value).
*/
public Map compareChi2(F1D f1) {
Map tmp= new HashMap();
int bins1 = get().axis().bins();
double sum1 = 0;
double nDf = 0;
for (int i = 0; i < bins1; i++) {
double bin1 = binHeight(i);
double e1 = binError(i);
double x1=get().axis().binLowerEdge(i);
double x2=get().axis().binUpperEdge(i);
double delta=x2-x1;
double x=x1+0.5*delta;
double ff=f1.eval(x);
if (e1 != 0) {
sum1=sum1+((ff-bin1)*(ff-bin1) / (e1*e1));
nDf++;
}
}
double chi2=sum1;
tmp.put("chi2", chi2);
tmp.put("ndf", (double)nDf);
org.apache.commons.math3.distribution.ChiSquaredDistribution chi2Distribution = new org.apache.commons.math3.distribution.ChiSquaredDistribution(
nDf);
double prob = chi2Distribution.cumulativeProbability(chi2);
tmp.put("p-value", 1.0-prob);
return tmp;
}
/**
* Compare two histograms. Comparison of two histograms test hypotheses that
* two histograms represent identical distributions. It calculates Chi2
* between 2 histograms taking into account errors on the heights of the
* bins. The number chi2/ndf gives the estimate (values close to 1 indicates
* similarity between 2 histograms.) Two histograms are identical if chi2=0.
* Chi2/ndf and p-value probability is 1.
* Make sure that both histograms have error (or set them to
* small values).
*
* @param h2
* second histogram to compare to.
* @return map with the result. It gives Chi2, gives number
* of degrees of freedom (ndf), probability
* ("quality", or p-value).
*/
public Map compareChi2(H1D h2) {
Map tmp= new HashMap();
int bins1 = get().axis().bins();
int bins2 = h2.get().axis().bins();
if (bins1 != bins2) {
System.out
.println("Different histograms! Please use histograms with the same bin numbers");
return tmp;
}
double chi2 = 0;
int nDf = 0;
double sum1 = 0;
double sum2 = 0;
double sumw1 = 0;
double sumw2 = 0;
for (int i = 0; i < bins1; i++) {
double bin1 = binHeight(i);
double bin2 = h2.binHeight(i);
double e1 = binError(i);
double e2 = h2.binError(i);
if (e1 > 0) {
bin1 *= bin1 / (e1 * e1);
} else
bin1 = 0;
if (e2 > 0) {
bin2 *= bin2 / (e2 * e2);
} else
bin2 = 0;
// sum contents
sum1 += bin1;
sum2 += bin2;
sumw1 += e1 * e1;
sumw2 += e2 * e2;
}
//double sum = sum1 + sum2;
if (sumw1 <= 0 || sumw2 <= 0) {
System.out
.println("Cannot compare histograms with all zero errors");
return tmp;
}
if (sum1 == 0 || sum2 == 0) {
System.out.println("One histogram is empty!");
return tmp;
}
for (int i = 0; i < bins1; i++) {
double bin1 = binHeight(i);
double bin2 = h2.binHeight(i);
double e1 = binError(i);
double e2 = h2.binError(i);
// System.out.println(Double.toString(bin1)+" - "+Double.toString(bin2));
if (e1 > 0)
bin1 *= bin1 / (e1 * e1);
else
bin1 = 0;
if (e2 > 0)
bin2 *= bin2 / (e2 * e2);
else
bin2 = 0;
double binsum = bin1 + bin2;
double delta = sum2 * bin1 - sum1 * bin2;
if (binsum > 0) {
chi2 += delta * delta / binsum;
// System.out.println(chi2);
nDf++;
}
}
chi2 /= (sum1 * sum2);
tmp.put("chi2", chi2);
tmp.put("ndf", (double)nDf);
org.apache.commons.math3.distribution.ChiSquaredDistribution chi2Distribution = new org.apache.commons.math3.distribution.ChiSquaredDistribution(
nDf);
double prob = chi2Distribution.cumulativeProbability(chi2);
tmp.put("p-value", 1.0-prob);
return tmp;
}
/**
* Various manipulations with histograms (+,-,*,/). Keep the original title.
* No new histogram object created.
*
* @param a
* H1D histogram.
* @param what
* String representing the operation: "+" add a histogram to the
* original "-" subtract a histogram from the original "*"
* multiply "/" divide
* @return modified H1D histogram
*/
public H1D oper(H1D a, String what) {
return oper(a, getTitle(), what);
}
/**
* Get positions in X,Y and Errors. For x, we take mean values
*
* @param mode
* if =1, take center of the bins. In all other cases - mean
* value in each bin
*
* @return array with X,Y, and Error on Y, double[3][bins];
*/
public double[][] getValues(int mode) {
// create the array of references of size 3
double[][] nums = new double[3][];
// this create the second level of arrays (red squares)
for (int i = 0; i < 3; i++)
nums[i] = new double[bins]; // create arrays of integers
for (int i = 0; i < bins; i++) {
nums[0][i] = binMean(i);
if (mode == 1)
nums[0][i] = binCenter(i);
nums[1][i] = binHeight(i);
nums[2][i] = binError(i);
}
return nums;
}
/**
* Various manipulations with histograms (+,-,*,/). Note: no new object will
* be created.
*
* @param a
* H1D histogram.
* @param title
* New Title
*
* @return same H1D object but modified
*/
public H1D oper(H1D a, String title, String what) {
IAnalysisFactory af = IAnalysisFactory.create();
IHistogramFactory hf = af.createHistogramFactory(af.createTreeFactory()
.create());
// first check them
if (what.equals("+")) {
IHistogram1D hnew = hf.add(title, get(), a.get());
return new H1D(hnew);
}
if (what.equals("-")) {
IHistogram1D hnew = hf.subtract(title, get(), a.get());
return new H1D(hnew);
}
if (what.equals("*")) {
IHistogram1D hnew = hf.multiply(title, get(), a.get());
return new H1D(hnew);
}
if (what.equals("/")) {
IHistogram1D hnew = hf.divide(title, get(), a.get());
return new H1D(hnew);
}
ErrorMessage("Operation \"" + what + "\" is not implemented");
return this;
}
/**
* Get statistical parameters of a Histogram as a list of strings
* @param h1 histogram H1D
* @return list of with mean, RMS etc.
*/
public String[] getStatParameters() {
double mean = h1.mean();
double rms = h1.rms();
DecimalFormat dfb = new DecimalFormat("##.###E00");
String name = getTitle();
String sentries = "Entries =" + Integer.toString(h1.entries());
String smean = "Mean =" + dfb.format(mean);
String srms = "RMS =" + dfb.format(rms);
String extra = "Under/Overflow =" + Integer.toString(h1.extraEntries());
String[] s = { name, sentries, smean, srms, extra };
return s;
}
/**
* Generate error message
*
* @param a
* Message
*/
private void ErrorMessage(String a) {
jhplot.utils.Util.ErrorMessage(a);
}
/**
* Show online documentation.
*/
public void doc() {
String a = this.getClass().getName();
a = a.replace(".", "/") + ".html";
new HelpBrowser(HelpBrowser.JHPLOT_HTTP + a);
}
}