Converting a TGraph to a TH1D nearly works


ROOT Version: 6.16
Platform: 20.04
Compiler: linuxx8664gcc


Dear co-rooters,

I am trying to convert a TGraph to a TH1D. This is convenient because i can use the TH1 functions later on.

For that I created a function, that accepts a TGraph object, and based on that it creates a binning. Note the the x points of the TGraph are not necessarily equidistant.
Then in my main code I am creating the the TGraph based on an ascii file and I am using the function to construct a TH1D histogram.

The trouble is that in some bins the BinCenter of the histogram is not exactly the same as the x of the TGraph. See the following image for instance.

Here is my code that I compile using .L macro.C++ and execute using oscillations(). Note that I upoaded the .dat as a .zip file.

Any idea on how to fix that?

Thanks in advance!

#include "TH1D.h"
#include "TGraph.h"
#include "TCanvas.h"

#include <vector>
#include <fstream>
#include <iostream>

using namespace std;

TH1D* TGraph_to_TH1D(TGraph* graph) {
    if (!graph) {
        std::cerr << "Error: Null TGraph pointer!" << std::endl;
        return nullptr;
    }
    
    
    int n = graph->GetN();
    double *x = new double[(n+1)];
    
    x[0] = graph->GetX()[0] - (graph->GetX()[1] - graph->GetX()[0]) / 2.0;
    x[n] = graph->GetX()[n-1] - (graph->GetX()[n-1] - graph->GetX()[n-2]) / 2.0;
    
    for (int i=1; i<n; ++i){
    	x[i] = (graph->GetX()[(i-1)] + graph->GetX()[i]) / 2.0;
    }
    
    TH1D *h = new TH1D("h", "h", n, x);
    
    for (int i=0; i<n; ++i) {
    	h->SetBinContent(i+1, graph->GetY()[i]);
	}

    return h;
}


void oscillations() {
    // Open the .dat file
    std::ifstream infile("235U_MT102_eV.dat");
    if (!infile) {
        std::cerr << "Error opening file!" << std::endl;
        return;
    }

    // Vectors to store data
    std::vector<double> energies, cross_sections;

    double energy, cross_section;
    while (infile >> energy >> cross_section) {
        energies.push_back(energy);
        cross_sections.push_back(cross_section);
    }
    infile.close();

    int nPoints = energies.size();
    if (nPoints == 0) {
        std::cerr << "No data found in file!" << std::endl;
        return;
    }

    // Create a TGraph
    TGraph *graph = new TGraph(nPoints, energies.data(), cross_sections.data());
    graph->SetTitle("Cross Section vs Energy;Energy (eV);Cross Section (barns)");
    
    TH1D *hist =(TH1D*) TGraph_to_TH1D(graph);

    // Draw the histogram and the graph
    hist->Draw("histo");

    graph->SetMarkerStyle(4);
    graph->SetMarkerSize(1);
    graph->Draw("PLsame"); // Overlay TGraph on histogram

}

235U_MT102_eV.dat.zip (260.1 KB)

If the points are not equidistant in x, as you said and already saw, you have to be more careful when you calculate the bin edges or centres.

1 Like

Which TH1 functions do you need which are not present in TGraph ?

Functions like Rebin, Divide(with other histograms), Scale.

Ok. Function like Rebin make sense only on binned data. Your data set is initially unbinned. I guess it is not possible to convert any graph into an histogram which will graphical exactly match the graph points. For that you need to make sure that the X value of each point correspond exactly to the center of each bins, Which not always possible.