package org.jlab.groot.data;
import org.jlab.groot.base.DatasetAttributes;
import org.jlab.groot.base.GStyle;
import org.jlab.groot.math.Axis;
import org.jlab.groot.math.Func1D;
import org.jlab.groot.math.StatNumber;
import org.jlab.groot.ui.PaveText;
/**
* Defines the class to create a basic 1D Histogram
*
* @author Erin Kirby
* @version 062614
*/
public class H1F implements IDataSet {
Axis xAxis;
Axis yAxis;
float[] histogramData;
float[] histogramDataError;
String histName = "";
int histogramUnderFlow = 0;
int histogramOverFlow = 0;
int histogramEntries = 0;
DatasetAttributes hAttr = new DatasetAttributes(DatasetAttributes.HISTOGRAM);
Func1D fittedFunction = null;
/**
* The default constructor, which creates a Histogram1D object with the Name "default",
* the Title "default", no Axis titles, and sets the minimum xAxis value to 0, the maximum x
* value to 1, and creates 1 bin.
*/
public H1F() {
setName("default");
setTitle("default");
set(1,0.0,1.0);
initDataStore(1);
this.initAttributes();
}
/**
* Creates a Histogram1D object using the specified name, axis titles, number of bins,
* and minimum and maximum x axis values.
*
* @param hName the desired name of the 1-D Histogram
* @param xTitle the desired x-axis title
* @param yTitle the desired y-axis title
* @param bins the desired number of bins
* @param xMin the desired minimum value on the x axis
* @param xMax the desired maximum value on the x axis
*/
public H1F(String hName, String xTitle, String yTitle, int bins, double xMin, double xMax) {
setName(hName);
set(bins, xMin, xMax);
initDataStore(bins);
this.initAttributes();
setTitleX(xTitle);
setTitleY(yTitle);
}
/**
* Creates a 1-D Histogram with the specified name, minimum and maximum x-axis values,
* and the bin heights
*
* @param name the desired name of the histogram
* @param xMin the desired minimum x-axis value
* @param xMax the desired maximum x-axis value
* @param binHeights a double array of the heights of the bins
*/
public H1F(String name, double xMin, double xMax, float[] binHeights) {
setName(name);
set(binHeights.length, xMin, xMax);
for (int i = 0; i < binHeights.length; i++) {
histogramData[i] = binHeights[i];
}
this.initAttributes();
}
/**
* Creates a 1-D Histogram with the specified name, number of bins, and minimum and maximum
* x-axis values
*
* @param name The desired name of the histogram
* @param bins The desired number of bins
* @param xMin The desired minimum x-axis value
* @param xMax The desired maximum x-axis value
*/
public H1F(String name, int bins, double xMin, double xMax) {
setName(name);
set(bins, xMin, xMax);
this.initAttributes();
}
/**
* Creates a 1-D Histogram with the specified name, title, number of bins, and minimum
* and maximum x-axis values
*
* @param name The desired name of the histogram
* @param title The desired title of the histogram
* @param bins The desired number of bins
* @param xMin The desired minimum x-axis value
* @param xMax The desired maximum x-axis value
*/
public H1F(String name, String title, int bins, double xMin, double xMax) {
setName(name);
setTitle(title);
set(bins, xMin, xMax);
this.initAttributes();
}
/**
* Creates a new histogram using the name, title, minimum, and maximum.
*
* @param name The desired name of the histogram
* @param title The desired title of the histogram
* @param xMin The desired minimum x-axis value
* @param xMax The desired maximum x-axis value
*/
public H1F(String name, String title, double xMin, double xMax) {
setName(name);
setTitle(title);
set((int)(xMax - xMin), xMin, xMax);
this.initAttributes();
}
public final void initAttributes(){
try {
this.hAttr = GStyle.getH1FAttributes().clone();
} catch (CloneNotSupportedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public final void setTitle(String title){
this.hAttr.setTitle(title);
}
/**
* Sets the x-axis title to the specified parameter
* @param xTitle The desired title of the x-axis
*/
public final void setTitleX(String xTitle) {
this.hAttr.setTitleX(xTitle);
//this.getXaxis().setTitle(xTitle);
//this.hAttr.addString(AttributeType.STRING_TITLE_X, xTitle);
}
/**
* Sets the y-axis title to the specified parameter
*
* @param yTitle The desired title of the y-axis
*/
public final void setTitleY(String yTitle) {
this.hAttr.setTitleY(yTitle);
//this.getYaxis().setTitle(yTitle);
//this.hAttr.addString(AttributeType.STRING_TITLE_Y, yTitle);
}
public static H1F create(String name, int bins, DataVector vec, DataVector weight){
double min = vec.getMin();
double max = vec.getMax();
if(min==max){
min = .9999*min;
max = 1.0001*max;
}
H1F h = new H1F(name,"",bins,min,max);
for(int i = 0; i < vec.getSize(); i++){
h.fill(vec.getValue(i), weight.getValue(i));
}
h.setFillColor(43);
return h;
}
public static H1F create(String name, int bins, DataVector vec){
double min = vec.getMin();
double max = vec.getMax();
if(min==max){
min = .9999*min;
max = 1.0001*max;
}
H1F h = new H1F(name,"",bins,min,max);
for(int i = 0; i < vec.getSize(); i++){
h.fill(vec.getValue(i));
}
h.setFillColor(43);
return h;
}
/**
* The getter for the histogram title.
* @return Title of the histogram.
*/
public String getTitle(){
return this.hAttr.getTitle();
}
/**
* The getter for the x-axis title.
*
* @return The title of the x-axis as a string
*/
public String getTitleX() {
return this.hAttr.getTitleX();
}
/**
* The getter for the y-axis title.
*
* @return The title of the y-axis as a string
*/
public String getTitleY() {
return this.hAttr.getTitleY();
}
/**
* Sets the specified parameter as the name of the histogram
*
* @param name The desired name of the histogram
*/
@Override
public final void setName(String name) {
histName = name;
}
/**
* Resets all bins to 0
*/
@Override
public void reset(){
this.histogramEntries = 0;
this.histogramOverFlow = 0;
this.histogramUnderFlow = 0;
for(int loop = 0; loop < this.histogramData.length;loop++){
this.histogramData[loop] = 0.0f;
if(this.histogramDataError.length==this.histogramData.length){
this.histogramDataError[loop] = 0.0f;
}
}
}
public int getEntries(){
int entries = 0;
for(int loop = 0; loop < this.histogramData.length; loop++){
entries += (int) this.histogramData[loop];
}
return histogramEntries;
}
/**
* Calculates the mean of the data in the histogram
*
* @return the mean of the histogram data as a double
*/
public double getMean() {
double mean = 0.0;
double summ = 0.0;
double count = 0;
for(int i = 0; i < this.getAxis().getNBins(); i++){
double bincontent = this.getBinContent(i);
//System.err.println(" bin count = " + count + " content summ = " + bincontent);
if(bincontent!=0){
summ += this.getAxis().getBinCenter(i)*this.getBinContent(i);
count += this.getBinContent(i);
}
}
if(count!=0){
mean = summ/count;
}
return mean;
}
public String[] getStatText(){
String[] lines = new String[4];
lines[0] = this.histName;
lines[1] = String.format("%-14s %9d", "Entries",this.getEntries());
lines[2] = String.format("%-14s %9.4f", "Mean",this.getMean());
lines[3] = String.format("%-14s %9.4f", "RMS",this.getRMS());
//lines[1] =;
return lines;
}
/**
* Calculates the root mean square of the histogram data
*
* @return the root mean square of the histogram data
*/
public double getRMS() {
double mean = this.getMean();
double rms = 0.0;
double summ = 0.0;
int count = 0;
for(int i = 0; i < this.getAxis().getNBins(); i++){
int bincontent = (int) this.getBinContent(i);
if(bincontent!=0){
double variance = this.getAxis().getBinCenter(i) - mean;
summ += variance*variance*this.getBinContent(i);
count += (int) this.getBinContent(i);
}
}
if(count!=0) {
rms = summ/count;
return Math.sqrt(rms);
}
return rms;
}
/**
* Sets the specified number of bins, min and max to the x axis
* and creates a standard Y axis with a min value of 0 and a max value
* of 0. Additionally, sets up the axes to store data.
*
* @param bins the desired number of bins.
* @param min the desired minimum x value
* @param max the desired maximum y value
*/
public final void set(int bins, double min, double max) {
xAxis = new Axis(bins, min, max);
yAxis = new Axis();
initDataStore(bins);
}
public double getIntegral(){
return integral();
}
public double integral(){
return this.integral(0, this.histogramData.length-1);
}
public double integral(int start_bin, int end_bin){
double integral = 0.0;
for(int loop = start_bin; loop <= end_bin; loop++){
integral += this.histogramData[loop];
}
return integral;
}
/**
* Initializes the double arrays for the histogram data and data errors.
*
* @param size the number of data points to store
*/
final void initDataStore(int size)
{
histogramData = new float[size];
histogramDataError = new float[size];
}
/**
* Increments the bin corresponding to that value by 1
*
* @param value the value to increment
*/
public void fill(double value) {
incrementBinContent(xAxis.getBin(value));
}
/**
* Increments the bin corresponding to that value by that weight
*
* @param value the value to increment
* @param weight the weight to increment by
*/
public void fill(double value, double weight) {
incrementBinContent(xAxis.getBin(value), weight);
}
/**
* Normalizes the histogram data to the specified number
*
* @param number the value to normalize the data to
*/
public void normalize(double number) {
for(int i = 0; i < histogramData.length; i++)
{
histogramData[i] /= number;
}
}
/**
* Increments the content in the specified bin by one. The bin is specified in array indexing
* format (to increment the 1st bin, enter 0, the 2nd, enter 1, ... , the nth, enter n-1)
*
* @param bin the bin to be incremented, specified in array indexing format.
*/
public void incrementBinContent(int bin) {
this.histogramEntries++;
if (bin >= 0 && bin < histogramData.length) {
histogramData[bin] = (float) (histogramData[bin] + 1.0);
histogramDataError[bin] = (float) Math.sqrt(Math.abs(histogramData[bin]));
} else {
if(bin<0){
this.histogramUnderFlow++;
} else {
this.histogramOverFlow++;
}
}
}
/**
* Increments the content in the specified bin by the entered weight. The bin is specified in array indexing
* format (to increment the 1st bin, enter 0, the 2nd, enter 1, ... , the nth, enter n-1)
*
* @param bin the bin to be incremented, specified in array indexing format.
* @param weight the weight to increment by
*/
public void incrementBinContent(int bin, double weight) {
this.histogramEntries++;
if (bin >= 0 && bin < histogramData.length) {
histogramData[bin] = (float) (histogramData[bin] + weight);
histogramDataError[bin] = (float) Math.sqrt(Math.abs(histogramData[bin]));
} else {
if(bin<0){
this.histogramUnderFlow++;
} else {
this.histogramOverFlow++;
}
}
}
public void modify(DataVector vec, double rmin, double rmax){
int nbins = xAxis.getNBins();
xAxis.set(nbins, rmin, rmax);
this.reset();
for(int loop = 0; loop < vec.getSize(); loop++){
this.fill(vec.getValue(loop));
}
}
public void fill(DataVector vec){
for(int loop = 0; loop < vec.getSize(); loop++){
this.fill(vec.getValue(loop));
}
}
public void fill(DataVector vec, DataVector weight){
for(int loop = 0; loop < vec.getSize(); loop++){
this.fill(vec.getValue(loop),weight.getValue(loop));
}
}
public void add(H1F h){
if(h.getAxis().getNBins()==this.getXaxis().getNBins()){
for(int loop = 0; loop < this.histogramData.length; loop++){
this.setBinContent(loop, this.getBinContent(loop)+h.getBinContent(loop));
}
} else {
System.out.println("[warning] ---> histograms have different bin number. not added.");
}
}
public void divide(double number){
for(int i = 0; i < this.getAxis().getNBins(); i++)
{
this.histogramData[i] = (float) (this.histogramData[i]/number);
}
}
/**
* Static method for H1D to divide two histograms, the resulting
* histogram is created, and arguments are untouched.
* @param h1
* @param h2
* @return
*/
public static H1F divide(H1F h1, H1F h2){
if(h1.getXaxis().getNBins()!=h2.getXaxis().getNBins()){
System.out.println("[H1D::divide] error : histograms have inconsistent bins");
return null;
}
H1F h1div = new H1F(h1.getName()+"_DIV_"+h2.getName(),
h1.getXaxis().getNBins(),
h1.getXaxis().min(),h1.getXaxis().max());
StatNumber result = new StatNumber();
StatNumber denom = new StatNumber();
for(int bin = 0; bin < h1.getXaxis().getNBins(); bin++){
result.set(h1.getBinContent(bin), h1.getBinError(bin));
denom.set(h2.getBinContent(bin), h2.getBinError(bin));
result.divide(denom);
h1div.setBinContent(bin, result.number());
h1div.setBinError(bin, result.error());
}
return h1div;
}
/**
* Adds two histograms. Returns a new histogram.
* @param h1 first histogram
* @param h2 second histogram
* @return sum of two histograms
*/
public static H1F add(H1F h1, H1F h2){
if(h1.getXaxis().getNBins()!=h2.getXaxis().getNBins()){
System.out.println("[H1D::divide] error : histograms have inconsistent bins");
return null;
}
H1F h1div = new H1F(h1.getName()+"_ADD_"+h2.getName(),
h1.getXaxis().getNBins(),
h1.getXaxis().min(),h1.getXaxis().max());
StatNumber result = new StatNumber();
StatNumber denom = new StatNumber();
for(int bin = 0; bin < h1.getXaxis().getNBins(); bin++){
result.set(h1.getBinContent(bin), h1.getBinError(bin));
denom.set(h2.getBinContent(bin), h2.getBinError(bin));
result.add(denom);
h1div.setBinContent(bin, result.number());
h1div.setBinError(bin, result.error());
}
return h1div;
}
/**
* returns a new histogram with a content of h1 where the integral is normalized
* to histogram h2.
* @param h1 histogram to normalize
* @param h2 histogram for normalization
* @return histogram with bin content of h1 normalized to h2 integral
*/
public static H1F normalized(H1F h1, H1F h2){
H1F h1norm = new H1F(h1.getName()+"_NORM_"+h2.getName(),
h1.getXaxis().getNBins(),
h1.getXaxis().min(),h1.getXaxis().max());
double integral_h1 = h1.integral();
double integral_h2 = h2.integral();
double ratio = integral_h2/integral_h1;
for(int bin = 0; bin < h1.getXaxis().getNBins(); bin++){
h1norm.setBinContent(bin, h1.getBinContent(bin)*ratio);
}
return h1norm;
}
/**
* Divides the current histogram object by the parameter 1-D histogram.
* Requires that both histograms have the same number of bins.
*
* @param hist the 1-D histogram object to divide the current object by
*/
public void divide(H1F hist) {
if(hist.getAxis().getNBins() !=this.getAxis().getNBins())
{
System.out.println("ERROR: inconsistent bins in histograms");
return;
}
StatNumber result = new StatNumber();
StatNumber hdiv = new StatNumber();
for(int i = 0; i < this.getAxis().getNBins(); i++)
{
result.set(this.getBinContent(i), this.getBinError(i));
hdiv.set(hist.getBinContent(i), hist.getBinError(i));
result.divide(hdiv);
this.setBinContent(i, result.number());
this.setBinError(i, result.error());
}
}
/**
* Sets the value to the specified bin. The bin is specified in array indexing format
* (i.e. to set the value to the 1st bin, enter 0, to the 2nd bin, enter 1, ... ,
* the nth bin, enter n-1)
*
* @param bin the bin to enter the value into, specified in array indexing format
* @param value the value to store in the specified bin
*/
public void setBinContent(int bin, double value) {
if ((bin >= 0) && (bin < histogramData.length)) {
histogramData[bin] = (float) value;
histogramDataError[bin] = (float) Math.sqrt(Math.abs(histogramData[bin]));
} else {
if(bin<0){
this.histogramUnderFlow++;
} else {
this.histogramOverFlow++;
}
}
}
/**
* returns a copy of the histogram with different name.
* @param name
* @return
*/
public H1F histClone(String name){
H1F hclone = new H1F(name, this.getTitleX(), this.getTitleY(),
this.xAxis.getNBins(),this.xAxis.min(),this.xAxis.max());
for(int loop = 0; loop < this.xAxis.getNBins(); loop++){
hclone.setBinContent(loop, this.getBinContent(loop));
hclone.setBinError(loop, this.getBinError(loop));
}
return hclone;
}
/**
* Sets the bin error to the specified bin. The bin is specified in array indexing format
* (i.e. to set the value to the 1st bin, enter 0, to the 2nd bin, enter 1, ... ,
* the nth bin, enter n-1)
*
* @param bin the bin to enter the value of the error into, specified in array indexing format
* @param value the error to store in the specified bin
*/
public void setBinError(int bin, double value) {
if (bin >= 0 && bin < histogramDataError.length) {
histogramDataError[bin] = (float) value;
}
}
/**
* Returns the content of the specified bin as a double. The bin is defined in array indexing
* format (i.e. to retrieve the 1st bin's content, enter 0, for the 2nd bin, enter 1, ... ,
* for the nth bin, enter n-1)
*
* @param bin The bin to retrieve the content of, specified in array indexing format
* @return The content of the bin entered as a parameter
*/
public double getBinContent(int bin) {
if ((bin >= 0) && (bin < histogramData.length)) {
return histogramData[bin];
}
return 0.0;
}
/**
*Returns the error of the specified bin as a double. The bin is defined in array indexing
* format (i.e. to retrieve the 1st bin's error, enter 0, for the 2nd bin, enter 1, ... ,
* for the nth bin, enter n-1)
*
* @param bin The bin to retrieve the error of, specified in array indexing format
* @return The error of the bin entered as a parameter
*/
public double getBinError(int bin) {
if(bin >= 0 && bin < histogramDataError.length) {
return histogramDataError[bin];
}
return 0.0;
}
public Axis getXaxis(){return this.xAxis;}
public Axis getYaxis(){ return this.yAxis;}
/**
* Retrieves the x-axis as an Axis object
*
* @return the x-axis of the histogram as an Axis object
*/
public Axis getxAxis() {
return xAxis;
}
/**
* Retrieves the y-axis as an Axis object
*
* @return the y-axis of the histogram as an Axis object
*/
public Axis getyAxis() {
return yAxis;
}
/**
* Retrieves the x-axis as an Axis object
*
* @return the x-axis of the histogram as an Axis object
*/
public Axis getAxis() {
return xAxis;
}
/**
* Overrides the toString method of type Object
*
* @return a formatted string representation of the content in the histogram
*/
@Override
public String toString() {
StringBuilder buffer = new StringBuilder();
for(int i = 0; i < xAxis.getNBins(); i++) {
buffer.append(String.format("%12.6f %12.6f %12.6f\n",
xAxis.getBinCenter(i),this.getBinContent(i),
this.getBinError(i)));
}
return buffer.toString();
}
/**
* Retrieves a graph of the histogram
*
* @return a DataPoints object of the histogram data
*/
public GraphErrors getGraph(){
//GraphErrors graph = new GraphErrors(this.getAxis().getBinCenters(),
// this.getData());
GraphErrors graph = new GraphErrors();
int npoints = this.getDataSize(0);// this.getDataSize();
for(int loop = 0; loop < npoints; loop++){
graph.addPoint(this.getDataX(loop), this.getDataY(loop),
this.getDataEX(loop)/2.0,this.getDataEY(loop));
}
return graph;
}
/*
public DataPoints getGraph() {
DataPoints graph = new DataPoints(this.histName+"_graph",this.histXTitle,this.histYTitle);
int npoints = this.getAxis().getNBins();
graph.set(npoints);
for(int i = 0; i < npoints; i++) {
graph.setPoint(i,
this.getAxis().getBinCenter(i),
this.getBinContent(i));
}
return graph;
}*/
/**
*
* @return the data in the histogram
*/
public float[] getData() {
return histogramData;
}
/**
*
* @return the data error in the histogram
*/
public float[] getDataError() {
return histogramDataError;
}
/**
* Returns bin number with maximum entries.
* @return
*/
public int getMaximumBin(){
int bin = 0;
double max = this.histogramData[0];
for(int loop = 0; loop < this.histogramData.length; loop++){
if(this.histogramData[loop]>max){
max = this.histogramData[loop];
bin = loop;
}
}
return bin;
}
/**
* Changes the bin widths to vary with a set minimum slope to
* be allowed as its own bin.
*
* @param sensitivity what percentage of the maximum slope
* all bins have to be at minimum to be
* considered its own distinct bin
*/
public void fixBinWidths(double sensitivity) {
double maxSlope = Math.abs(histogramData[1] - histogramData[0]);
for (int i = 1; i < histogramData.length - 1; i++) {
double slope = Math.abs(histogramData[i+1] - histogramData[i]);
if (slope > maxSlope) {
maxSlope = slope;
}
}
double minSlope = maxSlope * sensitivity; //allows bin slope to
//be as little as that
//magnitude of the max
double[] histData = new double[histogramData.length];
double[] histMargins = new double[xAxis.axisMargins.length];
for (int i = 0; i < histData.length; i++) {
histData[i] = -1.0;
}
histData[0] = histogramData[0];
histMargins[0] = xAxis.axisMargins[0];
int index = 0;
for (int i = 0; i < histogramData.length - 1; i++) {
if (Math.abs(histogramData[i+1] - histogramData[i]) < minSlope) {
if (histData[index] == -1.0) {
histData[index] = 0.0;
}
histData[index] += histogramData[i+1];
histMargins[index+1] = xAxis.axisMargins[i+2];
}
else {
histData[index+1] = histogramData[i+1];
histMargins[index+1] = xAxis.axisMargins[i+1];
index++;
}
}
set(index + 1, xAxis.min(), xAxis.max());
for (int i = 0; i < histogramData.length; i++) {
setBinContent(i, histData[i]);
xAxis.set(histMargins);
}
for (int i = 0; i < histogramData.length - 1; i++) {
if (Math.abs(histogramData[i+1] - histogramData[i]) < minSlope) {
fixBinWidths(sensitivity);
break;
}
}
}
@Override
public String getName() {
return this.histName;
}
@Override
public int getDataSize(int axis) {
return this.xAxis.getNBins();
}
@Override
public DatasetAttributes getAttributes() {
return this.hAttr;
}
@Override
public double getDataX(int bin) {
double binCenter = this.xAxis.getBinCenter(bin);
return binCenter;
}
@Override
public double getDataY(int bin) {
return this.histogramData[bin];
}
@Override
public double getDataEX(int bin) {
return this.xAxis.getBinWidth(bin);
}
@Override
public double getDataEY(int bin) {
return this.histogramDataError[bin];
}
@Override
public double getData(int xbin, int ybin) {
return 0.0;
}
/**
* ROOT COMPATABILITY Functions
* @param color
* @return
*/
public H1F setFillColor(int color){
this.hAttr.setFillColor(color);
return this;
}
public int getFillColor(){
return this.hAttr.getFillColor();
}
public H1F setLineColor(int color){
this.hAttr.setLineColor(color);
return this;
}
public int getLineColor(){
return this.hAttr.getLineColor();
}
public H1F setLineWidth(int width){
this.hAttr.setLineWidth(width);
return this;
}
public int getLineWidth(){
return this.hAttr.getLineWidth();
}
public void setFunction(Func1D f){
this.fittedFunction = f;
}
public Func1D getFunction(){
return this.fittedFunction;
}
@Override
public PaveText getStatBox() {
PaveText stat = new PaveText(2);
stat.addText("Name",this.getName());
stat.addText("Entries",Integer.toString(this.getEntries()));
stat.addText("Mean",String.format("%.3f", this.getMean()));
stat.addText("RMS",String.format("%.3f", this.getRMS()));
stat.addText("Underflow",Integer.toString(this.histogramUnderFlow));
stat.addText("Overflow",Integer.toString(this.histogramOverFlow));
stat.addText("Integral",String.format("%.3f", this.getIntegral()));
if(this.fittedFunction!=null){
stat.addText("#chi^2/NDF",
String.format("%.3f/%d",
this.fittedFunction.getChiSquare(),this.fittedFunction.getNDF()));
int npars = this.fittedFunction.getNPars();
for(int i = 0; i < npars; i++){
stat.addText(this.fittedFunction.parameter(i).name(),
String.format("%.3f/%.4f",
fittedFunction.parameter(i).value(),
fittedFunction.parameter(i).error()
));
}
}
return stat;
}
public void setOptStat(int i) {
this.hAttr.setOptStat(""+i);
}
public void setOptStat(String i) {
this.hAttr.setOptStat(i);
}
}
Ads help maintain this website.