Write histogram in subdirectory

Hi,

I have created a file with an hierarchy of directories and subdirectories, then I access a histogram from another file, and want to write it to the new file in a subdirectory that is low in directory hierarchy, but I cannot seem to make it. I am able to write it either in the first or the second “level”.
Is there a way to navigate to the desired subfolder?
You will find my code attached, the issue is in the last 4 lines, when I uncomment, it does not save the histo.

Thanks!

#include <TH2F.h>
#include <TFile.h>
#include <TGraph.h>
#include <TCanvas.h>
#include <TLegend.h>
#include <TMultiGraph.h>
#include <iostream>
#include <iomanip>
#include <string>
#include <sstream>
#include <TROOT.h>
#include <TSystem.h>
#include <vector>
#include <map>
#include <TColor.h>
#include "TRint.h"
#include "TStyle.h"
#include "TLatex.h"
#include "THStack.h"
#include "TROOT.h"
#include <cmath>
#include "TLine.h"
#include "TLatex.h"
#include "TPave.h"
#include "TH1.h"
#include "TMarker.h"
#include <fstream>

#include "TGraphErrors.h"
#include "TGraphAsymmErrors.h"

using namespace std;



void new2(){
    
    TFile *top = new TFile("input_F.root","recreate");

  
    TDirectory *folders1[4];
    TDirectory *folders2[9];
    TDirectory *folders3[4];
    
    TString srlist[4];
    TString samplelist[9];
    TString channellist[4];
    
    srlist[0]="SR";
    srlist[1]="CR1";
    srlist[2]="CR2";
    srlist[3]="CR3";
    
    samplelist[0]="WZjj";
    samplelist[1]="ZZ";
    samplelist[2]="ttbar";
    samplelist[3]="ttbarV";
    samplelist[4]="Zgamma";
    samplelist[5]="tZ";
    samplelist[6]="Zll";
    samplelist[7]="WZQCD";
    samplelist[8]="VVV";
    
    channellist[0]="eee";
    channellist[1]="emm";
    channellist[2]="mee";
    channellist[3]="mmm";
    
    for (int i=0; i<4; i++) {
        folders1[i] = top->mkdir( (srlist[i]).Data());
        folders1[i]->cd();
        for(int j=0; j<9;j++){
            folders2[j]=folders1[i]->mkdir((samplelist[j]).Data());
            folders2[j]->cd();
            for(int k=0;k<4;k++){
                folders3[k]=folders2[j]->mkdir((channellist[k]).Data());
                folders3[k]->cd();
            }
        }
        
    }
    top->cd();
    
   
    TFile *f_SR_WZ_pt = TFile::Open("hist-15_WZlllnu_PowHegPythia_mc15c.root");
    string varName ="pTZ";
    string CR0 ="WZ";
    string channel ="EEE";
    
   string histo_name = "h"+CR0+"_"+channel+"_"+varName;
    cout<<histo_name<<endl;
    
    TH1* pt1 =(TH1*)f_SR_WZ_pt->Get(histo_name.c_str());
    pt1->Draw();
   

    // top->cd();
    TString newname ="kati";
    TString nee="2";
    TString newname2=newname+nee;
    top->cd();
    folders1[0]->cd();
    //folders2[0]->cd();   //when I uncomment these two lines, it does not write the histo
    //folders3[0]->cd();

    pt1->SetName(newname2.Data());
    pt1->Write();

}


Isn’t the problem that ‘folders3’ points to the ‘last’ set of sub folders rather than the first?
I.e. adding

   cout << "Attempting to write in :" << folders3[0]->GetName() << " " << folders3[0]->GetPath() << "\n";

will show

Attempting to write in :eee input_F.root:/CR3/VVV/eee

and as far as I can tell the histogram is indeed in that sub-directory.

Cheers,
Philippe.

1 Like

@pcanal Thanks a lot Philippe. I have another question, is it possible to set the path of where I will save the histogram? I know in general that I can do this with it with SaveAs but I cannot save in a TH1 format like this…

Best,
Des

Yes. Try:

pt1->SetDirectory(folders3[0]);

and then later

top->Write();

which will write all the histograms in all the sub-directory.

Cheers,
Philippe.

1 Like

Thanks @pcanal ! But my problem is that I do not want to write it in this subfolder, I would like to specify by hand in which folder I will write it, is this possible?

I would like to specify by hand in which folder I will write it, is this possible?

