Trees

ROOT provides the TTree and the TNtuple class to store large quantities of same-class objects.
A tree is a typical data container used for example by all LHC (Large Hadron Collider) experiments.
Trees are optimized to reduce disk space and enhance access speed.

A tree consists of a list of independent columns, called branches. The TBranch class represents a branch. A branch can contain all kind of data, such as objects or arrays in addition to all the simple types.

A TNtuple is a TTree , which is limited to contain only floating-point numbers.


Tree tutorials

Tree classes

ROOT provides numerous classes for trees and branches, of which the following are among the most used:

  • TTree
    Represents a columnar data set. Any C++ type can be stored in its columns.
  • TNtuple
    A simple TTree restricted to a list of float variables only.
  • TBranch
    Organizes columns, i.e. branches, of a TTree.
  • TChain
    A list of ROOT files containing TTree objects.

Working with trees

OOT offers many possibilities to work with trees, for example:

Creating a tree

  • Use the TTree constructor to create a tree.

Example

   TTree t("MyTree","Example Tree");

It creates a tree with the title Example Tree.

Creating a tree from a folder structure

You can build a folder structure and create a tree with branches for each of the sub-folders.

Example

TTree folder_tree("MyFolderTree","/MyFolder");

MyFolder is the top folder. / indicates the TTree constructor that a folder is being used. You can fill the tree by placing the data into the folder structure and then calling the TTree::Fill() method.

Example: Building a tree from an ASCII file

The tutorial $ROOTSYS/tutorials/tree/cernbuild.C provides an example how to build a TTree from an ASCII file. The input file is cernstaff.dat that contains statistics about the staff at CERN.

The cernbuild.C ROOT macro creates a root file (cernstaff.root) and prints the tree T and its branches with TTree::Print().

root [0] .x cernbuild.C
******************************************************************************
*Tree    :T         : CERN 1988 staff data                                   *
*Entries :     3354 : Total =          176339 bytes  File  Size =      15005 *
*        :          : Tree compression factor =   2.74                       *
******************************************************************************
*Br    0 :Category  : Category/I                                             *
*Entries :     3354 : Total  Size=      14073 bytes  One basket in memory    *
*Baskets :        0 : Basket Size=      32000 bytes  Compression=   1.00     *
*............................................................................*
*Br    1 :Flag      : Flag/i                                                 *
*Entries :     3354 : Total  Size=      14049 bytes  One basket in memory    *
*Baskets :        0 : Basket Size=      32000 bytes  Compression=   1.00     *
*............................................................................*
*Br    2 :Age       : Age/I                                                  *
*Entries :     3354 : Total  Size=      14043 bytes  One basket in memory    *
*Baskets :        0 : Basket Size=      32000 bytes  Compression=   1.00     *
*............................................................................*
*Br    3 :Service   : Service/I                                              *
*Entries :     3354 : Total  Size=      14067 bytes  One basket in memory    *
*Baskets :        0 : Basket Size=      32000 bytes  Compression=   1.00     *
*............................................................................*
*Br    4 :Children  : Children/I                                             *
*Entries :     3354 : Total  Size=      14073 bytes  One basket in memory    *
*Baskets :        0 : Basket Size=      32000 bytes  Compression=   1.00     *
*............................................................................*
*Br    5 :Grade     : Grade/I                                                *
*Entries :     3354 : Total  Size=      14055 bytes  One basket in memory    *
*Baskets :        0 : Basket Size=      32000 bytes  Compression=   1.00     *
*............................................................................*
*Br    6 :Step      : Step/I                                                 *
*Entries :     3354 : Total  Size=      14049 bytes  One basket in memory    *
*Baskets :        0 : Basket Size=      32000 bytes  Compression=   1.00     *
*............................................................................*
*Br    7 :Hrweek    : Hrweek/I                                               *
*Entries :     3354 : Total  Size=      14061 bytes  One basket in memory    *
*Baskets :        0 : Basket Size=      32000 bytes  Compression=   1.00     *
*............................................................................*
*Br    8 :Cost      : Cost/I                                                 *
*Entries :     3354 : Total  Size=      14049 bytes  One basket in memory    *
*Baskets :        0 : Basket Size=      32000 bytes  Compression=   1.00     *
*............................................................................*
*Br    9 :Division  : Division/C                                             *
*Entries :     3354 : Total  Size=      25326 bytes  File Size  =       8325 *
*Baskets :        1 : Basket Size=      32000 bytes  Compression=   2.49     *
*............................................................................*
*Br   10 :Nation    : Nation/C                                               *
*Entries :     3354 : Total  Size=      24209 bytes  File Size  =       6680 *
*Baskets :        1 : Basket Size=      32000 bytes  Compression=   3.05     *
*............................................................................*
(TFile *) nullptr
root [1]

