Selecting subset of entries in TTree and plot them in Histogram

Hello Rooters,

I am trying to select the entries in an TTree by imposing conditions on the Branches. Let me explain:

  • I have written a TTree to file, with new Branches, like below:
   TFile *fin = new TFile("tmp_outfile.root");
   TTree *t1 = (TTree*)fin->Get("t1");


   Float_t NTracks; //overall amount of tracks in event
   Float_t nKaonTracks;//number of kaon tracks
   Float_t M_KK; //Invariant mass of Kaon pairs
   Float_t PIDK; //Kaon PID
   Float_t PIDK1; //1st Kaon PID
   Float_t PIDK2; //2nd Kaon PID
 
   t1->Branch("NTracks", &NTracks,"NTracks/F");
   t1->Branch("nKaonTracks", &nKaonTracks,"nKaonTracks/F");
   t1->Branch("M_KK", &M_KK,"M_KK/F");
   t1->Branch("PIDK", &PIDK,"PIDK/F");
   t1->Branch("PIDK1", &PIDK1,"PIDK1/F");
   t1->Branch("PIDK2", &PIDK2,"PIDK2/F");
   
   if (some condition)
   {
   t1->Fill();
   }

Now, I have a file tmp_outfile.root that stores the computed invariant mass of kaon pairs M_KK and the PID information of the tracks PIDK1 and PIDK2. What I would like to do is to fill a histogram by selecting all the entries in M_KK with a corresponding PIDK1 and/or PIDK2 values greater than a set number.

I am finding looping through the events particularly awkward; I have this basic attempt

    TTree *t1 = (TTree*)fin->Get("t1");
    Float_t NTracks; //overall amount of tracks in event
    Float_t nKaonTracks;//number of kaon tracks
    Float_t M_KK; //Invariant mass of Kaon pairs
    Float_t PIDK; //Kaon PID
    Float_t PIDK1; //1st Kaon PID
    Float_t PIDK2; //2nd Kaon PID
    
    t1->SetBranchAddress("NTracks",&NTracks);
    t1->SetBranchAddress("nKaonTracks",&nKaonTracks);
    t1->SetBranchAddress("M_KK",&M_KK);
    t1->SetBranchAddress("PIDK",&PIDK);
    t1->SetBranchAddress("PIDK1",&PIDK1);
    t1->SetBranchAddress("PIDK2",&PIDK2);
   
    Long64_t nentries = t1->GetEntriesFast();
    for (Long64_t i=0; i<<nentries;++i)
    {
        t1->GetEntry(i);
        <some if condition> 
    }

I was hoping someone could help me with the if loop: what I want to do is something like

for (int j=0; i<PIDK1[i].size(); ++j)
{
      if(PID[j][i] >= 0)
      {
      h.Fill(M_KK[i][j]);
      }
}

Where h is a histogram and i is the index in the previous loop with GetEntry(i); Again, all I want to do is take all the entries with a given value of PIDK1 greater than a value n and fill a histogram with the corresponding M_KK entries.

Thank you for your help, I hope I was clear enough.

Blaise

Hi,

If you want to avoid looping I see two opportunities for you.
If you can use the latest ROOT version, v6.09/02, you can take advantage of the new TDataFrame class.
In your case

ROOT::Experimental::TDataFrame d(*t1);
auto m_kk = d.Filter([](float pidk1, float pidk2){ <here your cut> ; return booleanValue;}, {"PIDK1", "PIDK2"}).Histo1D("M_KK");

The advantages are many, for example adding one single line

ROOT::EnableImplicitMT(); // <-- this line
ROOT::Experimental::TDataFrame d(*t1);
auto m_kk = d.Filter([](float pidk1, float pidk2){ <here your cut> ; return booleanValue;}, {"PIDK1", "PIDK2"}).Histo1D("M_KK");

will make your analysis parallelised.

Alternatively, you can use the TTree::Draw method.

Cheers,
D

Hi,

Thank you - this looks great! I am just wondering how to get the latest version of Root on lxplus. Currently I have the following setup in my ~/.bashrc

export ROOTSYS=/afs/cern.ch/sw/lcg/app/releases/ROOT/6.06.06/x86_64-slc6-gcc49-opt/root
export PATH=$PATH:$ROOTSYS/bin
LD_LIBRARY_PATH=/usr/local/lib64/:$LD_LIBRARY_PATH
. /afs/cern.ch/sw/lcg/external/gcc/4.9/x86_64-slc6-gcc49-opt/setup.sh
. /afs/cern.ch/sw/lcg/app/releases/ROOT/6.06.06/x86_64-slc6-gcc49-opt/root/bin/thisroot.sh

Thanks,

Blaise

Hi,

here you can find all releases in ROOT
https://root.cern.ch/releases
In each one, we describe how to set up the environment on lxplus, for example
https://root.cern.ch/content/release-60902

The command for lxplus7 (ssh lxplus7.cern.ch) is
. /cvmfs/sft.cern.ch/lcg/app/releases/ROOT/6.09.02/x86_64-centos7-gcc48-opt/root/bin/thisroot.sh

