[[root:root|Getting started with ROOT]] -> [[root:pyroot|Useful pyROOT snippets]] → [[root:pyroot_ttree|Handling TTree trees]]
====== Handling TTree trees ======
[[https://root.cern.ch/doc/master/classTTree.html|Here]] is the class reference for ''TTree''.
[[root:example_TTree|Here]] is one file containing multiple examples.
===== Creating a TTree with branches and writing it to a TFile =====
Below is an example of creating and saving a tree with two branches (variables) each containing a randomly distributed variable for each event.
If you fill a ''TTree'' in ''C++'', you can pass a double as a reference, called the //address// of the branch, from [[https://root.cern.ch/root/html/tutorials/tree/tree1.C.html|the official tree1.C example]]:
TTree tree("tree_name","tree title");
Float_t px;
tree.Branch("px",&px,"px/F");
In ''python'' however, you will need to use an array instead, for example the ''array'' class. More information on the [[https://root.cern/doc/master/classTTree.html#ac1fa9466ce018d4aa739b357f981c615|TTree::Branch(name,address, leaflist) method]].
from ROOT import TFile, TTree, gRandom
from array import array
# make new root file with new tree
file = TFile("tree.root", 'recreate')
tree = TTree("tree_name", "tree title")
# create 1 dimensional float arrays as fill variables, in this way the float
# array serves as a pointer which can be passed to the branch
px = array('d',[0])
phi = array('d',[0])
# create the branches and assign the fill-variables to them as doubles (D)
tree.Branch("px", px, 'normal/D')
tree.Branch("phi", phi, 'uniform/D')
# create some random numbers, assign them into the fill variables and call Fill()
for i in xrange(10000):
px[0] = gRandom.Gaus(20,2)
phi[0] = gRandom.Uniform(2*3.1416)
tree.Fill()
# write the tree into the output file and close the file
file.Write()
file.Close()
Alternatively, you could use the ''numpy'' class:
import numpy
...
px = numpy.zeros(1, dtype=float)
phi = numpy.zeros(1, dtype=float)
...
Note that ''file.Write()'' will write all objects (trees, histograms, graphs, ...) that are still opened. Instead, you can write a individual object, in this case a ''TTree'', with the [[https://root.cern.ch/doc/master/classTTree.html#af6f2d9ae4048ad85fcae5d2afa05100f|Write() method]]:
tree.Write()
Optional arguments are a string for a new name and some writing options, e.g. to overwrite with ''TFile.kOverwrite''.
===== Filling a branch with multiple values per event =====
Here is an example of filling a tree with a variable number of particles, each having a ''pt'' variable:
from ROOT import TFile, TTree, gRandom
from array import array
file = TFile("tree.root", 'recreate')
tree = TTree("tree_name", "tree title")
Nmax = 10
nParticles = array( 'i', [ 0 ] )
pt = array( 'd', Nmax*[ 0. ] )
tree.Branch( 'nParticles', nParticles, 'nParticles/I' )
tree.Branch( 'pt', pt, 'pt[nParticles]/D' )
for i in xrange(1000): # loop over events
nParticles[0] = int(gRandom.Uniform()*10)
for j in xrange(nParticles[0]): # loop over particles in this event
pt[j] = gRandom.Gaus(20,2)
tree.Fill()
file.Write("",TFile.kOverwrite)
file.Close()
===== Looping over a TTree =====
The classic way of looping through a tree is:
N = tree.GetEntries()
for i in xrange(N):
tree.GetEntry(i)
print tree.px
where you can access the values in branch ''px'' for each event. A more elegant and pythonic way is the following:
for event in tree:
print event.px
If you also need the event's index:
for i, event in enumerate(tree):
print i, event.px
===== Making a histogram with TTree =====
See [[root:pyroot_th1#filling_a_histogram_from_a_tree|this page]].
===== Adding and saving a branch to a TTree in a TFile =====
Here is simple example of adding a completely new branch to an existing tree.
from ROOT import TFile, TTree, gRandom
# reopen tree file
file = TFile("tree.root",'update')
tree = file.Get("tree_name")
# make new variable and add it as a branch to the tree
py = array('d',[0])
branch = tree.Branch("py", py, 'py/D')
# fill the branch
N = tree.GetEntries()
for i in xrange(N):
tree.GetEntry(i)
py[0] = gRandom.Gaus(23,4)
branch.Fill()
# overwrite the tree in the output file and close the file
file.Write("",TFile.kOverwrite)
file.Close()
More interestingly, you can **access existing branches** in the tree and use those values to create new variables. Here is an example of making a new branch containing transverse momentum for each event, assuming the tree has branches ''px'' and ''py'':
import sqrt from math
...
pt = array('d',[0])
branch = tree.Branch("pt", pt, 'pt/D')
N = tree.GetEntries()
for i in xrange(N):
tree.GetEntry(i)
pt[0] = sqrt(tree.px**2 + tree.py**2)
branch.Fill()
===== Scanning the values of a TTree =====
Print the values of some branches in columns with ''TTree::Scan'':
tree.Scan("run:lumi:event")
tree.Scan("run:lumi:event","pt1>30 && pt2>30") # with some selections
tree.Scan("run:lumi:event","pt1>30 && pt2>30","colsize=8") # with some option
The [[https://root.cern.ch/doc/master/classTTreePlayer.html#aa0149b416e4b812a8762ec1e389ba2db|documentation of TTreePlayer::Scan()]] has more information on print options (column size, decimal precision, ...) and formatting.
To write the output directly to a file (which gets overwritten every time):
tree.GetPlayer().SetScanRedirect(True)
tree.GetPlayer().SetScanFileName("runnumber.txt")
tree.Scan("run:lum:evt","pt1>30 && pt2>30")
===== TChain =====
If you have a samples split into many files, each containing the same tree, you can either add the files into one big one in the command line with ''hadd'' or load them in a ''TChain'' in you analysis code.
With ''hadd'' in the command line:
hadd sample.root sample_1.root sample_2.root sample_3.root
With ''TChain'':
chain = TChain("tree_name")
chain.Add("sample_1.root")
chain.Add("sample_2.root")
chain.Add("sample_3.root")
for event in chain:
print event.px
Looping over the events in a chain is similar as for [[root:pyroot_ttree#looping_over_a_ttree|trees]]. Note it's also possible to use a glob wildcard: ''chain.Add("sample_*.root")''