Hello again,
I am trying to make a for loop that would help me shorten my code. I have several histograms that have almost same name, but differ in suffix. I would like the loop to take the histogram, set all the things like color, scaling, filling etc. So far I have managed to make a piece of code that might do it (hopefully… I am new to programming and struggle a lot), but I get error: no member named ‘SetFillStyle’ in ‘std::__cxx11::basic_string’ name.SetFillStyle(1001);.
I could make that pt, eta, phi a number (ttbar1_1, ttbar1_2,…) and know how to do it, but I prefer having letters there, because they make clear what does the variable stay for.
Any ideas how to do that so that it works?
Thank you!
Hi Marta,
“where” are the histograms? Are they stored in a ROOT file or are they objects that you have created earlier in your script?
The error you get is because name, within the for loop, is a std::string, so you are trying to call SetFillStyle on a std::string and that obviously doesn’t work. You need something like
for (const auto &name: names) {
TH1* histo = nullptr;
gDirectory->GetObject(name.c_str(), histo);
histo->SetFillStyle(1001);
// ...color, scaling...
}
i.e. you need to retrieve the histogram object from ROOT using the name before you can do anything with it.
Thank you for your response! I get what is wrong there now. Unfortunatelly, your idea would not work well for me, because each of the histograms is getting something else from the file, like this:
When I try to compile this, I get error: no matching constructor for initialization of 'std::vector<TH1D *>' std::vector<TH1D*> histos;. So I try to include TH1::TH1D, but that gives me error, too, saying no member named ‘TH1D’ in 'TH1. (Sorry if it is stupid question, I am a beginner learning as I go)
Hi Marta,
thank you for the minimal reproducer, very helpful!
Here’s the main issue (the code also contains typos, e.g. histo.push_back instead of histos.push_back, which the compiler will point out):
for (const auto& name: names){
histo.push_back(static_cast<TH1D*>(name))
names is a vector<string>, so in this loop name is a string.
You can’t convert the string "ttbar1_pt" to the variable ttbar1_pt!
Here’s one way to do what you want. Make sure you understand what’s happening, C++ can be tricky – if not, just ask:
void mwe(){
TFile *ttbar = TFile::Open("ttbar_out.root");
std::vector<std::string> names{"h_muon1_pt", "h_muon1_eta", "h_muon1_phi"};
std::vector<TH1D*> histos; // vector of pointers to histograms
// fill the vector of TH1D pointers and do things that you want to do for each histogram
for (const auto& name: names) {
TH1D* h_ptr = static_cast<TH1D*>(ttbar->Get(name.c_str()));
histos.push_back(h_ptr);
h_ptr->SetFillStyle(1001);
// ...
}
TCanvas* Canvas1_pt = new TCanvas("Canvas1_pt", "muon1 pt", 1000, 800);
histos[0]->Draw("same hist"); // I chose one of them
}