Creating a THStack for n histograms

Greetings! I have some questions concerning THStacks,

Say I want to create a THStrack for as many histograms as I want. And these come from root files that all have the same folder names and the same histogram names in this way:

for file 1:
         find folder 1
                find histo 1
                         add to stack
for file 2:
         find folder 1 w/ same name
                find histo 1 w/ same name
                          add to stack
 etc.

And then write this stack to an output root file. Is this possible? How can I customize the way the histograms are stacked? Say I want them to have specific colors, I can do this from input, but the number would be limited.

EDIT: I’m trying to do it this way:

 //Open the config file.
  ifstream inFile;
  inFile.open ("config.in", ios::in);
  if (!inFile){
    std::cerr << "Error: Can't open input file:" << std::endl;
    exit(1);
  }
  
  //Get whatever is needed from the config file.
  
  TEnv *config_file = new TEnv("config_file");
  config_file->ReadFile("config.in", kEnvChange);
  
  string input_filenames     = config_file->GetValue("input_filenames", "file"     );
  string rebin_histoName     = config_file->GetValue("histo_name"     , "histogram");
  double rebin_histoValue    = config_file->GetValue("rebin_histo"    , 0.       );
  double ScaleFactor         = config_file->GetValue("ScaleFactor"    , 0.       ); 
  std::cout <<"Opening:  "  << input_filenames << std::endl;
  std::cout << rebin_histoName << " will be rebinned to " << rebin_histoValue << std::endl;

  //Put the names in a List.
 
  TList *FileList = new TList();
  std::ifstream inFileNames;
  string line;
  inFileNames.open(input_filenames);
  
  if (!inFile){
    std::cerr << "The ROOT file names list could not be opened." << endl;
    exit(1);
  }
  
  while(getline(inFileNames, line)){
    
    TFile *add_file = TFile::Open(line.c_str());
    if(!add_file){
      
      std::cout << "Root file could not be opened." << std::endl;
    }
    
    FileList->Add(add_file);
    
  }
  
  FileList->Print();
  
  
  //Create the output file
  
  TIter fileIter(FileList);
  TKey *file_key;
  while((file_key = (TKey*) fileIter())){
    
    TFile *output = TFile::Open(TString::Format("Normalized_%s", file_key->GetName()) , "RECREATE");
    std::cout << "Opening output: " << output->GetName() << std::endl;
    
    //Open the input root file
    TFile *input_file = TFile::Open(file_key->GetName());
    TDirectory *input_dir = gDirectory;



To make a THStack Structure and then write my histograms to it, but It doesn’t work.

Thank you and best regards!


ROOT Version: 6.14.06
Platform: Ubuntu 18.04
Compiler: g++ 7.4.0


Hi,
In FileList->Add(add_file); you add a TFile to the FileList. But then later you claim that the elements are TKeys and not TFiles:

TIter fileIter(FileList);
while((/*...*/ (TKey*) fileIter())){

That won’t work. I also don’t understand why you iterate over the files twice. Or why you open one output file per input file - how can you assemble your THStack then? And I don’t see where you are building the THStack - where are the input histograms? This might work better:

  TH1::AddDirectory(false); // keep histograms independent from their directory
  THStack *outStack = new THStack(...);
  while(getline(inFileNames, line)){
    
    TFile *add_file = TFile::Open(line.c_str());
    if(!add_file){      
      std::cout << "Root file could not be opened." << std::endl;
      continue;
    }
    file->cd("someDirectory");
    while(TObject *file_key: gDirectory->GetKeys()) {
      if (TH1* hist = dynamic_cast<TH1*>(((TKey*)file_key)->ReadObj())) {
        // this is a TH1.
        outStack->Add(hist);
      }
    }
  } // loop over files
  TFile *output = TFile::Open(TString::Format("Normalized_%s", file_key->GetName()) , "RECREATE");
  outStack->Write();

That might give you some ideas on how to do it…

Axel.

1 Like

Thank you very much! I’ll work on it to see if I can get it to work how I want it to.

About the colors thing, is this not possible or do I work with the colors given to each histogram in the Stack?

Greetings!

Since ROOT 6.09/01 you can use the "PFC" drawing option to let the THStack select suitable colors automatically. See https://root.cern/doc/master/classTHistPainter.html#HP061 Otherwise the color defined for each histogram will be used.

Thank you for your answer! The reason I opened twice was so I could keep the folder structure (of the input files, that for convenience is the same, so the same histograms with the same cuts are stacked) in the output file, but I realize I can do this without opening the file twice. I’ll post here if I have more doubts.

Thank you for your time!

while(TObject *file_key: gDirectory->GetKeys()

Does not work for me, it gives me an error:

/home/fernando/Desktop/Normalizer_Appli/Histo_Merger/Forum/histo_merger2.C:64:23: error: variable declaration in condition must have an initializer
              while(TObject *file_key: gDirectory->GetKeys()){

I’ll try to iterate another way.

It runs now, with mistakes:


  TH1::AddDirectory(false);
  //TFile *output = TFile::Open(output_filename.c_str(), "RECREATE");
  THStack *outstack = new THStack(output_filename.c_str(), "");
  std::ifstream inFileNames;
  string line;
  inFileNames.open(input_filenames);
  while(getline(inFileNames, line)){

    TFile *input_file = TFile::Open(line.c_str());
    if(!input_file){
      std::cout << "ROOT file could no be opened" << std::endl;
      continue;
    }
    TDirectory *input_dir = gDirectory;

    TIter nextdir(input_dir->GetListOfKeys());
    TKey *dir_key;
    while((dir_key = (TKey*)nextdir())){
      if(dir_key->IsFolder()){
        input_file->cd();
//      output->cd();
//      TDirectory *output_dir = output->mkdir(dir_key->GetName());
//      output_dir->cd();
        input_dir->cd(dir_key->GetName());
        TIter next_folder(gDirectory->GetListOfKeys());
        TKey *key_folder;
        //THStack *outstack = new THStacki(keyfolder->GetTitle(), "");
        while((key_folder = (TKey*)next_folder())){
         // TH1::AddDirectory(false);
          if(TH1 *hist  = dynamic_cast<TH1*>(((TKey*)key_folder)->ReadObj())){

            outstack->Add(hist);

          }
        }
      }
    }
    delete input_file;
    //outstack->Write();
  }
  //output->cd();  
  //outstack->Write();
  TFile *output = TFile::Open(output_filename.c_str(), "RECREATE");
  outstack->Write();
  delete output;


}

I want to stack the histograms in the folders of the output file, this only creates only one stack, should I create a stack in the loop?

Thanks!

Well yes, if you want multiple you’ll need to loop.

I’m getting errors stacking in the output file. I get the error that the input file is not writable, so it tries to write the to the input file and not to the output file. Or I get a segmentation violation.

Is it better to just open each file individually and stack them by hand, basically? Or do I add them, say, to a list or a map and then stack them in the output file?

I’d create the THStack before the loop that can add the histograms to the stack, and then write the stack into the output file.

Can you post your code?

Axel.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.