Filling a tree

A loop on all defined branches (see → Branches) is executed.

Writing a tree

The data of a tree are saved in a ROOT file (see → ROOT files).

The TTree::Write() method is needed to write the ROOT file header.

When writing a TTree to a ROOT file and if the ROOT file size reaches the value stored in the TTree::GetMaxTreeSize(), the current ROOT file is closed and a new ROOT file is created. If the original ROOT file is named myfile.root, the subsequent ROOT files are named myfile_1.root, myfile_2.root, etc.

Printing the summary of a tree

  • Use the TTree::Print(Option_t * option = “”) method to print a summary of the tree contents.

  • option = "all": Friend trees are also printed.
  • option = "toponly": Only the top level branches are printed.
  • option = "clusters": Information about the cluster of baskets is printed.

Example

root[] TFile f("cernstaff.root")
root[] T->TTree::Print()

******************************************************************************
*Tree    :T         : CERN 1988 staff data                                   *
*Entries :     3354 : Total =          175531 bytes  File  Size =      47246 *
*        :          : Tree compression factor =   3.69                       *
******************************************************************************
*Br    0 :Category  : Category/I                                             *
*Entries :     3354 : Total  Size=      13985 bytes  File Size  =       4919 *
*Baskets :        1 : Basket Size=      32000 bytes  Compression=   2.74     *
*............................................................................*
*Br    1 :Flag      : Flag/i                                                 *
*Entries :     3354 : Total  Size=      13965 bytes  File Size  =       2165 *
*Baskets :        1 : Basket Size=      32000 bytes  Compression=   6.23     *
*............................................................................*
*Br    2 :Age       : Age/I                                                  *
*Entries :     3354 : Total  Size=      13960 bytes  File Size  =       3489 *
*Baskets :        1 : Basket Size=      32000 bytes  Compression=   3.86     *
*............................................................................*
*Br    3 :Service   : Service/I                                              *
*Entries :     3354 : Total  Size=      13980 bytes  File Size  =       2214 *
...
...

Showing an entry of a tree

Example

Showing an entry from the cernstaff.root file (see → Building a tree from an ASCII file).

root[] TFile f("cernstaff.root")
root[] T->Show(42)

======> EVENT:42
Category = 301
Flag = 13
Age = 56
Service = 31
Children = 0
Grade = 9
Step = 8
Hrweek = 40
Cost = 8645
Division = EP
Nation = CH

Scanning trees

  • Use the TTree::Scan() method to show all values of the list of leaves.

Example

Scanning the cernstaff.root file (see → Building a tree from an ASCII file).

   root[] TFile f("cernstaff.root")
   root[] T->Scan("Cost:Age:Children")

   ************************************************
   *    Row *    Cost *       Age *    Children   *
   ************************************************
   *     0 *    11975 *        58 *             0 *
   *     1 *    10228 *        63 *             0 *
   *     2 *    10730 *        56 *             2 *
   *     3 *     9311 *        61 *             0 *
   *     4 *     9966 *        52 *             2 *
   *     5 *     7599 *        60 *             0 *
   *     6 *     9868 *        53 *             1 *
   *     7 *     8012 *        60 *             1 *
   *     8 *     8813 *        51 *             0 *
   *     9 *     7850 *        56 *             1 *
   *    10 *     7599 *        51 *             0 *
   *    11 *     9315 *        54 *             2 *
   *    12 *     7599 *        54 *             0 *
   *    13 *     7892 *        46 *             0 *
   *    14 *     7850 *        54 *             1 *
   *    15 *     7599 *        57 *             0 *
   *    16 *     8137 *        55 *             0 *
   *    17 *     7850 *        55 *             1 *
   *    18 *     7294 *        57 *             1 *
   *    19 *     8101 *        51 *             2 *
   *    20 *     5720 *        54 *             0 *
   *    21 *    15832 *        57 *             1 *
   *    22 *    12226 *        63 *             1 *
   *    23 *    13135 *        56 *             0 *
   *    24 *     9617 *        49 *             0 *

