ROOT is a popular data analysis framework developed at CERN based on C/C++ programming language. Historically it played a crucial role for the data analysis at CERN and also around the world and it is still being used in many many experiments.
At the first glance, from the programming point of view and considering modern methods and analysis frameworks, there might not be enough justification to continue using ROOT except for very large scale experiments. Almost all of ROOTs features are already available as standard Python functions or in its libraries such as numpy
and scipy
. So among the many features inside of the ROOT library, some of them come out as really handy and can be used in Python with more comfort. These include the histogram objects TH1
and TH2
, but also TGraph
, TFile
and many available fitting algorithms. TBrowser
which also has a web version, allows for viewing different graphs and histograms and specifically using the Fit Panel.
In general ROOT is sometimes a bit more comfortable and hence enjoys a huge popularity in the high energy and particle physics and generally science communities. The code developement is very active with a very good documentation there is a nice support forum where people can get help.
So why not use ROOT inside Python?
Many thanks to the PyROOT interface, the whole ROOT functionality can be imported to Python just by using an import
call, as if you are importing just another Python library.
The easiest way to install ROOT is using Anaconda, as described in this article. In summary, after setting up Anaconda, just create a ROOT env by using this command:
conda create -n my_root_env root -c conda-forge
then you can activate your environment by:
conda activate my_root_env
There are many examples on the internet which show how to use ROOT, but these are mainly written in C/C++. In fact the PyROOT interface makes it easy to use the same commands inside PyROOT. In order to achieve this, one might need to "clean-up" the C++ code and make a Python code out of it. In fact this can be done with little effort, as the following example shows:
This example is taken from here:
#include <TCanvas.h>
#include <TCutG.h>
#include <TH2F.h>
#include <TProfile.h>
#include <TRandom.h>
void fit2d()
{
// generate a 2-d histogram using a TCutG
const int n = 6;
float x[n] = {0.092,0.83,0.94,0.81,0.12,0.1};
float y[n] = {0.71,9.4,9,8,0.3,0.71};
TCutG *cut = new TCutG("cut",n,x,y);
TH2F *h2 = new TH2F("h2","h2",40,0,1,40,0,10);
float u,v;
for (int i=0;i<100000;i++) {
u = gRandom->Rndm();
v = 10*gRandom->Rndm();
if (cut->IsInside(u,v)) h2->Fill(u,v);
}
TCanvas *c1 = new TCanvas("c1","show profile",600,900);
c1->Divide(1,2);
c1->cd(1);
h2->Draw();
c1->cd(2);
//use a TProfile to convert the 2-d to 1-d problem
TProfile *prof = h2->ProfileX();
prof->Fit("pol1");
}
Now in order to make a Python code out of this, just remove the typical C/C++ code style, like semicolons, brackets, etc... the rest stays the same as the C/C++ code. Here is how the resulting code looks like:
from ROOT import TCanvas, TCutG, TH2F, TProfile, gRandom
import numpy as np
def fit2d():
# generate a 2-d histogram using a TCutG
n = 6
x = np.array([0.092,0.83,0.94,0.81,0.12,0.1])
y = np.array([0.71,9.4,9,8,0.3,0.71])
cut = TCutG("cut",n,x,y)
h2 = TH2F("h2","h2",40,0,1,40,0,10)
for i in range(100000):
u = gRandom.Rndm()
v = 10*gRandom.Rndm()
if cut.IsInside(u,v):
h2.Fill(u,v)
c1 = TCanvas("c1","show profile",600,900)
c1.Divide(1,2)
c1.cd(1)
h2.Draw()
c1.cd(2)
# use a TProfile to convert the 2-d to 1-d problem
prof = h2.ProfileX()
prof.Fit("pol1")
Note that here we additionally imported numpy
to add the functionality of ndarrays. Also, instead of importing TRandom
, we are importing gRandom
directly. This is a typical change from C/C++ ROOT to PyROOT. Finally you may notice, that in the original C/C++ code the actual call for making the plot c1->Drtaw();
is missing. This should be done by hand in ROOT's CINT interface, or in the Python code in form of c1.Draw()
. The results can be seen in the picture in this gist.
In the example above you can see that the function fit2d
itself is actually not needed. So you can remove it and make a flatter code. Also, you may notice that the module gRandom
is used. Actually this is also not really needed, as you can use python's own random generators, such as the random
module inside of the numpy
module.
BTW, it is a matter of taste in the Python world, to use single quotes rather than double quotes. But your code will probably be judged as more pythonic if you use single quotes for strings.
Here is the more pythonic code:
from ROOT import TCanvas, TCutG, TH2F, TProfile
import numpy as np
# generate a 2-d histogram using a TCutG
x = np.array([0.092,0.83,0.94,0.81,0.12,0.1])
y = np.array([0.71,9.4,9,8,0.3,0.71])
cut = TCutG('cut',len(x),x,y)
h2 = TH2F('h2','h2',40,0,1,40,0,10)
for i in range(100000):
u = np.random.random()
v = 10 * np.random.random()
if cut.IsInside(u,v):
h2.Fill(u,v)
c1 = TCanvas('c1','show profile',600,900)
c1.Divide(1,2)
c1.cd(1)
h2.Draw('')
c1.cd(2)
# use a TProfile to convert the 2-d to 1-d problem
prof = h2.ProfileX()
prof.Fit('pol1')
c1.Draw()
Similarly, many other features, like the above TCutG
can be eliminated and replaced by pure python functions.