Walkthrough: Making a histogram with Analyze
(15 minutes)
Edit the file Analyze.C. In the Definitions section, insert the following code:
TH1* chi2Hist = NULL;
Note
This means “define a new histogram pointer and call it chi2Hist
.”
Why define this as a pointer when plain ol’ variables are easier to use?
The short answer is that ROOT uses pointers all the time; for example,
if you want to read something from a file, you must always use pointers.
The sooner you get used to pointers, the better.1
Don’t forget the semi-colons “;” at the ends of the lines! You can omit them in interactive commands, but not in macros.
In the Initialization section, insert the following code:
chi2Hist = new TH1D("chi2","Histogram of Chi2",100,0,20);
Note
This means “set this pointer to a new histogram object.” We’re doing this here, instead of the Definitions section, because sometimes you want quantities like histogram limits to be variable rather than fixed; e.g., they depend on user input.
In the Loop section, put this in:
GetEntry(entry);
chi2Hist->Fill(*chi2);
Note
The first of these two lines means “get the ‘(entry+1)-th’ row
from the TTree
”; e.g., if entry
is 100, get the 101st row from the
n-tuple.2 Note that the variable entry
comes from an argument to the
Process
method, so you don’t have to set it. This line will assign
values to variables defined in the n-tuple: *ebeam
, *chi2
,
and so on.3 In code prepared by MakeSelector
, the variables
extracted from an n-tuple are pointers; they have to be prefixed with
“*” to access their values.
The second line means “in the histogram chi2Hist
add 1 to a bin that
corresponds to the value of *chi2
.”
This goes in the Wrap-up section:
chi2Hist->Draw();
Note
You already know what this does; you’ve used it before!
Save the file, quit and restart ROOT, then enter the same commands as before:
[] TFile myFile("experiment.root")
[] tree1->Process("Analyze.C")
Note
Finally, we’ve made our first histogram with a C++ analysis macro. In the Initialization section, we defined a histogram; in the Loop section, we filled the histogram with values; in the Wrap-up section, we drew the histogram.
“What histogram? I don’t see anything!” Don’t forget: if you have the TBrowser open, you may need to click on the Canvas 1 tab.
How did I know which bin limits to use on chi2Hist
? Before I wrote
the code, I drew a test histogram with the command:
[] tree1->Draw("chi2")
Hmm, the histogram’s axes aren’t labeled. How do I put the labels in the macro? Here’s how I figured it out: I labeled the axes on the test histogram by right-clicking on them and selecting
. I saved the canvas by selecting . I looked at c1.C and saw these commands in the file:chi2->GetXaxis()->SetTitle("chi2");
chi2->GetYaxis()->SetTitle("number of events");
I scrolled up and saw that ROOT had used the variable chi2
for the
name of the histogram pointer. I copied the lines into Analyze.C, but
used the name of my histogram instead:
chi2Hist->GetXaxis()->SetTitle("chi2");
chi2Hist->GetYaxis()->SetTitle("number of events");
Try this yourself: add the two lines above to the Initialization section, right after the line that defines the histogram. Test the revised Analyze class.
- 1
Why are we defining a pointer then setting it equal to
NULL
? I’m teaching you to avoid a common problem in programming: uninitialized variables. If we didn’t setchi2Hist
toNULL
, what would its value be? I don’t know. It would likely be set to zero, which is also the typical value ofNULL
. But this behavior varies between different C++ compilers. It’s better to be sure.This is not an issue in the code we’re writing now, but in the future you’ll discover that uninitialized variables cause lots of crashes. Let’s get into good programming habits and avoid them from the start.
Some compilers offer another name for
NULL
:nullptr
. They both have the same value, but for you one may be clearer than the other.- 2
Actually, in the context of
MakeSelector
it means “get the data from theTTree
pointed to byfReader.SetEntry(entry)
”.Note that when
entry
is 0,GetEntry
will fetch the first row in the n-tuple; that’s why whenentry
is 100,GetEntry
will fetch the 101st row in the n-tuple.- 3
It’s mildly annoying that whenever you use
MakeSelector
to create an analysis skeleton, you must remember to put aGetEntry
line. SinceMakeSelector
is doing everything else for us, why can’t it put in that one line too so we don’t have to remember?The answer is that there’s more that can be done with the
TSelector
skeleton than we’re doing in this course; do a web search on “TSelector example” for some ideas. Since there are times when a simple line likeGetEntry(entry)
is not what you want, or you might create an analysis skeleton for one tree and use it on another,MakeSelector
makes you put in theGetEntry
line manually.