package org.jlab.groot.data;

import java.util.ArrayList;

import org.jlab.groot.base.DatasetAttributes;
import org.jlab.groot.base.GStyle;
import org.jlab.groot.math.Axis;
import org.jlab.groot.math.MultiIndex;
import org.jlab.groot.ui.PaveText;


/**
 * Specifies the methods to create a 2D Histogram and operations to fill it and
 * set values to its bins
 * 
 * @author Erin Kirby
 * @version 061714
 */
public class H2F implements IDataSet {

    private String hName = "basic2D";
    private Axis xAxis = new Axis();
    private Axis yAxis = new Axis();
    private float[] hBuffer;
    private MultiIndex offset;

    private DatasetAttributes attr = new DatasetAttributes(DatasetAttributes.HISTOGRAM2D);
    private Float     maximumBinValue = 0.0f;
        
    public H2F() {
        offset = new MultiIndex(xAxis.getNBins(), yAxis.getNBins());
        hBuffer = new float[offset.getArraySize()];
        initAttributes();
    }
    
    @Override
    public void setName(String name){ this.hName = name;}
    /**
     * Creates an empty 2D Histogram with 1 bin x and y axes
     * 
     * @param name
     *            the desired name of the 2D Histogram
     */
    public H2F(String name) {
        hName = name;
        offset = new MultiIndex(xAxis.getNBins(), yAxis.getNBins());
        hBuffer = new float[offset.getArraySize()];
        initAttributes();
        
    }
    
    /**
     * Creates a 2D Histogram with the specified parameters.
     * 
     * @param name
     *            the name of the histogram
     * @param bx
     *            the number of x axis bins
     * @param xmin
     *            the minimum x axis value
     * @param xmax
     *            the maximum x axis value
     * @param by
     *            the number of y axis bins
     * @param ymin
     *            the minimum y axis value
     * @param ymax
     *            the maximum y axis value
     */
    public H2F(String name, int bx, double xmin, double xmax, int by,
            double ymin, double ymax) {
        hName = name;
        this.set(bx, xmin, xmax, by, ymin, ymax);
        offset = new MultiIndex(bx, by);
        hBuffer = new float[offset.getArraySize()];    
        initAttributes();
    }
    
    public H2F(String name, String title, int bx, double xmin, double xmax, int by,
            double ymin, double ymax) {
        
        hName = name;
        this.setTitle(title);
        this.set(bx, xmin, xmax, by, ymin, ymax);
        offset = new MultiIndex(bx, by);
        hBuffer = new float[offset.getArraySize()];          
        initAttributes();
    }
    
    private void initAttributes() {
        try {
            this.attr = GStyle.getH2FAttributes().clone();
        } catch (CloneNotSupportedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }			
    }
    
    /**
     * Sets the bins to the x and y axes and creates the buffer of the histogram
     * 
     * @param bx
     *            number of bins on the x axis
     * @param xmin
     *            the minimum value on the x axis
     * @param xmax
     *            the maximum value on the x axis
     * @param by
     *            number of bins on the y axis
     * @param ymin
     *            the minimum value on the y axis
     * @param ymax
     *            the maximum value on the y axis
     */
    public final void set(int bx, double xmin, double xmax, int by,
            double ymin, double ymax) {
        xAxis.set(bx, xmin, xmax);
        yAxis.set(by, ymin, ymax);
        offset = new MultiIndex(bx, by);
        int buff = offset.getArraySize();
        hBuffer = new float[buff];
    }
    
    /**
     *
     * @return the name of the Histogram
     */
    @Override
    public String getName() {
        return hName;
    }
    
    /**
     *
     * @return the x-axis of the 2D Histogram
     */
    public Axis getXAxis() {
        return xAxis;
    }
    
    /**
     *
     * @return the y-axis of the 2D Histogram
     */
    public Axis getYAxis() {
        return yAxis;
    }
    
