Export histogram data in vector

Assume that a .root file exists of histograms.
What I want to do, is to export the histogram data in a c++ .
Is this possible?

1 Like

Hi,

you can read out the histogram (TFile::Get), loop over the bins (get the number of bins with TH1::GetNbins{X,Y,Z}), get their content (TH1::GetBinContent) and store in a vector (std::vector::emplace_back). Don’t forget to reserve enough space in your std vector with std::vector::reserve.

Danilo

1 Like

Note a much simpler solution that is valid for any ROOT object. Simply do:
myhist.SaveAs(“myhist.C”)
if your histogram has errors, bin labels, titles, etc, everything will be saved in a C"" script that you can execute
to recreate the object in the original state.

Rene

1 Like

[quote=“brun”]Note a much simpler solution that is valid for any ROOT object. Simply do:
myhist.SaveAs(“myhist.C”)
if your histogram has errors, bin labels, titles, etc, everything will be saved in a C"" script that you can execute
to recreate the object in the original state.

Rene[/quote]

Thank you very much for your answer!
I saved the histogram as you indicated but the .C file has the following format

[code]{
//========= Macro generated from object: FIMG6_EV_1/FIMG6_EV_1
//========= by ROOT version5.34/20

TH1F *FIMG6_EV_1 = new TH1F(“FIMG6_EV_1”,“FIMG6_EV_1”,8192000,0,16384);
FIMG6_EV_1->SetBinContent(0,217);
FIMG6_EV_1->SetBinContent(1,217);
FIMG6_EV_1->SetBinContent(2,217);
FIMG6_EV_1->SetBinContent(3,217);
FIMG6_EV_1->SetBinContent(4,218);
FIMG6_EV_1->SetBinContent(5,218);
FIMG6_EV_1->SetBinContent(6,217);
FIMG6_EV_1->SetBinContent(7,217);
FIMG6_EV_1->SetBinContent(8,218);
FIMG6_EV_1->SetBinContent(9,217);
FIMG6_EV_1->SetBinContent(10,218);
…
FIMG6_EV_1->SetBinContent(8191998,217);
FIMG6_EV_1->SetBinContent(8191999,215);
FIMG6_EV_1->SetEntries(8.192e+06);

Int_t ci; // for color index setting
TColor *color; // for color definition with alpha
ci = TColor::GetColor("#000099");
FIMG6_EV_1->SetLineColor(ci);
FIMG6_EV_1->GetXaxis()->SetTitle(“Time (us)”);
FIMG6_EV_1->GetXaxis()->SetLabelFont(42);
FIMG6_EV_1->GetXaxis()->SetLabelSize(0.035);
FIMG6_EV_1->GetXaxis()->SetTitleSize(0.035);
FIMG6_EV_1->GetXaxis()->SetTitleFont(42);
FIMG6_EV_1->GetYaxis()->SetLabelFont(42);
FIMG6_EV_1->GetYaxis()->SetLabelSize(0.035);
FIMG6_EV_1->GetYaxis()->SetTitleSize(0.035);
FIMG6_EV_1->GetYaxis()->SetTitleFont(42);
FIMG6_EV_1->GetZaxis()->SetLabelFont(42);
FIMG6_EV_1->GetZaxis()->SetLabelSize(0.035);
FIMG6_EV_1->GetZaxis()->SetTitleSize(0.035);
FIMG6_EV_1->GetZaxis()->SetTitleFont(42);
FIMG6_EV_1->Draw("");
}[/code]

I am not sure how these values can be translated into vectors.

P.S.: The reason I want to vectorize a histogram is to use Persistence class(people.mpi-inf.mpg.de/~weinkauf/ … nce1d.html) to locate local extrema in a histogram.

1 Like

