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 a TCanvas* 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 a TObject*, then converting it to a TH1F*:

    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.

xkcd compiler_complaint

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() and isinstance() 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.