    public double getMaximum(){
        double maximum = 0.0;
        for(int loop = 0; loop < hBuffer.length; loop++)
            if(hBuffer[loop]>maximum) maximum = hBuffer[loop];
        return maximum;
    }
    
    /**
     * Checks if that bin is valid (exists)
     *
     * @param bx
     *            The x coordinate of the bin
     * @param by
     *            The y coordinate of the bin
     * @return The truth value of the validity of that bin
     */
    private boolean isValidBins(int bx, int by) {
        if ((bx >= 0) && (bx <= xAxis.getNBins()) && (by >= 0)
                && (by <= yAxis.getNBins())) {
            return true;
        }
        return false;
    }
    
    /**
     * Finds the bin content at that bin
     *
     * @param bx
     *            The x coordinate of the bin
     * @param by
     *            The y coordinate of the bin
     * @return The content at that bin
     */
    public double getBinContent(int bx, int by) {
        if (this.isValidBins(bx, by)) {
            int buff = offset.getArrayIndex(bx, by);
            if(buff>=0&&buff= 0)
            this.addBinContent(bin);
    }
    
    public void fill(double x, double y, double w) {
        int bin = this.findBin(x, y);
        if (bin >= 0) {
            this.addBinContent(bin, w);
        }
    }
    
    /**
     * Increments the current bin by 1.0
     *
     * @param bin
     *            the bin in array indexing format to increment
     */
    private void addBinContent(int bin) {
        hBuffer[bin] = (float) (hBuffer[bin] + 1.0);
        if(hBuffer[bin]>this.maximumBinValue)
            this.maximumBinValue = hBuffer[bin];
    }
    
    /**
     * Increments the bin with that value by that weight
     *
     * @param bin
     *            the bin to add the content to, in array indexing format
     * @param w
     *            the value to add to the bin content
     */
    private void addBinContent(int bin, double w) {
        hBuffer[bin] = (float) (hBuffer[bin] + w);
        if(hBuffer[bin]>this.maximumBinValue)
            this.maximumBinValue = hBuffer[bin];
    }
    
    public ArrayList  getSlicesX(){
        ArrayList  slices = new ArrayList();
        for(int loop = 0; loop < this.getXAxis().getNBins(); loop++){
            H1F slice = this.sliceX(loop);
            slice.setName(this.getName()+"_"+loop);
            slice.setTitleX(this.getTitleY());
            slices.add(slice);
        }
        return slices;
    }
    
    public ArrayList  getSlicesY(){
        ArrayList  slices = new ArrayList();
        for(int loop = 0; loop < this.getYAxis().getNBins(); loop++){
            H1F slice = this.sliceY(loop);
            slice.setName(this.getName()+"_"+loop);
            slice.setTitleX(this.getTitleX());
            slices.add(slice);
        }
        return slices;
    }
    
    public void add(H2F h){
        if(h.getXAxis().getNBins()==this.getXAxis().getNBins()&&
                h.getYAxis().getNBins()==this.getYAxis().getNBins()){
            for(int loop = 0; loop < this.hBuffer.length; loop++){
                this.hBuffer[loop] = this.hBuffer[loop] + h.hBuffer[loop];
            }
        } else {
            System.out.println("[warning] ---> error adding histograms "
                    + this.getName() + "  " + h.getName()
                    + ". inconsistent bin numbers");
        }
    }
    
    
    public static H2F  divide(H2F h1, H2F h2){
        if((h1.getXAxis().getNBins()!=h2.getXAxis().getNBins())||
                (h1.getYAxis().getNBins()!=h2.getYAxis().getNBins())
                ){
            System.out.println("[H2D::divide] error : histograms have inconsistent bins");
            return null;
        }
        
        H2F h2div = new H2F(h1.getName()+"_DIV",
                h1.getXAxis().getNBins(),h1.getXAxis().min(),h1.getXAxis().max(),
                h1.getYAxis().getNBins(),h1.getYAxis().min(),h1.getYAxis().max()
        );
        for(int bx = 0; bx < h1.getXAxis().getNBins();bx++){
            for(int by = 0; by < h1.getYAxis().getNBins();by++){
                if(h2.getBinContent(bx, by)!=0){
                    h2div.setBinContent(bx, by, h1.getBinContent(bx, by)/h2.getBinContent(bx, by));
                }
            }
        }
        return h2div;
    }
    
    public void divide(H2F h){
        if(h.getXAxis().getNBins()==this.getXAxis().getNBins()&&
                h.getYAxis().getNBins()==this.getYAxis().getNBins()){
            for(int loop = 0; loop < this.hBuffer.length; loop++){
                if(h.hBuffer[loop]==0){
                    this.hBuffer[loop] = 0.0f;
                } else {
                    this.hBuffer[loop] = this.hBuffer[loop]/h.hBuffer[loop];
                }
            }
        } else {
            System.err.println("[H2D::divide] error the bins in 2d histogram do not match");
        }
    }
    /**
     * Finds which bin has that value.
     *
     * @param x
     *            The x value to search for
     * @param y
     *            The y value to search for
     * @return The bin, in array indexing format, which holds that x-y value
     */
    public int findBin(double x, double y) {
        int bx = xAxis.getBin(x);
        int by = yAxis.getBin(y);
        if (this.isValidBins(bx, by)) {
            return (offset.getArrayIndex(bx, by));
        }
        return -1;
    }
    
    /**
     * Generates a 2D array with the content in the histogram
     *
     * @return a 2D array with each bin in its array index
     */
    public double[][] getContentBuffer() {
        double[][] buff = new double[xAxis.getNBins()][yAxis.getNBins()];
        for (int xloop = 0; xloop < xAxis.getNBins(); xloop++) {
            for (int yloop = 0; yloop < yAxis.getNBins(); yloop++) {
                buff[xloop][yloop] = this.getBinContent(xloop, yloop);
            }
        }
        return buff;
    }
    
    /**
     * Creates an error buffer with each element being 0.0
     *
     * @return a double 2D array with a size of xAxis * yAxis with each element
     *         being 0.0
     */
    public double[][] getErrorBuffer() {
        double[][] buff = new double[xAxis.getNBins()][yAxis.getNBins()];
        for (int xloop = 0; xloop < xAxis.getNBins(); xloop++) {
            for (int yloop = 0; yloop < yAxis.getNBins(); yloop++) {
                buff[xloop][yloop] = 0.0;
            }
        }
        return buff;
    }
    
    /**
     * Specifies the region in the 2D histogram with those attributes
     *
     * @param name
     *            The name of the histogram
     * @param bx_start
     *            The x coordinate beginning
     * @param bx_end
     *            The x coordinate end
     * @param by_start
     *            The y coordinate beginning
     * @param by_end
     *            The y coordinate end
     * @return A 2D histogram with the entered specifications
     */
    public H2F getRegion(String name, int bx_start, int bx_end,
            int by_start, int by_end) {
        double xBinWidth = xAxis.getBinWidth(bx_start);
        double newXMin = xAxis.min() + (xBinWidth * bx_start);
        double newXMax = xAxis.min() + (xBinWidth * bx_end);
        
        double yBinWidth = yAxis.getBinWidth(by_start);
        double newYMin = yAxis.min() + (yBinWidth * by_start);
        double newYMax = yAxis.min() + (yBinWidth * by_end);
        H2F regHist = new H2F(name, bx_end - bx_start, newXMin,
                newXMax, by_end - by_start, newYMin, newYMax);
        
        double content = 0.0;
        for (int y = by_start; y < by_end; y++) {
            for (int x = bx_start; x < bx_end; x++) {
                content = this.getBinContent(x, y);
                regHist.setBinContent(x, y, content);
            }
        }
        return regHist;
    }
    
    public H2F histClone(String name){
        H2F hclone = new H2F(name,
                this.xAxis.getNBins(),this.xAxis.min(),this.xAxis.max(),
                this.yAxis.getNBins(),this.yAxis.min(),this.yAxis.max()
        );
        for(int loop = 0; loop < this.hBuffer.length; loop++){
            hclone.hBuffer[loop] = this.hBuffer[loop];
        }
        return hclone;
    }
    
    public GraphErrors  getProfileX(){
        GraphErrors graph = new GraphErrors();
        int nbinsX = this.getXAxis().getNBins();
        for(int loop = 0 ; loop < nbinsX; loop++){
            H1F h1 = this.sliceX(loop);
            double mean = h1.getMean();
            double rms  = h1.getRMS();
            //System.out.println("MEAN = " + mean + "  RMS = " + rms);
            double bincenter = this.getXAxis().getBinCenter(loop);
            if(h1.integral()>1.0){
                graph.addPoint(bincenter, mean, this.getXAxis().getBinWidth(loop)/2.0, rms);
            }
        }
        return graph;
    }
    
    public GraphErrors  getProfileY(){
        GraphErrors graph = new GraphErrors();
        int nbinsY = this.getYAxis().getNBins();
        for(int loop = 0 ; loop < nbinsY; loop++){
            H1F h1 = this.sliceY(loop);
            double mean = h1.getMean();
            double rms  = h1.getRMS();
            //System.out.println("MEAN = " + mean + "  RMS = " + rms);
            double bincenter = this.getYAxis().getBinCenter(loop);
            graph.addPoint(bincenter, mean, 0.0, rms);
        }
        return graph;
    }
    
    /**
     *
     * @param ngroups indicates how many bins of this have to be merged into one
     * bin of the result NOTE: If ngroup is not an exact divider of the number
     * of bins, the top limit of the rebinned histogram is reduced to the upper
     * edge of the last bin that can make a complete group.
     * 
     * @return a H2F object obtained from original histogram with rebinned
     * x-axis
     */
    public H2F rebinX(int ngroups) {
        int nbinsX = xAxis.getNBins() / ngroups;

        H2F hrebinX = new H2F(hName, this.getTitle(),
                nbinsX, xAxis.min(), xAxis.min() + nbinsX * ngroups * xAxis.getBinWidth(0),
                yAxis.getNBins(), yAxis.min(), yAxis.max());

        for (int iby = 0; iby < yAxis.getNBins(); iby++) {
            for (int ibx = 0; ibx < nbinsX; ibx++) {
                double height = 0.0;
                for (int igroup = 0; igroup < ngroups; igroup++) {
                    height += this.getBinContent(ibx * ngroups + igroup, iby);
                }
                hrebinX.setBinContent(ibx, iby, height);
            }
        }
        return hrebinX;
    }

    /**
     *
     * @param ngroups indicates how many bins of this have to be merged into one
     * bin of the result NOTE: If ngroup is not an exact divider of the number
     * of bins, the top limit of the rebinned histogram is reduced to the upper
     * edge of the last bin that can make a complete group.
     * 
     * @return a H2F object obtained from original histogram with rebinned
     * y-axis
     */
    public H2F rebinY(int ngroups) {
        int nbinsY = yAxis.getNBins() / ngroups;

        H2F hrebinY = new H2F(hName, this.getTitle(),
                xAxis.getNBins(), xAxis.min(), xAxis.max(),
                nbinsY, yAxis.min(), yAxis.min() + nbinsY * ngroups * yAxis.getBinWidth(0));

        for (int ibx = 0; ibx < xAxis.getNBins(); ibx++) {
            for (int iby = 0; iby < nbinsY; iby++) {
                double height = 0.0;
                for (int igroup = 0; igroup < ngroups; igroup++) {
                    height += this.getBinContent(ibx, iby * ngroups + igroup);
                }
                hrebinY.setBinContent(ibx, iby, height);
            }
        }
        return hrebinY;
    }

    /**
     * Creates a projection of the 2D histogram onto the X Axis, adding up all
     * the y bins for each x bin
     *
     * @return a H1F object that is a projection of the Histogram2D
     *         object onto the x-axis
     */
    public H1F projectionX() {
        String name = "X Projection";
        double xMin = xAxis.min();
        double xMax = xAxis.max();
        int xNum = xAxis.getNBins();
        H1F projX = new H1F(name, xNum, xMin, xMax);
        
        double height = 0.0;
        for (int x = 0; x < xAxis.getNBins(); x++) {
            height = 0.0;
            for (int y = 0; y < yAxis.getNBins(); y++) {
                height += this.getBinContent(x, y);
            }
            projX.setBinContent(x, height);
        }
        
        return projX;
    }
    
    /**
     * Creates a projection of the 2D histogram onto the Y Axis, adding up all
     * the x bins for each y bin
     *
     * @return a H1F object that is a projection of the Histogram2D
     *         object onto the y-axis
     */
    public H1F projectionY() {
        String name = "Y Projection";
        double yMin = yAxis.min();
        double yMax = yAxis.max();
        int yNum = yAxis.getNBins() ;
        H1F projY = new H1F(name, yNum, yMin, yMax);
        
        double height = 0.0;
        for (int y = 0; y < yAxis.getNBins(); y++) {
            height = 0.0;
            for (int x = 0; x < xAxis.getNBins(); x++) {
                height += this.getBinContent(x, y);
            }
            projY.setBinContent(y, height);
        }
        
        return projY;
    }
    
    /**
     * Creates a 1-D Histogram slice of the specified y Bin
     *
     * @param xBin		the bin on the y axis to create a slice of
     * @return 			a slice of the x bins on the specified y bin as a 1-D Histogram
     */
    public H1F sliceX(int xBin) {
        String name = "Slice of " + xBin + " X Bin";
        double xMin = yAxis.min();
        double xMax = yAxis.max();
        int xNum    = yAxis.getNBins();
        H1F sliceX = new H1F(name, name, xNum, xMin, xMax);
        
        for (int x = 0; x < xNum; x++) {
            sliceX.setBinContent(x, this.getBinContent(xBin,x));
        }
        return sliceX;
    }
    
    /**
     * Creates a 1-D Histogram slice of the specified x Bin
     *
     * @param yBin			the bin on the x axis to create a slice of
     * @return 				a slice of the y bins on the specified x bin as a 1-D Histogram
     */
    public H1F sliceY(int yBin) {
        String name = "Slice of " + yBin + " Y Bin";
        double xMin = xAxis.min();
        double xMax = xAxis.max();
        int    xNum = xAxis.getNBins();
        H1F sliceY = new H1F(name, name, xNum, xMin, xMax);
        
        for (int y = 0; y < xNum; y++) {
            sliceY.setBinContent(y, this.getBinContent(y,yBin));
        }
        
        return sliceY;
    }
    
    public float[] offset() {
        return hBuffer;
    }
    /**
     * Resets the content of the histogram, sets all bin contents to 0
     */
    @Override
    public void reset(){
        for(int bin = 0; bin < this.hBuffer.length; bin++){
            this.hBuffer[bin] = 0.0f;
        }
    }
    
    @Override
    public int getDataSize(int axis) {
        if(axis==0) {
            return this.xAxis.getNBins();
        } else {
            return this.yAxis.getNBins();
        }
    }
    
    @Override
    public DatasetAttributes getAttributes() {
        return this.attr;
    }
    
    @Override
    public double getDataX(int bin) {
        return this.xAxis.getBinCenter(bin);
    }
    
    @Override
    public double getDataY(int bin) {
        return this.yAxis.getBinCenter(bin);
    }
    
    @Override
    public double getDataEX(int bin) {
        return this.xAxis.getBinWidth(bin);
    }
    
    @Override
    public double getDataEY(int bin) {
        return this.yAxis.getBinWidth(bin);
    }
    
    @Override
    public double getData(int xbin, int ybin) {
        return this.getBinContent(xbin, ybin);
    }
    
    @Override
    public PaveText getStatBox() {
        return new PaveText(2);
    }
    
}

 

Ads help maintain this website.