Java tutorial
/** * 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 <http://www.gnu.org/licenses>. * * 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 <https://www.gnu.org/licenses/lgpl.html>), * 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. <p> * The key for the output <b>map are: mean, error, rms, variance, stddev etc. Print the keys of this * map to get the full access to statistics</b>. * * @return map representing histogram statistics */ public Map<String, Double> getStat() { Map<String, Double> tmp = new HashMap<String, Double>(); 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. * <p> * 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 <i>k</i> then the width of the window is <i>2*k + 1</i>. 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 <i>k</i> 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. * * <p> * 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 * <code>IllegalArgumentException</code> 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. * * <p> * 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<String, Double> compareChi2(F1D f1) { Map<String, Double> tmp = new HashMap<String, Double>(); 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<String, Double> compareChi2(H1D h2) { Map<String, Double> tmp = new HashMap<String, Double>(); 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); } }