Exercise 14: A brutally realistic example of a plotting task
(1-2 hours)
Take a look at folder example3
. You probably already looked in there
and were overwhelmed with the number of histograms.
Here’s the task: it’s another x-y plot, with the y values and error bars from fitting the histograms. You only want to include those histograms whose names begin with “plotAfterCuts”; the other histograms you can ignore.
The x values come from the histograms themselves. Double-click on a few histograms to plot them. You’ll see that the x values are in the titles (not the names!) of the histograms.
Note
You’ll be able to re-use code you developed for the previous two exercises. There are some new problems to solve: how to get the list of all the histograms in the example3 folder, how to test if a histogram’s name begins with “plotAfterCuts”, and how to convert a histogram’s title from a string into a number.
Let’s think about the easier problems first.
If you’re fairly familiar with C or C++, you probably already know how
to convert strings into numbers. If you’re not, then I suggest you take
a look at the description of the TString
class on the ROOT web site; the
Atof()
method looks interesting.
The TString
class is pretty good about converting string formats
implicitly.1 You probably already figured out how to look up
getting the title from a histogram. The method returns const char *
but something like this will work:
TString title = histogram->GetTitle();
What about testing if the text in a TString
begins with “plotAfterCuts”?
Take another look at the TString
web page. Is there a method that looks
like it might help you with that test?
The next problem is trickier: How do you get a list of objects in a directory?2
By now you’ve got the hang of the above hint: I want to “Get” a “List” of objects in a directory. When I worked on this problem, I went to the TFile web page and looked for methods with names that began with “GetList”. Nothing there, so I went to the parent class TDirectoryFile, continuing to search for “GetList.” Nothing there, so I went to its parent3 TDirectory. I found something, clicked on the name of the method… then pounded my head against the desk.4
I finally got the answer by using the UNIX grep
command to search
through the ROOT tutorials directory for the text “GetList”. There are
many files there with a “GetList…” call, but one file name stood out
for me. Since I had read the TList
web page first, I could see that the
answer was there. But it’s sloppily written and you’ll have to change
it.
To understand what you’d have to change, you’ll have to know a little bit about class inheritance. In C++, the practical aspect of class inheritance is that you can use a pointer to a base class to refer to a derived class object; if class Derived inherits from class Base, you can do this:
Base* basePointer = new Derived();
If that’s a little abstract for you, consider this in terms of the classes with which you’ve worked. Any of the following is correct in C++:5
TH1D* doublePrecisionHistogram = new TH1D(...);
TH1* histogram = new TH1D(...);
TObject* genericRootObject = new TH1D(...);
Why does this matter? Because ROOT does not read or write histograms,
functions, n-tuples, nor any other specific object. ROOT reads and
writes pointers to class TObject*
. After you read in a TObject*
, you’ll
probably want to convert it to a pointer to something useful.
In C++, the simplest way to attempt to convert a base class pointer to a
derived class pointer something like this (assuming genericRootObject is
a TObject*
):
TH1* histogram = (TH1*) genericRootObject;
if ( histogram == NULL )
{
// The genericRootObject was not a TH1*
}
else
{
// The genericRootObject was a TH1*; you can use it for things like:
histogram->FillRandom("gaus",10000);
histogram->Draw();
}
If I didn’t put that test in there and just tried
histogram->FillRandom("gaus",10000)
, and histogram==NULL
, then the
program would crash with a segmentation fault.6
Note
Why did I write such a long note to go over such a dry topic?
Understanding object inheritance makes it clear why the macros that ROOT automatically creates for you use pointers, why ROOT’s container classes only contain
TObject*
, why the default canvas is aTCanvas* c1
, etc.It’s so when you see a line like this in the ROOT tutorials, you have an idea of what it’s doing: using a
TKey
to read in aTObject*
, then converting it to aTH1F*
:h = (TH1F*)key->ReadObj();
Now you should have an idea of how to edit this line to do what you want to do… and how to check if what you’ve read is actually a histogram or is some other object that was placed inside that folder.

Figure 77: https://xkcd.com/371/ by Randall Munroe
- 1
Yet another digression: There are three main ways of handling strings in ROOT/C++:
The original way from the older language C, as an array of char:
char oldStyleString[256];
A newer way, added to the C++ language:
std::string newStyleString;
The ROOT way:
TString rootStyleString;
Which is better? My attitude is that none of them is best. In a ROOT program, I tend to use
TString
; if my program doesn’t use ROOT, I use std::string for string variables and arrays of char for constant strings.Until recently, C++ didn’t have the built-in text manipulation facilities of languages like perl or Python. This can be important in a physics analysis procedure; while your calculations are based on numbers, manipulating files or program arguments can be based on strings. A language update, C++11, has a “regex” library for handling regular expressions; this can also be found in ROOT’s cling.
In Python, all this is much simpler. (Hint:
import re
)- 2
For Python programmers: This discussion of object inheritance is relevant to you as well, but you deal with it in a different way. Look up the Python
type()
andisinstance()
functions.- 3
TFile’s “grandparent.”
- 4
I suppose the programmer thought that they would write the documentation for GetList later.
Here’s a tip for writing code that will make you a hero: “later” does not exist. (As of 2016, the ATLAS collaboration collected over 35 fb\(^{-1}\) of data, and they still haven’t discovered evidence of “later”!) Treat the comments as part of the code-writing process. If you have to edit the code, edit the comments.
Yes, I know it’s a pain. But pounding your head on a desk is a bigger pain. It’s the biggest pain of all when you realize that you wrote the code yourself six months ago, have completely forgotten what it means, and must now spend an hour figuring it out. It would have taken five seconds to write a comment.
- 5
How do you figure out which classes derive from where? The only way to find out in the current ROOT documentation is to search ROOT’s C++ source code, which you can browse via the links to the .h files in the class’ web page. Welcome to the wild adventure hunt that is ROOT!
- 6
If you haven’t encountered a segmentation fault yet in this tutorial, you’re either very lucky or very good at managing your pointers. Now you know why it happens: someone tried to call a method for an object that wasn’t there.