Tree Viewer

With the Tree Viewer you can examine a tree in a GUI.

Note

You can also use the ROOT Object Browser to examine a tree that is saved in a ROOT file. See → ROOT Object Browser.

  • Use the TTreeViewer class to open the ROOT file (containing the tree) in the Tree Viewer.

Example

Open the Tree Viewer for the cernstaff.root file (see → Building a tree from an ASCII file) that contains the tree T.

   root[] TFile f("cernstaff.root")
   root[] new TTreeViewer("T")

Figure: Tree Viewer.

Drawing correlating variables in a scatterplot

You can show the correlation between the variables, listed in the TTreeViewer , by drawing a scatterplot.

  • Select a variable in the TTreeViewer and drag it to the X:-empty- entry.
  • Select a second variable and drag it to the Y:-empty- entry.

Figure: Variables Age and Cost selected for the scatterplot.

  • Click Scatterplot

Figure: Scatterplot icon.

The scatterplot is drawn.

Figure: Scatterplot of the variables Age and Cost.

Note, that not each (x,y) point on a scatterplot represents two values in your n−tuple. In fact, the scatterplot is a grid and each square in the grid is randomly populated with a density of dots that’s proportional to the number of values in that grid.

Branches

You can organize columns, this is branches, of a tree with the TBranch class. A variable on a TBranch is called a leaf (TLeaf ).

The branch type differs by what is stored in it. A branch can contain the following data:

  • an entire object,
  • a list of simple variables,
  • contents of a folder,
  • contents of a TList ,
  • an array of objects.

If two variables are independent and the variables will not be used together, place them on separate branches. If the variables are related, such as the coordinates of a point, create one branch with both coordinates on it.

Adding a branch

   auto branch = tree.Branch(branchname, address, leaflist, bufsize)

address is the address of the first item of a structure. leaflist is the concatenation of all the variable names and types separated by a colon character. The variable name and the variable type are separated by a slash (/). The variable type must be 1 character. For more information on adding a branch to tree, see → TTree .

Note

Do not use the TBranch constructor to add a branch to a tree.

Adding a branch with a folder

  • Use the following syntax to add a branch with a folder:
   tree->Branch("/aFolder")

This creates one branch for each element in the folder. The method returns the total number of branches created.

Adding a branch of STL collections

A STLcollection is a address of a pointer to std::vector, std::list, std::deque, std::set or std::multiset containing pointers to objects.

  • Use the following syntax of the TTree::Branch() method to add a STLcollection:
   auto branch = tree.Branch(branchname, STLcollection, buffsize, splitlevel);
 

If the splitlevel is a value bigger than 100 TTree::kSplitCollectionOfPointers then the STLcollection will be written in split mode.

If a dynamic structures changes with each entry, you have to redefine the branch address with TBranch::SetAddress before filling the branch again.

Adding a branch of objects

  • Use the following syntax of the TTree::Branch() method to add objects to a tree:
   MyClass object;
   auto branch = tree.Branch(branchname, &object, bufsize, splitlevel)

&object must be the address of a valid object. The object must not be destroyed (i.e. be deleted) until the TTree is deleted or TTree::ResetBranchAddress is called.

For the splitlevel the following values are available:

splitlevel=0
The object is serialized in the branch buffer.

splitlevel=1 (default)
This branch will automatically be split into sub-branches, with one sub-branch for each data member or object of the object itself. In case the object member is a TClonesArray , it is processed as a TObject , but only one branch.

splitlevel=2
This branch will automatically be split into sub-branches, with one sub-branch for each data member or object of the object itself. In case the object member is a TClonesArray , it is processed as a TObject , but only one branch.

Adding a branch to an existing tree

You can add a branch to an existing tree.

Example

If one variable in the tree was computed with a certain algorithm, you may want to try another algorithm and compare the results. To do this, you can add a new branch, fill it, and save the tree.

