19.3 Reading ROOT Files with Python
Table of Contents
TFile
In PyROOT you open ROOT files using the TFile class, exactly as in C++, but through the ROOT module. The basic pattern is to import ROOT, open a file by name, check that it is valid, and then access objects inside it.
A minimal example looks like this:
import ROOT
f = ROOT.TFile.Open("data.root") # or ROOT.TFile("data.root", "READ")
if not f or f.IsZombie():
print("Error: could not open file")
else:
f.ls() # list contents of the file
TFile.Open() is usually preferred in Python, because it either returns a valid pointer or None when the open fails. The second argument controls the mode. For reading existing files you normally use "READ" or leave it empty, which also means read only. For this chapter we focus on reading, not writing.
Once the file is open, you can retrieve objects by name using Get:
h = f.Get("h_energy") # histogram
g = f.Get("g_calibration") # graph
t = f.Get("Events") # TTreeThe return value is a PyROOT proxy for the underlying C++ object. You should always verify that the object exists before using it:
t = f.Get("Events")
if not t:
raise RuntimeError("TTree 'Events' not found in file")In Python the file object will be closed automatically when it is garbage collected, but for analysis scripts it is good practice to close it explicitly when you are finished:
f.Close()
You can also use a with context manager to ensure the file closes even if an exception occurs. PyROOT does not provide a built-in context manager for TFile, so a simple helper can be useful:
import contextlib
import ROOT
@contextlib.contextmanager
def open_root(filename, mode="READ"):
f = ROOT.TFile.Open(filename, mode)
if not f or f.IsZombie():
raise IOError(f"Cannot open ROOT file '{filename}'")
try:
yield f
finally:
f.Close()
with open_root("data.root") as f:
f.ls()
t = f.Get("Events")
Within the with block, the file is open and you can freely access histograms, graphs, and trees. When the block ends, f.Close() is called automatically.
When you work with multiple input files in the same script, it is important to avoid reusing the same variable name if you still need the previous file open. Each TFile has its own internal directory structure, so the same object name can exist in different files. You must always know from which file you obtained a given object.
Always check that TFile.Open() and Get() actually return valid objects before using them. Trying to use a null or zombie object often leads to confusing errors later in your Python script.
TTrees
In PyROOT TTrees behave like C++ TTrees, but Python gives you a few extra ways to loop over entries and inspect data. Typical workflows read an existing tree from a file and then either inspect it directly, use TTree::Draw, or convert data to NumPy arrays or to RDataFrame for further analysis.
To obtain a TTree from a file, you use Get with the tree name:
import ROOT
f = ROOT.TFile.Open("data.root")
tree = f.Get("Events")
if not tree:
raise RuntimeError("Could not find TTree 'Events'")You can quickly inspect the structure of the tree from Python using familiar ROOT methods:
tree.Print() # full branch structure
tree.Show(0) # show first entry
tree.Scan("energy") # print values of a given branch
If you want to loop over events directly in Python, the simplest approach uses a for loop. PyROOT lets you iterate over a TTree and gives you an object where branch names become attributes:
for entry in tree:
e = entry.energy # access branch "energy"
t = entry.time # access branch "time"
if e > 1.0:
# perform some analysis
pass
This pattern is convenient for quick scripts. It avoids manual calls to GetEntry and manual branch address setup. It is suitable for small and medium size datasets or for prototyping.
For a more explicit C++ style loop you can still use GetEntry:
n_entries = tree.GetEntries()
for i in range(n_entries):
tree.GetEntry(i)
e = tree.energy
# do something with e
From Python the attribute access tree.energy automatically refers to the branch called "energy". Both loop styles are compatible with branches that hold simple numeric types. For more complex structures such as std::vector<double> you can still access the branch as an attribute and then use it like a Python sequence:
for entry in tree:
hits = entry.hit_energy # std::vector<float> on C++ side
n_hits = len(hits)
if n_hits > 0:
first = hits[0]
When you already use NumPy in your Python analysis, it is common to convert TTree data to NumPy arrays. PyROOT provides helpers in ROOT.RDataFrame and in ROOT.AsMatrix from the TMVA utilities in some ROOT versions, but these belong in the chapters on RDataFrame and PyROOT with NumPy. In this chapter it is enough to know that you can read the data once with a TTree loop in Python and then fill your own NumPy arrays or lists.
Another common pattern is to use TTree::Draw from Python, which lets ROOT handle the loop internally. For instance, to make a quick histogram from a branch:
c = ROOT.TCanvas()
tree.Draw("energy") # creates a TH1F in memory
hist = ROOT.gPad.GetPrimitive("htemp") # grab the automatically created histogramYou can pass selection cuts as a string and additional drawing options:
tree.Draw("energy >> h_sel(100,0,10)", "time > 50", "E")
h_sel = ROOT.gDirectory.Get("h_sel")This interface is identical to C++, but in Python it is very fast to prototype different selections and variables.
When reading TTrees from Python you must keep the parent TFile alive as long as you use the tree. If you close the file too early, the TTree and its branches may point to invalid memory. A safe pattern is to keep the TFile object in a variable that remains in scope for the lifetime of your analysis, or to nest all TTree usage inside a with block that manages the file, as shown before.
Never use a TTree or branch after its parent TFile has been closed. Keep the file object alive and in scope for as long as you access the tree from Python.
For high level analysis you will very often combine TTrees in Python with RDataFrame or with conversion to NumPy arrays. This keeps your loops concise, uses ROOT’s optimized back end, and takes advantage of Python’s ecosystem for further processing.
Views: 13
KAHIBARO