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

RNTuple

RNTuple (for N-tuple and nested tuple) is the experimental evolution of TTree columnar data storage. RNTuple introduces new interfaces that are more robust.

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

ROOT 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.

Example: A simple tree

The following script builds a TTree from an ASCII file containing statistics about the staff at CERN. Both, staff.C and staff.dat are in available in $ROOTSYS/tutorials/tree.

The following script declares a structure called staff_t. It opens the ASCII file, creates a ROOT file and a TTree. Then it creates one branch with the TTree::Branch() method.
The first parameter of the Branch() method is the branch name.
The second parameter is the address from which the first leaf is to be read. In this example, it is the address of the structure staff. Once the branch is defined, the script reads the data from the ASCII file into the staff_t structure and fills the tree. The ASCII file is closed, and the ROOT file is written to disk saving the tree. Trees and histograms are created in the current directory, which is the ROOT file in our example. Hence an f->Write() saves the tree.

{
// Create the structure to hold the variables for the branch.
   struct staff_t {
   Int_t cat;
   Int_t division;
   Int_t flag;
   Int_t age;
   Int_t service;
   Int_t children;
   Int_t grade;
   Int_t step;
   Int_t nation;
   Int_t hrweek;
   Int_t cost;
   };
   staff_t staff;

// Open the ASCII file.
   FILE *fp = fopen("staff.dat","r");
   char line[81];

// Create a new ROOT file.
   TFile *f = new TFile("staff.root","RECREATE");

// Create a TTree.
   TTree *tree = new TTree("T","Staff data from ASCII file");

// Create one branch with all information from the structure.
   tree->Branch("staff",&staff.cat,"cat/I:division:flag:age:service:
   children:grade:step:nation:hrweek:cost");

// Fill the tree from the values in ASCII file.
   while (fgets(&line,80,fp)) {
      sscanf(&line[0],"%d%d%d%d",&staff.cat,&staff.division,
      &staff.flag,&staff.age);
      sscanf(&line[13],"%d%d%d%d",&staff.service,&staff.children,
      &staff.grade,&staff.step);
      sscanf(&line[24],"%d%d%d",&staff.nation,&staff.hrweek,
      &staff.cost);
      tree->Fill();
   }

// Check what the tree looks like.
   tree->Print();
   fclose(fp);
   f->Write();
}

Example: Building a tree from an ASCII file

The tutorial 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     *
*............................................................................*
...
...
...

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.

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.

Autosave

Autosave gives you the option to save all branch buffers every n byte. It is recommended to use Autosave for large acquisitions. If the acquisition fails to complete, you can recover the ROOT file and all the contents since the last Autosave.

You can also use TTree::SetAutosave() in the acquisition loop every n entry.

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 display 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 *

Indexing trees

  • Use TTree::BuildIndex() method to build an index table using expressions depending on the value in the leaves.

The index is built in the following way:

  • A pass on all entries is made like in TTree::Draw().
  • var1 = majorname
  • var2 = minorname
  • sel = 231 × majorname + minorname
  • For each entry in the tree the sel expression is evaluated and the result array is sorted into fIndexValues.

Once the index is calculated, an entry can be retrieved with TTree::GetEntryWithIndex(majornumber, minornumber).

Example

// To create an index using the leaves "Run" and "Event".
   tree.BuildIndex("Run","Event");

// To read entry corresponding to Run=1234 and Event=56789.
   tree.GetEntryWithIndex(1234,56789);
   

Note that majorname and minorname can be expressions using original tree variables e.g., "run-90000" or "event +3*xx".

In case an expression is specified, the equivalent expression must be computed when calling TTree::GetEntryWithIndex(majornumber, minornumber). To build an index with only majorname, specify minorname="0" (default).

Once the index is built, it can be saved with the TTree object with tree.Write().

The most convenient place to create the index is at the end of the filling process just before saving the tree header. If a previous index was calculated, it will be redefined by this new call.

Note that this function can also be applied to a TChain . The return value is the number of entries in the Index (< 0 indicates failure).

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.

The left panel contains the list of trees and their branches. The right panel displays the leaves or variables in the tree.

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 ). If two variables are independent and it is certain that the variables will not be used together, they should be placed on separate branches.

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 one 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 with 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 with 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 (this is be deleted) until the TTree is deleted or TTree::ResetBranchAddress is called.

The following values are available for the splitlevel:

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

splitlevel=1 (default)
This branch is automatically into sub-branches, with one sub-branch for each data member or object of the object itself. If the object member is a TClonesArray, it is processed as it is with splitlevel=2.

splitlevel=2
This branch is automatically split into sub-branches, with one sub-branch for each data member or object of the object itself. If the object member is a TClonesArray it is processed as a TObject, but only for 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.

Examples for writing and reading trees

The following sections are examples of writing and reading trees that range in complexity from a simple tree with a few variables to a tree with folders and complex event objects.

A tree with a C structure

Tutorial

tree2.C

In this tutorial is shown:

  • how to build branches from a C structure
  • how to make a branch with a fixed length array
  • how to make a branch with a variable length array
  • how to read selective branches
  • how to fill a histogram from a branch
  • how to TTree::Draw to draw a 3D plot

Adding friends to trees

Tutorial

tree3.C

Adding a branch is often not possible because the tree is a read-only file and you do not have permission to save the modified tree with the new branch. Even if you do have the permission, you risk loosing the original tree with an unsuccessful attempt to save the modification. Since trees are usually large, adding a branch could extend it over the 2 GB limit. In this case, the attempt to write the tree fails, and the original data is may also be corrupted. In addition, adding a branch to a tree enlarges the tree and increases the amount of memory needed to read an entry, and therefore decreases the performance.

For these reasons ROOT offers the concept of friends for trees (and chains) by adding a branch manually with TTree::AddFriend().

The TTree::AddFriend() method has two parameters, the first is the tree name and the second is the name of the ROOT file where the friend tree is saved. TTree::AddFriend() automatically opens the friend file.

Importing an ASCII file into a tree

Use TTree::ReadFile() to automatically define the structure of the TTree and read the data from a formatted ASCII file.

Example

{
   gROOT->Reset();
   TFile *f = new TFile("basic2.root","RECREATE");
   TH1F *h1 = new TH1F("h1","x distribution",100,-4,4);
   TTree *T = new TTree("ntuple","data from ascii file");
   Long64_t nlines = T->ReadFile("basic.dat","x:y:z");
   printf(" found %lld pointsn",nlines);
   T->Draw("x","z>2");
   T->Write();
}

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 a variable (a leaf).

Example

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

root [] TFile f("cernstaff.root")
root [] 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 [] TTree *MyTree = T

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

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

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

   root [] 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 [] 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 containing up to three expressions, one for each dimension, separated by a colon (“e1:e2:e3”).

   root [] myCanvas->cd(2)
   root [] 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 [] myCanvas->cd(3)
   root [] 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 [] myCanvas->cd(4)
   root [] MyTree->Draw("Cost:Age","Nation == \"CH\"","colz")

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

The TTree::Draw() method also accepts TCut objects. A TCut object is a specialized string object used for TTree selections.

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. A 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();