void tree3AddBranch() {
   TFile f("tree3.root", "update");
   Float_t new_v;
   auto t3 = f->Get<TTree>("t3");
   auto newBranch = t3->Branch("new_v", &new_v, "new_v/F");
   Long64_t nentries = t3->GetEntries(); // read the number of entries in the t3
   for (Long64_t i = 0; i < nentries; i++) {
      new_v = gRandom->Gaus(0, 1);
      newBranch->Fill();
   }
   t3->Write("", TObject::kOverwrite); // save only the new version of the tree
}

kOverwrite in the Write() method causes the tree to be overwritten.

Using trees for data analysis

The following methods are available for data analysis using trees:

Using TTree:Draw()

With the TTree::Draw() method, you can easily plot variables (this is leaf).

Example

Open the cernstaff.root file (see → Building a tree from an ASCII file) and lists its content.

root [0] TFile f("cernstaff.root")
root [1] f.ls()
TFile**      cernstaff.root
 TFile*      cernstaff.root
  KEY: TTree   T;1   CERN 1988 staff data

The cernstaff.root file contains the TTree T. A pointer is created to the tree.

   root [2] TTree *MyTree = T

To show the different Draw() options, a canvas with four sub-pads is created.

   root [3] TCanvas *myCanvas = new TCanvas()
   root [4] myCanvas->Divide(2,2)

The first pad with is activated with TCanvas::cd.

   root [5] myCanvas->cd(1)

The Cost variable is drawn. TTree::Draw automatically creates a histogram. The style of the histogram is inherited from the TTree attributes.

   root [9] MyTree->Draw("Cost")

Figure: The variable Cost drawn in a histogram.

Next, the second pad is activated and scatter plot is drawn. Two dimensions (here Cost and Age) are separated by a colon (“x:y”).
In general, this parameter is a string that contains up to three expressions, one for each dimension, separated by a colon (“e1:e2:e3”).

   root [10] myCanvas->cd(2)
   root [11] MyTree->Draw("Cost:Age")

Figure: The variable Cost and Age drawn in a histogram.

