(brutally-realistic)=
# 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.[^f137] 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?[^f138]
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
parent[^f139] TDirectory. I found something, clicked on the name of the
method... then pounded my head against the desk.[^f140]
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++:[^f141]
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*`):
(segmentation-fault)=
:::{code-block} c++
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.[^f142]
:::::
:::{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.
:::
[^f137]: 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`)
[^f138]: 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.
[^f139]: TFile's "grandparent."
[^f140]: 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.
[^f141]: 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!
[^f142]: 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.
:::{figure-md} compiler_complaint-fig
:class: align-center
by Randall Munroe
:::