Even the most ardent fans of ROOT have from the beginning found its plot facilities inadequate, particularly in comparison with those easily available from its ancestor, PAW. It is difficult and cumbersome to add axis labels and legends with symbols, and axis specifications for a TGraph are simply discarded if the TGraph has not yet been drawn. When they do appear, axis labels often collide with the axis numbers. There is no automatic facility for adding dates. Overcoming these problems poses a real challange for users needing to create publication-quality plots, and they have generally resorted to copying data to other commercial (Kaleidagraph, Excel) and non-commercial (PAW, Grapher) applications.
The ROOT team admits some of these faults, but has made no real progress in addressing them.
The TPhDisp class contains a graphic object, such as a graph-with-errors or a one- or two-dimensional histogram, along with a set of "labels" that make it presentable. These include an X-label, a Y-label, a Z-label (for 2-d histograms), a title, a date, a legend, a symbol for the plot and legend, and two arbitrary notes (more can be added). For each label, you can specify the position in NDC coordinates that run from 0 to 1 in both dimensions, the text, font, size, color, angle, and alignment (hv = 1-3 for left, centered, or right) with respect to the given coordinate point. The default values of all these quantities can be modified by using public fields, or standard Get and Set methods, or they can be read from a text preference file. Once you have adjusted a plot to your satisfaction, you can save the TPhDisp in a file. When you read it back, it will have all your settings, as well as a complete copy of the plotted object and its data,which enables the ROOT feature that allows you to change the original data to fit your model of what the experiment SHOULD have measured. It is not necessary to draw a TPhDisp before saving it, so that it is an appropriate object for saving information produced online or in any time-critical environment.
It's important to recognize that a TPhDisp simply packages standard ROOT objects and control parameters with methods that minimize the number of keystrokes required to make professional plots. You can do everything that a TPhDisp does using standard ROOT methods [you can look in TPhDisp.cxx to see how it does things, and then do them better yourself], and you can add ROOT features like little text platforms with unphysical shadows if you want. The advantage of this approach is that TPhDisp can take advantage of improvements in ROOT facilities when, or if, they happen.
A word of caution: the access methods will almost certainly change as this preliminary version develops.
In this section, we use red to indicate what you type. Suppose you have a TGraphErrors * called g1, say.
For tutorial purposes, you can use the macro $PHATHOME/phatmul/macros/makegh.C to create TGraphErrors , TH1Fs, and a TH2F with which you can experiment.
Thus,
> phat .x $PHATHOME/phatmul/macros/makegh.C
Created TGraphErrors g1 and g2.
Created TH1Fs h1 and and h2 and TH2F k1.
Suppose you have done this. Let's first use the built-in ROOT commands to draw g1:
g1->Draw()
Oops! This default (Fig. 1) isn't very useful. You have to say
g1->Draw("ape")
Now it draws (Fig. 2) and you can almost see the points, but the result couldn't possibly be accepted for publication by any known journal.
Let's now create a TPhDisp - display of g1:
TPhDisp a1(g1)
a1.Draw()
As you can see in Fig. 3, the default adds a date, title, and two dummy axis labels, "X" and "Y".
You can also create the TPhDisp on the heap:
TPhDisp *a1 = new TPhDisp(g1)
a1->Draw()
There is no particular advantage in doing this, and in fact CInt allows-- perhaps unwisely-- the use of either notation for either kind of creation. But don't try it in compiled code.
When you first draw something without creating a "canvas", ROOT will create it for you and will give you a message like <TCanvas::MakeDefCanvas>: created default TCanvas with name c1
You can save the result very simply by using the command c1.Print("filename.type"), where type can be ps, eps, gif, or jpg. This ROOT feature is priceless.
You can modify any of these labels, or turn them off entirely. Suppose you want to change the X-label from "X" to the Greek letter eta, which is represented by "h" in the symbol font. You can do this most simply by accessing fields in a1 directly. The fields have names of the form <label-name><entry>, all lower case with no intervening spaces. The label-names are symbol, x, y, z, legend, title, date, note1, and note2. The entries are h, v, color, font [or style], size, color, align, angle, and NDC (which is non-zero to use NDC coordinates, which run from 0 to 1, in both horizontal and vertical directions). The absence of an entry refers to the text string itself. Just typing the field name will cause ROOT to evaluate it for you:
a1.x
(Text_t* 0x300030119f0)"X"
a1.xfont
(Int_t )131
Now make the change:
a1.x="h"
a1.xfont=121
a1.Draw()
The result is in Fig. 4. 121 is the ROOT [and PAW, of course] identifier for the symbol font.
If you see many of the labels in Greek, you have run afoul of a bug in the Free TruType engine distributed with ROOT v 2.23. Sorry, there's no known cure for this disease except to wait for our friends in the ROOT team to realize it. Just spell out eta, phi, and theta.
The next release of TPhDisp will make use of the recently-added ROOT TLatex class, in which it will be possible to mix Greek and English fonts in a label, and to include mathematical symbols, subscripts, and superscripts. At present, you can get Greek letters into Postscript printer output but not on the screen, using the same special symbols as in PAW. Do you still have your old manual, with all the post-its stuck in so you can find the information?
You can find fonts, marker symbols, color indices, and fill patterns for histograms listed in TPhDisp.h and briefly discussed later.
If you find typing a healthful and fulfilling exercise, you can achieve exactly the same result by using conventional getters and setters:
a1.GetText("x")
a1.GetFont("x")
a1.SetText("x","h")
a1.SetFont("x",121)
If you want to make the Y-label 20% larger and red, and put the date in the upper right corner,
a1.ysize*=1.2
(or a1.SetSize("y",a1.GetSize("y")*1.2))
a1.ycolor=2
a1.dateh=0.90
a1.datev=0.98
a1.datealign=33
After any change, you can repeat a1.Draw() to see the effect (Fig. 5).
Another unfortunate change in ROOT v 2.23 leaves the original objects on the screen and overprints instead of replacing them. The only way to get around this, if you use the new ROOT, is to do gPad->Clear() and then redraw. Fortunately, we didn't pay a lot of money for the new version of ROOT.
You can use the method a1.GetCurrentDate(1) to put the date in its original system form, with day of week and time in seconds. You can use a1.<...>angle to change the angle of any label. The preference file discussed below uses this for a B-stamp.
You can specify the most-used parameters using the creator
TPhDisp x(graphics object, sequence, x-title, y-title, legend, symbol, symbol color, symbol size), for example:
TPhDisp a2(g1, 0, "Eta", "dNch/dEta", "Reconstructed", 21, 4)
a2.Draw()
Fig. 6 shows the result. Unspecified parameters have sensible defaults. The sequence parameter here is necessary, even though its normal default is 0, to tell C++ which method to use. The sequence parameter is used with overlay plots to reposition the legends and change symbols automatically, and to omit labels like x, y, date and title that should only be drawn for the first plot.
If you want to change many things, you can create a macro to do it, or you can read a "preference file" that sets everything the way you want it. Fig 7 shows, for illustrative purposes, the result of using a simple macro:
.x $PHATHOME/phatmul/macros/overplot.C
Fig 8 shows the result of invoking a rather elaborate set of preferences by typing
TPhDisp a1(g1, "dispref.txt")
You can copy $PHATHOME/phatmul/macros/dispref.txt and use it as a template. Note that only things that you want to change need to be specified, since each line is self-identifying.
You can display histograms in the same way, for example, Fig. 9 shows a display of a TH1F called h1, made by typing
TPhDisp a3(h1, 0, "Eta", "dNch/dEta", "Reconstructed", 2, 4)
a3.Draw()
and Fig. 10 shows a two-dimensional histogram k1 plotted with a preference file,
TPhDisp a4(k1,"dispref.txt")
a4.Draw()
The histogram defaults are still being developed.
To save a display, with any changes you have made, to a file,
TFile f1("displays.root","recreate")
a1.Write("d1")
and to read it back,
TFile f1("displays.root")
TPhDisp *a1 = (TPhDisp *)f1.Get("d1")
(Up until version 2.23 of ROOT, you could simply say TPhDisp *a1 = f1.Get("d1"), but the ROOT team improved that.)
Note that TFile::Get returns a pointer to an object, which means that if you now make further modifications in a1, you should use the -> notation, as in
a1->title="Engineering run 99"
In addition to the alternative Get and Set methods used to access the label parameters, there are Get and Set methods for most other parameters, such as GetGraph, GetHist1, GetHist2, GetSequence, GetOpts, ... The graphic objects themselves can be modified or enhanced through their own methods, and fits can be made using standard ROOT methods. The variable ReportLevel can be increased to follow progress in debugging complex situations. The ROOT .class command will display a list of all existing methods.
For an overplotted object, drawn with sequence > 0, TPhDisp only creates and draws the legend and notes. Their position, color, and style are generated using the public fields fDYSeq, fDColorSeq, and fDStyleSeq. A special value of the sequence, -1, is used to mean "display only the legend and notes for this object but place them exactly according to legendv, legendcolor, ..." in order to allow the user complete control over the legend.
The first plan for the TPhDisp class architecture was to make it inherit from the graphic object classes, but it soon became evident that that would be difficult. Basically, a TPhDisp is NOT simply a TGraphErrors with enhanced properties, and the only explicit methods it needs to inherit are Draw and streamer facilities that it inherits directly from TObject. Instead, TPhDisp has fields that point to the graphics object and contain the parameter values. The constructors instantiate the object with default values copied from an initialized internal struct of type LabDef, which are then modified by values from explicit constructors and from preference files. The original plan was to use these structs for all information storage, but that failed when CInt proved unable to access the struct fields.
A considerable complication is introduced by the requirement that text strings read from the disk and from preference files must be copied to dynamically allocated heap storage, and deleted when the object is deleted, whereas text strings entered by initialization or typed by the user into CInt must not be deleted.
When a Draw command is issued, the TTexts that embody the label information are created and drawn on the fly. They are not saved or written out, in order to minimize the overhead in storing a large number of disps on disk. Note that this implies that changes made by using a mouse to move an object on the screen will NOT be saved to the disk. It is not unlike the differencebetween using TeX and Word for creating a document; not coincidentally, most publications are done using the precision of TeX. Also, ROOT displays are not exactly WYSIWYG, so resizings sometimes print badly.
I am still considering whether a TPhDisp should be able to contain several graphic objects to be overplotted, or whether that should be left to a planned new TPhDispSet class whose job is to contain a set of TPhDisps along with information about how they are to be displayed on a single- or multi-frame page.
The header file, TPhDisp.h, lists some of this information; you can view it within a ROOT session by entering
.! more $PHATHOME/phatmul/inc/TPhDisp.h
The basic source of information is the ROOT web documentation on classes TAxis and TAttText. For convenience we include some of the commonly-used values here:
Font ID's (see TAttText): 41 is Helvetica, 61 is Helvetica bold, 91 is Courier, 121 is Symbol, 131 is Times, 141 is Windgings. There are also bold and italic versions. The default is 62, set in gStyle (see class TStyle). If you want to include Greek letters in Postscript output ONLY, ` means to Greek, # means end, so `h# will print, but not display, the Greek letter eta. The TLatex class, when it is enabled, will allow mixing fonts in a label and displaying them correctly on both screen and printed output.
Marker styles: 20-23 are filled circle, square, triangle up, triangle down. 24-27 are the same in outline. 28-31 are outline cross, X, star, and point. 1-6 are x's and crosses.
Histogram fill styles: 3001-3 are dots, 4-... are ///, \\\, |||, ===, weave, scales, bricks, .... The fill style and color may be specified as symbolstyle and symbolcolor, or as a Draw() parameter, but this is not yet implemented; meanwhile they can be set directly from aa.GetHist1()->Setxxx(...).
Line styles: 1-4 are ____, ....., _ _ _ _, _ . _ . _ .
Colors: 1-12 are black, red, green, blue, yellow, magenta, cyan, green2, blue2, white, gray, black2... See Patrick Decowski's color palette macro in $PHATHOME/macros for values up to 255.
The TPhDisp class grew out of the TPhMulDisp class, which handles multiple displays for the multiplicity package, and also out of pubplot.C, a sample macro for creating publication quality plots.
Status on 17-Nov-99:
Last updated 17-Nov-1999. Please send comments to Robin Verdier (verdier@mit.edu).