Next, the third pad is activated and a selection is added. Cost versus Age for the entries where the nation is equal to “CH” is drawn.
You can use any C++ operator. The value of the selection is used as a weight when filling the histogram. If the expression includes only Boolean operations the result is 0 (histogram is not filled) or 1 ((histogram is filled).

   root [11] myCanvas->cd(3)
   root [22] MyTree->Draw("Cost:Age","Nation == \"CH\"")

Figure: The variable Cost and Age with a selection drawn in a histogram.

Next, the fourth pad is activated and the histogram is drawn with the draw option surf2. Refer to the THistPainter class for possible draw options.

   root [11] myCanvas->cd(4)
   root [22] MyTree->Draw("Cost:Age","Nation == \"CH\"","colz")

Figure: The variable Cost and Age with a selection and a draw option drawn in a histogram.

Using TTree::MakeClass()

  • Use the TTree::MakeClass() method, to generate a skeleton class for looping over the entries of a tree.

Using TTree::MakeSelector()

Example: Using a ROOT macro for data analysis

The following example shows a simple ROOT macro for analyzing a tree. The ROOT macro calculates the sum of all event sizes.

Example

#include "TFile.h"
#include "TTree.h"
#include "TBranch.h"

void CountEvents()
{
// Variables used to store the data.

// Sum of data size (in bytes) of all events.
   Int_t totalSize = 0;

// Size of the current event.
   Int_t eventSize = 0;

// Pointer to the event.fEventsize branch.
   TBranch *eventSizeBranch = 0;

// Open the ROOT file.
   TFile *f = TFile::Open("http://root.cern/files/introtutorials/eventdata.root");
   if (f == 0) {

// If we cannot open the ROOT file, print an error message and return immediately.
      printf("Error: cannot open http://root.cern/files/introtutorials/eventdata.root!\n");
      return;
   }

// Get a pointer to the tree.
   TTree *tree = (TTree *)f->Get("EventTree");

// Use SetBranchAddress() with simple types (e.g. double, int) instead of objects (e.g. std::vector<Particle>).
   tree->SetMakeClass(1);

// Connect the branch "fEventSize" with the variable eventSize that we want to contain the data.
// While we are at it, ask the tree to save the branch in eventSizeBranch.
   tree->SetBranchAddress("fEventSize", &eventSize, &eventSizeBranch);

// First, get the total number of entries.
   Long64_t nentries = tree->GetEntries();

// Then loop over all of them.
   for (Long64_t i=0;i<nentries;i++) {

// Load the data for TTree entry number "i" from branch
// fEventSize into the connected variable (eventSize).
      eventSizeBranch->GetEntry(i);
      totalSize += eventSize;
   }
   Int_t sizeInMB = totalSize/1024/1024;
   printf("Total size of all events: %d MB\n", sizeInMB);
}

Now you can create a histogram, for example for the X position of the particles (hPosX). For more information on creating a histogram for this data analysis, see → Example: Histogramming a data analysis

Using Chains

A chain is a list of ROOT files containing TTree objects. A chain is created via the TChain object.

Example

There are three ROOT files file1.root, file2.root and file3.root. Each ROOT file contains a tree T. The chain is created with TChain::Add().

   TChain chain("T");
   chain.Add("file1.root");
   chain.Add("file2.root");
   chain.Add("file3.root");

The name of the TChain is the same as the name of the tree.

The TChain class is derived from the TTree class.

Example

To generate an histogram corresponding to the attribute x in the tree T by processing sequentially the three files of this chain, you can write:

   chain.Draw("x");

The next example illustrates how to set the address of an object to be read and how to loop on all events of all files of the chain.

TH1F* hnseg(nullptr);
void processChain(){
// Create a chain out of three ROOT files.
   TChain chain("T");
   chain.Add("file1.root");
   chain.Add("file2.root");
   chain.Add("file3.root");

// Create an histogram.
   hnseg = new TH1F("hnseg","Number of segments for selected tracks",4096,0,8192);

// Specify the address where to read the event object.
// In the program writing the ROOT files, the event was stored in a branch called "event".
   Event *event = new Event();

// The object must be created before setting the branch address.
   chain.SetBranchAddress("event", &event);

// Start main loop on all events.
// In case you want to read only a few branches, use TChain::SetBranchStatus to activate/deactivate a branch.
   Int_t nevent = chain.GetEntries();
   for (Int_t i=0;i<nevent;i++) {
      chain.GetEvent(i);              //Read the complete accepted event in memory.
      hnseg->Fill(event->GetNseg());  //Fill the histogram with number of segments.
   }

N-tuples

An N-tuple TNtuple is a simple TTree restricted to a list of float variables only.

Writing simple N-tuples

In the following example, three independent variables (voltage, pressure and temperature) and one variable (current) which depends on the others according to very simple law, and an additional Gaussian smearing, are written to a ROOT file.

Example

void write_ntuple_to_file(){
   TFile ofile("ntuple.root","CREATE");

// Initialize the TNtuple.
   TNtuple cond_data("cond_data","Example N-Tuple","Potential:Current:Temperature:Pressure");

// Fill it randomly to fake the acquired data.
   TRandom3 rndm;
   float pot,cur,temp,pres;
   for (int i=0;i<10000;++i){

// Get voltage.
      pot=rndm.Uniform(0.,10.);

// Get temperature.
      temp=rndm.Uniform(250.,350.);

// Get pressure.
      pres=rndm.Uniform(0.5,1.5);

// Current.
      cur=pot/(10.+0.05*(temp-300.)-0.2*(pres-1.));

// Add some random smearing (measurement errors).
// 1% error on voltage.
      pot*=rndm.Gaus(1.,0.01);

// 0.3 absolute error on temperature.
      temp+=rndm.Gaus(0.,0.3);

// 1% error on pressure.
      pres*=rndm.Gaus(1.,0.02);

// 1% error on current.
      cur*=rndm.Gaus(1.,0.01);

// Write to an N-tuple.
      cond_data.Fill(pot,cur,temp,pres);
   }

// Save the N-tuple and close the ROOT file.
cond_data.Write();
}

In the ROOT Object Browser you can find the columns of your n-tuple written as leafs. Clicking on one of the leafs obtains the histogram of the appropriate variable.

   TFile f("ntuple.root")
   TBrowser b

Figure: N-tuple in the ROOT Object Browser.

Use the following commands at the system prompt or in the ROOT shell to draw a simple correlation plot:

   $ root ntuple.root
   root [1] cond_data->Draw("Current:Potential")

Figure: Current/Potential correlation plot.

Reading N-tuples

The following example shows how to read the data from a ROOT N-tuple.

Example

void read_ntuple_from_file(){

// Open a ROOT file, save the N-tuple and close the ROOT file.

   TFile in_file("ntuple.root");
   TNtuple* my_tuple;in_file.GetObject("cond_data",my_tuple);
   float pot,cur,temp,pres;
   float* row_content;
   cout << "Potential\tCurrent\tTemperature\tPressure\n";
   for (int irow=0;irow<my_tuple->GetEntries();++irow){
      my_tuple->GetEntry(irow);
      row_content = my_tuple->GetArgs();
      pot = row_content[0];
      cur = row_content[1];
      temp = row_content[2];
      pres = row_content[3];
      cout << pot << "\t" << cur << "\t" << temp << "\t" << pres << endl;
   }
}
.x read_ntuple_from_file.C
Potential     Current     Temperature     Pressure
10.0756       1.19547     266.282         0.795519
5.37825       0.484204    324.413         1.23512
3.86672       0.449388    271.75          0.724136
8.90976       0.825837    316.434         0.981151
7.38798       0.681633    313.64          1.26236
2.07977       0.229839    279.348         0.597366
1.40566       0.148727    289.691         1.18724
7.5371        0.778955    286.499         0.657541
3.32501       0.427904    259.546         0.926214
3.70217       0.312457    333.17          0.643932
6.12199       0.591663    306.463         0.974056
4.30285       0.416644    309.89          1.18534
...           ...         ...             ...

Writing arbitrary N-tuples

You can write N-tuples of arbitrary type by using the TBranch class. This is especially important as TNtuple::Fill() accepts only floats.

Example

The same N-tuple as before is created, but the branches are booked directly. The Fill() function then fills the current values of the connected variables to the tree.

void write_ntuple_to_file_advanced(const std::string& outputFileName="ntuple.root",unsigned int numDataPoints=1000000)
{
   TFile ofile(outputFileName.c_str(),"RECREATE");

// Initialize the TNtuple.
   TTree cond_data("cond_data", "Example N-tuple");

// Define the variables and book them for the N-tuple.
   float pot,cur,temp,pres;
   cond_data.Branch("Potential", &pot, "Potential/F");
   cond_data.Branch("Current", &cur, "Current/F");
   cond_data.Branch("Temperature", &temp, "Temperature/F");
   cond_data.Branch("Pressure", &pres, "Pressure/F");
   for (int i=0;i<numDataPoints;++i){

// Fill it randomly to fake the acquired data.
      pot=gRandom->Uniform(0.,10.)*gRandom->Gaus(1.,0.01);
      temp=gRandom->Uniform(250.,350.)+gRandom->Gaus(0.,0.3);
      pres=gRandom->Uniform(0.5,1.5)*gRandom->Gaus(1.,0.02);
      cur=pot/(10.+0.05*(temp-300.)-0.2*(pres-1.))*
      gRandom->Gaus(1.,0.01);

// Write to the N-tuple.
      cond_data.Fill();
      }

// Save the N-tuple and close the ROOT file.
   cond_data.Write();
   ofile.Close();
}

Reading TTrees, TChains and TNtuples

The TTreeReader class provides a simple, robust and fast interface to read values from ROOT columnar data sets such as TTree , TChain or TNtuple .

Example

A simple example using a TTreeReader.

// Create a histogram.
   auto myHist = new TH1F("h1","ntuple",100,-4,4);

// Open the file containing the tree.
   auto myFile = TFile::Open("hsimple.root");

// Create a TTreeReader for the tree.
   TTreeReader myReader("ntuple", myFile);

// The branch "px" contains floats; access them as myPx.
   TTreeReaderValue<Float_t> myPx(myReader, "px");

// The branch "py" contains floats, too; access those as myPy.
   TTreeReaderValue<Float_t> myPy(myReader, "py");

// Loop over all entries of the TTree or TChain.
   while (myReader.Next()) {
      // Just access the data as if myPx and myPy were iterators (note the '*'in front of them):
      myHist->Fill(*myPx + *myPy);
   }
   myHist->Draw();