Apriori yes … but I don’t quite understand the difference and/or what you mean. Maybe provide pseudo code showing what you mean/want/hope-for :slight_smile:

1 Like

@pcanal thanks for your answer philippe!
Continuing the same example, if I write what you proposed, I can can only write to CR3/VVV/eee, whereas I would like to be able to write also in CR1/WZ/eee (the first two levels of hierarchy stay the same, because they are “saved” in the last for loop in folders3, thats why I would like to do it by hand)

    top->cd();// when I do this, I can only write to CR3/VVV/eee,whereas I would like to be able to write
    //also in CR1/WZ/eee
  //  pt1->SetDirectory(folders3[0]);
    pt1->SetDirectory("SR/ZZ/eee");//something like this?
    top->Write();

My full code is here

#include <TH2F.h>
#include <TFile.h>
#include <TGraph.h>
#include <TCanvas.h>
#include <TLegend.h>
#include <TMultiGraph.h>
#include <iostream>
#include <iomanip>
#include <string>
#include <sstream>
#include <TROOT.h>
#include <TSystem.h>
#include <vector>
#include <map>
#include <TColor.h>
#include "TRint.h"
#include "TStyle.h"
#include "TLatex.h"
#include "THStack.h"
#include "TROOT.h"
#include <cmath>
#include "TLine.h"
#include "TLatex.h"
#include "TPave.h"
#include "TH1.h"
#include "TMarker.h"
#include <fstream>

#include "TGraphErrors.h"
#include "TGraphAsymmErrors.h"

using namespace std;



void redo(){
    
    TFile *top = new TFile("input_F.root","recreate");

  
    TDirectory *folders1[4];
    TDirectory *folders2[9];
    TDirectory *folders3[4];
    
    TString srlist[4];
    TString samplelist[9];
    TString channellist[4];
    
    srlist[0]="SR";
    srlist[1]="CR1";
    srlist[2]="CR2";
    srlist[3]="CR3";
    
    samplelist[0]="WZjj";
    samplelist[1]="ZZ";
    samplelist[2]="ttbar";
    samplelist[3]="ttbarV";
    samplelist[4]="Zgamma";
    samplelist[5]="tZ";
    samplelist[6]="Zll";
    samplelist[7]="WZQCD";
    samplelist[8]="VVV";
    
    channellist[0]="eee";
    channellist[1]="emm";
    channellist[2]="mee";
    channellist[3]="mmm";
    
    for (int i=0; i<4; i++) {
        folders1[i] = top->mkdir( (srlist[i]).Data());
        folders1[i]->cd();
        for(int j=0; j<9;j++){
            folders2[j]=folders1[i]->mkdir((samplelist[j]).Data());
            folders2[j]->cd();
            for(int k=0;k<4;k++){
                folders3[k]=folders2[j]->mkdir((channellist[k]).Data());
                folders3[k]->cd();
            }
        }
        
    }
    top->cd();
    
   
    TFile *f_SR_WZ_pt = TFile::Open("hist-15_WZlllnu_PowHegPythia_mc15c.root");
    string varName ="pTZ";
    string CR0 ="WZ";
    string channel ="EEE";
    
   string histo_name = "h"+CR0+"_"+channel+"_"+varName;
    cout<<histo_name<<endl;
    
    TH1* pt1 =(TH1*)f_SR_WZ_pt->Get(histo_name.c_str());
    pt1->Draw();
   

    // top->cd();
    TString newname ="kati";
    TString nee="2";
    TString newname2=newname+nee;
    top->cd();// when I do this, I can only write to CR3/VVV/eee,whereas I would like to be able to write
    //also in CR1/WZ/eee
  //  pt1->SetDirectory(folders3[0]);
    pt1->SetDirectory("SR/ZZ/eee");

    top->Write();

    
   // folders1[0]->cd();
    //folders2[0]->cd();   //when I uncomment these two lines, it does not write the histo
    //folders3[0]->cd();
    pt1->SetDirectory("SR/ZZ/eee");
    top->Write();
// pt1->SetName(newname2.Data());
   // pt1->Write();

}




, if I write what you proposed, I can can only write to CR3/VVV/eee,

Technically this could be fixed by enhancing your arrays (i.e. use multi-dimensional collection).
Or

pt1->SetDirectory(“SR/ZZ/eee”);//something like this?

can be done with

auto dir = top->GetDirectory("SR/ZZ/eee");
pt1->SetDirectory(dir);

Cheers,
Philippe.

1 Like

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