Read values from root file

Hi. Suppose I have a root file with one tree and several leaves (and no branches). I want to loop over the entries of a specific leaf (in order to pose some constraints - cuts), and print it into a histo.

The second question is how I can do it for two root files (with different trees and leaves) and in the end to combine them into one histo.

Any ideas?


please take a look at the tutorials, in particular the ones under “Tree tutorials”. You can also search this forum for more specific issues.

As an overview, there are four main ways to loop over ROOT data (lower to higher level):

  1. using TTree and SetBranchAddress (see e.g. this example)
  2. using TTreeReader and TTreeReaderValue (see e.g. this example)
  3. using TTree::Draw to directly create histograms (I could not find tutorials, documentation is here, some example usage is here)
  4. using TDataFrame (tutorials here, documentation here, requires ROOT v6.10 or superior). EDIT: since ROOT v6.14 TDataFrame has been renamed to RDataFrame and left the experimental stage.

To read multiple files containing trees with the same name and structure you have to create a TChain instead of a TTree object:

// creating a TTree from one file
TFile f("file.root");
TTree *t = nullptr;
f.GetObject("treename", t);
// creating a TChain from two files
TChain c("treename");

Simple example of creating a histogram of variable x from a tree contained in two files using TDataFrame:

#include "ROOT/TDataFrame.hxx"
using namespace ROOT::Experimental;

int main() {
  TDataFrame df("treename", {"file1.root","file2.root"});
  auto hist = df.Histo1D("x");
  return 0;
1 Like

Hello, thank you very much for the response. Inexperienced as I am I found another(?) way to do it, neater and closer to the c++ coding mentality. I solved my problem for one variable from one tree but things are not the same for 2 variables. I post the code:

int read(){
double energytop1=0;
double energytop12=0;

TFile *f = new TFile("susysignal_total.root");
TTree * signal_tree = (TTree*) f->Get("signal_Tree");
signal_tree->SetBranchAddress("energytop1",& energytop1);

TFile *g = new TFile("susybackground_total.root");
TTree * bgtree = (TTree*) g->Get("susybg_Tree");

TH1D *histo = new TH1D("histo","",100,0,2200);
TH1D *histo2 = new TH1D("histo2","",100,0,2200);

        for(int i=0; i<signal_tree->GetEntries(); ++i){


        for(int j=0; j<bgtree->GetEntries(); ++j){




NOTE: that there are 2 different root files with 2 different trees, but with the same leaves. But the variables (that correspond to leaves) have different number of entries.

The output of this is just one of the two histograms. Do you know how I should proceed? Thank you again.


we might discuss at length of what approach is closer to a “c++ coding mentality” (or whether such a thing exists at all :stuck_out_tongue_winking_eye:). In any case, this corresponds to method number 1. in my list above. If you preferred, you could add the two files to a TChain and loop once over it instead of looping twice over two different TTree, but the end result is the same.

I am not sure what you mean with “the output of this is just one of the two histograms”, but it might be because you are declaring energyop1 and energyop12 but you are calling SetBranchAddress on the first variable only, twice.

Also note that:

  • you can re-use the i index in the second loop as it is only defined inside the loop
  • your i and j indeces might overflow due to GetEntries() returning a long int that you are truncating to an int (compiling with -Wall should warn you about these kind of things – always use -Wall)
  • if this was a full-blown c++ program rather than a ROOT macro you would have to manually call delete to match each one of your new – especially on the TFiles, to close them properly. It is good practice to use std::unique_ptr (defined in header <memory> of the standard library), to define pointer types the automatically delete the pointee when they go out of scope.
  • you are declaring read as returning an int but you are not returning anything – you can make it a void instead to avoid compiler warnings

Most of the above quirks can be side-stepped by using TTreeReader+TTreeReaderValue or TDataFrame to manage the loop over your data; that’s one advantage of using higher level interfaces, in which you don’t have to care about these kind of details.

For completeness and future reference, your snippet would look like the following with TTreeReader (modulo typos :slight_smile: ):

// the two repeated snippets should be made into a single function called twice
void read() {
  TFile fsig("susysignal_total.root");
  TTreeReader rsignal("signal_Tree", &fsig);
  TTreeReaderValue<double> energytop_sig(rsignal, "energytop1");
  auto histo_sig = new TH1D("histo", "", 100, 0., 2200.);

  TFile fbg("susybackground_total.root");
  TTreeReader rbg("susybg_Tree", &fbg);
  TTreeReaderValue<double> energytop_bg(rbg, "energytop1");
  auto histo_bg = new TH1D("histo", "", 100, 0., 2200.);


and like the following with TDataFrame:

// the two repeated snippets should be made into a single function called twice
using namespace ROOT::Experimental;
void read() {
   TDataFrame dfsig("signal_Tree", "susysignal_total.root");
   auto histo_sig = dfsig.Histo1D("energytop1");

   TDataFrame dfbg("susybg_Tree", "susybackground_total.root");
   auto histo_bg = dfbg.Histo1D("energytop1");

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