Cheers,
D

Hi,

Thanks again. I tried a few things, with odd outcomes:

ROOT::Experimental::TDataFrame d(*t1);
auto m_kk = d.Filter([](float pidk1){return pidk1>2;},{"PIDK1"}).Histo1D("M_KK"); 

I received an error: it was unable to guess the type of M_KK, so I tried

ROOT::Experimental::TDataFrame d(*t1);
auto m_kk = d.Filter([](float pidk1){return pidk1>2;},{"PIDK1"}).Histo1D<Float_t>("M_KK"); 

Now all works fine, but the histogram does not seem to be filled. I am wondering if it is actually selecting the data, i.e. if the type indicated is correct, with the preamble

    TFile *fin = new TFile("tmp_outfile.root");
    TTree *t1 = (TTree*)fin->Get("t1");
    Float_t NTracks; //overall amount of tracks in event
    Float_t nKaonTracks;//number of kaon tracks
    Float_t M_KK; //Invariant mass of Kaon pairs
    Float_t PIDK; //Kaon PID
    Float_t PIDK1; //1st Kaon PID
    Float_t PIDK2; //2nd Kaon PID
    
    t1->SetBranchAddress("NTracks",&NTracks);
    t1->SetBranchAddress("nKaonTracks",&nKaonTracks);
    t1->SetBranchAddress("M_KK",&M_KK);
    t1->SetBranchAddress("PIDK",&PIDK);
    t1->SetBranchAddress("PIDK1",&PIDK1);
    t1->SetBranchAddress("PIDK2",&PIDK2);

Upon trying what you suggested, I have used

auto m_kk = d.Filter([](float pidk1, float pidk2){ pidk1>2, pidk1>2 ; return booleanValue;}, {"PIDK1", "PIDK2"}).Histo1D("M_KK");

And I get a series of errors, namely

/afs/cern.ch/work/b/bldelane/private/DST/Analysis/ROOT_Macro/FINAL_WORK/PHI/treelr.C:23:61: warning: relational comparison result unused [-Wunused-comparison]
    auto m_kk = d.Filter([](float pidk1, float pidk2){ pidk1>2, pidk1>2 ; return booleanValue;}, {"PIDK1", "PIDK2"}).Histo1D("M_KK"); 
                                                       ~~~~~^~
/afs/cern.ch/work/b/bldelane/private/DST/Analysis/ROOT_Macro/FINAL_WORK/PHI/treelr.C:23:82: error: use of undeclared identifier 'booleanValue'
    auto m_kk = d.Filter([](float pidk1, float pidk2){ pidk1>2, pidk1>2 ; return booleanValue;}, {"PIDK1", "PIDK2"}).Histo1D("M_KK"); 
                                                                                 ^
/afs/cern.ch/work/b/bldelane/private/DST/Analysis/ROOT_Macro/FINAL_WORK/PHI/treelr.C:23:70: warning: expression result unused [-Wunused-value]
    auto m_kk = d.Filter([](float pidk1, float pidk2){ pidk1>2, pidk1>2 ; return booleanValue;}, {"PIDK1", "PIDK2"}).Histo1D("M_KK"); 

I have read crash course, but I am unclear about how to fix this? Could you please advise me on how to proceed?

Alternatively, what would be the “old fashioned way” to fill a histogram? I know Draw() allows me to produce histograms that I can save as pdfs, but is there a way to save a TH1F object and save it to file fo future fitting?

Thanks,

Blaise

Hi,

about type guessing: you did the right thing specifying the float type as template argument. This limitation of ROOT will be soon lifted and all types will be guessable by the system.

about the empty histogram, I do not have an explanation. The code is fine: is ever pidk1 greater than 2? Can you share the ntuple or part of it?

This

auto m_kk = d.Filter([](float pidk1, float pidk2){ pidk1>2, pidk1>2 ; return booleanValue;}, {"PIDK1", "PIDK2"}).Histo1D("M_KK")

is not C++ but rather pesudocode. Perhaps you meant:

auto m_kk = d.Filter([](float pidk1, float pidk2){ return pidk2>2 && pidk1>2 ;}, {"PIDK1", "PIDK2"}).Histo1D("M_KK")

What you have is not a “read crash” but rather a compiler error, which is perfectly justified :slight_smile:

Cheers,
D

1 Like

Hi,

Following your suggestion, when then requiring

m_kk->Draw();

All I get is an empty canvas, with no histogram. Do you have any suggestion on the matter? Thanks.

Hi,

no. Is the histogram filled with any entry?

Cheers,
Danilo

Hi,

No - the canvas is completely black with no histogram. I tried:

ROOT::Experimental::TDataFrame d(*t1);
auto m_kk = d.Filter([](float pidk1, float pidk2){ return pidk2>2 && pidk1>2 ;}, {"PIDK1", "PIDK2"}).Histo1D<Float_t>("M_KK");
m_kk->Draw();

Cheers,

Blaise

Hi Blaise,