{ TH1D *h = new TH1D("h", "h", 100, -3, 3); for (int i = 0; i < 10000; i++) h->Fill(gRandom->Gaus(0, 1)); // http://www.cplusplus.com/reference/vector/vector/ std::vector<double> *v = new std::vector<double>(h->GetNbinsX()); for (int i = 0; i < h->GetNbinsX(); i++) v->at(i) = h->GetBinContent(i + 1); }

1 Like

Hello,
since TH1D derives from TH1 and TArrayD what bout just using TArray::GetArray(): as you can find in the reference guide here root.cern.ch/root/html/TArrayD. … D:GetArray this does what you want. giving you a double array (pointer for dinamyc change of size).
Keep in mind that if lets say your histo has N bins from 1 to N there always is a 0 bin for underflow and a N+1 bin for overflow, so the array you will get out of your histo is of size N+2.

have fun

Gabriele

P.S. the code to get it into a std::vector is:

(... histo with N bins ...)
vector<double> data(N+2);
&data[0]=histo->GetArray();
(...)

[quote=“Wile E. Coyote”]{ TH1D *h = new TH1D("h", "h", 100, -3, 3); for (int i = 0; i < 10000; i++) h->Fill(gRandom->Gaus(0, 1)); // http://www.cplusplus.com/reference/vector/vector/ std::vector<double> *v = new std::vector<double>(h->GetNbinsX()); for (int i = 0; i < h->GetNbinsX(); i++) v->at(i) = h->GetBinContent(i + 1); }[/quote]

Thank you very much for your answer!!!
It seems that it’s working, however I do not understand why you are using the for loop. Wouldn’t

be enough?
I assume that it has to do with overflows or lost histogram data, but I am not sure…

Hello,
GetNBins() just tells you how much bins the histogram contains, in order to allocate space for the data, while the for loop is needed to load in every “cell” of the vector the bincontent of the correspondent bin.
Another solution is:

{ TH1D *h = new TH1D("h", "h", 100, -3, 3); for (int i = 0; i < 10000; i++) h->Fill(gRandom->Gaus(0, 1)); std::vector<double> v; for (int i = 0; i < h->GetNbinsX(); i++) v.pushback(h->GetBinContent(i + 1)); }
have fun

Gabriele

1 Like

In (pre)compiled code you can also simply use (the underflow and overflow histogram’s bins are skipped): // ... TH1F *h = new TH1F("h", "h", 100, -3, 3); for (int i = 0; i < 10000; i++) h->Fill(gRandom->Gaus(0, 1)); // http://www.cplusplus.com/reference/vector/vector/ std::vector<float> *v = new std::vector<float>( h->GetArray() + 1, h->GetArray() + 1 + h->GetNbinsX() ); // ...

[quote=“Jet”]Hello,
GetNBins() just tells you how much bins the histogram contains, in order to allocate space for the data, while the for loop is needed to load in every “cell” of the vector the bincontent of the correspondent bin.
Another solution is:

{ TH1D *h = new TH1D("h", "h", 100, -3, 3); for (int i = 0; i < 10000; i++) h->Fill(gRandom->Gaus(0, 1)); std::vector<double> v; for (int i = 0; i < h->GetNbinsX(); i++) v.pushback(h->GetBinContent(i + 1)); }
have fun

Gabriele[/quote]

I think you meant push_back
The thing is that push_back takes more time to fill in the vector!
Why is this happening?

[quote=“Wile E. Coyote”]In (pre)compiled code you can also simply use (the underflow and overflow histogram’s bins are skipped): // ... TH1F *h = new TH1F("h", "h", 100, -3, 3); for (int i = 0; i < 10000; i++) h->Fill(gRandom->Gaus(0, 1)); // http://www.cplusplus.com/reference/vector/vector/ std::vector<float> *v = new std::vector<float>( h->GetArray() + 1, h->GetArray() + 1 + h->GetNbinsX() ); // ...[/quote]

I tried to run this code but I get this error

Error: Can't call vector<float,allocator<float> >::vector<float,allocator<float> >(FIMG6_EV_1->GetArray()+1,FIMG6_EV_1->GetArray()+1+FIMG6_EV_1->GetNbinsX()) in current scope extrema_root_forum.C:31: Possible candidates are... (in vector<float,allocator<float> >) vector.dll -1:-1 0 public: vector<float,allocator<float> > vector<float,allocator<float> >::vector<float,allocator<float> >(void); vector.dll -1:-1 0 public: vector<float,allocator<float> > vector<float,allocator<float> >::vector<float,allocator<float> >(vector<float,allocator<float> >::size_type n,const float& value=float()); vector.dll -1:-1 0 public: vector<float,allocator<float> > vector<float,allocator<float> >::vector<float,allocator<float> >(const vector<float,allocator<float> >& x); vector.dll -1:-1 0 public: vector<float,allocator<float> > vector<float,allocator<float> >::vector<float,allocator<float> >(vector<float,allocator<float> >::const_iterator first,vector<float,allocator<float> >::const_iterator last); vector.dll -1:-1 0 public: vector<float,allocator<float> > vector<float,allocator<float> >::vector<float,allocator<float> >(void); vector.dll -1:-1 0 public: vector<float,allocator<float> > vector<float,allocator<float> >::vector<float,allocator<float> >(vector<float,allocator<float> >::size_type n,const float& value=float()); vector.dll -1:-1 0 public: vector<float,allocator<float> > vector<float,allocator<float> >::vector<float,allocator<float> >(const vector<float,allocator<float> >& x); vector.dll -1:-1 0 public: vector<float,allocator<float> > vector<float,allocator<float> >::vector<float,allocator<float> >(vector<float,allocator<float> >::const_iterator first,vector<float,allocator<float> >::const_iterator last);

Search for “reallocation” in the std::vector::push_back method description.

BTW. I did say explicitly that my last example works in (pre)compiled code only.

[quote=“Wile E. Coyote”]Search for “reallocation” in the std::vector::push_back method description.

BTW. I did say explicitly that my last example works in (pre)compiled code only.[/quote]

What do you mean (pre)compiled version?

(pre)compiled = ACLiC used or shared library or standalone code compiled by g++ / cling / …

[quote=“atha.stam”][quote=“Jet”]Hello,
GetNBins() just tells you how much bins the histogram contains, in order to allocate space for the data, while the for loop is needed to load in every “cell” of the vector the bincontent of the correspondent bin.
Another solution is:

{ TH1D *h = new TH1D("h", "h", 100, -3, 3); for (int i = 0; i < 10000; i++) h->Fill(gRandom->Gaus(0, 1)); std::vector<double> v; for (int i = 0; i < h->GetNbinsX(); i++) v.pushback(h->GetBinContent(i + 1)); }
have fun

Gabriele[/quote]

I think you meant push_back
The thing is that push_back takes more time to fill in the vector!
Why is this happening?[/quote]

Hello,
yes, I was wrong on pushback() that is push_back(). #-o
When you push back you do 3 steps operation: is the memory enough to accomodate the whole expanded vector? if yes allocate space for a new element contiguous to the vector (call constructor). then fill the new element. if you have performances in mind just use the one step option:

double* arr=new double [h->GetBinX()];
arr=h->GetArray();
std::vector<double> v(std::begin(arr),std::end(arr));
delete arr;

I am not able to try this out atm, but it should work well since the GetArray() returns the double* item.
let me know.

have fun

Gabriele