Java source code of 'jhplot.H1D'

/**
*    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); } }