sure. I am asking if the histo has any entry at all: can you try the GetEntries method on it?

Cheera,
D

Hi @Danilo,

I was literally about to rectify my reply. I have indeed retrieved the number of entries, by

m_kk->GetEntries();

And all seems fine. I assume that m_kk is filled correctly.

Thanks, and sorry about the confusion,

Blaise

Hi,

are you sure that you are not closing a scope and the histogram, and therefore its graphical representation, is disappearing? Can you post the entire program/macro you are running? Can you try with DrawClone to avoid the deletion to affect the graphical representation of the object?

Cheers,
D

Hi,

using the following commands in the ROOT shell interactively

TFile *fin = new TFile("tmp_outfile.root");
//ROOT::EnableImplicitMT(); 
ROOT::Experimental::TDataFrame d(*t1);
auto m_kk = d.Filter([](float pidk1, float pidk2){ return pidk2>2 && pidk1>2 ;}, {"PIDK1", "PIDK2"}).Histo1D<Float_t>("M_KK");
TTree *t1 = (TTree*)fin->Get("t1");
m_kk->Draw();

Things work fine. Placing the same commands in a macro:

#include <TH1.h>
#include <TH2.h>
#include <TStyle.h>
#include <TCanvas.h>

void treelr()
{
    TFile *fin = new TFile("tmp_outfile.root");
    TTree *t1 = (TTree*)fin->Get("t1");
    TCanvas *c1 = new TCanvas("c1","c1");
    c1->cd();
   //ROOT::EnableImplicitMT(); 
    ROOT::Experimental::TDataFrame d(*t1);
    
    auto m_kk = d.Filter([](float pidk1, float pidk2){ return pidk2>2 && pidk1>2 ;}, {"PIDK1", "PIDK2"}).Histo1D<Float_t>("M_KK");
   m_kk->Draw();
}

The canvas is generated, without any histogram; In addition, how can I set the range of the histogram?

Thanks again,

Blaise

Hi,

as I said, this is due to the fact that the histogram goes out of scope. This is a behaviour due to how C++ itself works. Please use DrawClone.
As for the range, you can use TAxis methods, for example:

myhisto.GetXaxis()->SetRangeUser(myminval,mymaxval);

Cheers,
D

1 Like

Hi @Danilo,

Is there a way I can specify directly the range for m_kk and its binning, much like for usual histograms?

When trying in my macro

 m_kk->GetXaxis()->SetRangeUser(0,100); 
 m_kk->DrawClone();

or

 m_kk->SetAxisRange(0, 100,"X"); 
 m_kk->DrawClone();

An odd behaviour occurs: the range is redue from ~0 to 1000 (original) to about 0 to 400, with no histogram being filled. The issue is probably along the lines of the of my previous queries, and I would be grateful if you could advise me one last time on how to solve this. I apologise for my ignorance, I am still a beginner.

Thanks,

Blaise

Hi,

you can select the range of your histogram in several ways.

tdf.Histo1D("myBranch", nBins, xmin, xmax);
// or
tdf.Histo1D(TH1F("myname","mytitle",nbind, xmin, xmax), "myBranch");

see
https://root.cern/doc/master/classROOT_1_1Experimental_1_1TDataFrameInterface.html#a6787b03b80ca915f460c189ac6cb9402
and
https://root.cern/doc/master/classROOT_1_1Experimental_1_1TDataFrameInterface.html#a9645740ca68b9100b61de883169cc638

Then, the issue you are having with axes is something different. I do not understand: you set a range from 0 to 100 and you see an axis from 0 to 400?

Cheers,
D

Hi,

All I would like to do is to use what you suggest

ROOT::Experimental::TDataFrame d(*t1);
auto m_kk = d.Filter([](float pidk1, float pidk2){ return pidk2>2 && pidk1>2 ;}, {"PIDK1", "PIDK2"}).Histo1D<Float_t>("M_KK");

And obtain a histogram where I can set the range and the number of bins. And yes, I try setting a range from 0 to 100, but all I get is an empty histogram with range 0 to bout 400.

can I combine

auto m_kk = d.Filter([](float pidk1, float pidk2){ return pidk2>2 && pidk1>2 ;}, {"PIDK1", "PIDK2"}).Histo1D<Float_t>("M_KK");

With the methods

tdf.Histo1D("myBranch", nBins, xmin, xmax);
// or
tdf.Histo1D(TH1F("myname","mytitle",nbind, xmin, xmax), "myBranch");

As you suggest?

Thank you for your patience.

Hi,

yes.

auto m_kk = d.Filter([](float pidk1, float pidk2){ return pidk2>2 && pidk1>2 ;}, {"PIDK1", "PIDK2"}).Histo1D<Float_t>("M_KK", 123, 0 , 100);
// or 
auto m_kk = d.Filter([](float pidk1, float pidk2){ return pidk2>2 && pidk1>2 ;}, {"PIDK1", "PIDK2"}).Histo1D<Float_t>(TH1F("m_kk","m_kk", 123, 0 ,100), "M_KK");

Cheers,
D

1 Like

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