You are here

Canvases and pads

Whenever we obtain graphical output on our monitor, ROOT puts it into a canvas, that is an area mapped to a window directly under the control of the display manager. Of course, we can open multiple canvas if we want to display different things, but it is often better to organize everything into a single canvas. For this reason, any instance of TCanvas can be subdivided into independent graphical areas, called pads (by default, a canvas contain a single pad, occupying the whole space - TCanvas inherits from TPad).

To split a canvas, one uses the method TPad::Divide(...), specifying the number of horizontal and vertical slices (both default to 1), the horizontal and vertical margins (both default to 0.01, i.e. to 1% of the width/height of the parent pad), and the background color (default to 0, i.e. white).

To be able to display anything into a pad, we first need to make it the active pad by means of the method cd(...), that takes the integer index of the pad. By default, this parameter is 0, indicating the parent pad. Subpads are numbered starting from 1, following the sequence left-right, top-bottom (i.e. they are "read" as the words in any English text). The active pad, highlighted by a colored border, can also be set by clicking on it with the central mouse button.

The following (buggy! Continue reading...) example creates and display a new canvas with 400 pixels width and 300 pixels height, then splits it into 6 subpads (3 rows, 2 columns) and activates the mid-right pad. Finally, it creates a mathematical expression (encoded as a TLatex object) and displays it inside the selected canvas. The result is shown below (and the problem is explained in the next section).

 
root [] TCanvas c1("c1", "First canvas", 400, 300); // problems here
root [] c1.Divide(2,3);
root [] c1.cd(4);
root [] TLatex l(0.1,0.4,"C(x) = d #sqrt{#frac{2}{#lambdaD}}  #int^{x}_{0}cos(#frac{#pi}{2}t^{2})dt");
root [] l.SetTextSize(0.15);
root [] l.Draw();

c1.png

All ROOT classes inheriting from TObject can be displayed into a pad with the Draw(...) method. Graphical object sizes are usually expressed as user coordinates, that in our case coincide with the normalized coordinates (NDC), in which the origin is the lower-left corner and the units are the width and height of the current pad. However, if the formula is drawn after an histogram or a graph has been drawn on the same pad, the user coordinates coincide with those defined by the plot axes.

The most notable exception to this rule is the TCanvas constructor, that requires dimensions in pixels. In the above example, the formula (using NDC) origins from a point that is at 10% of the width right from the pad origin and 40% of the height above the pad origin. In addition, the text size is 15% of the canvas height (because the pad is a horizontal rectangle; the unit is the width in case of a vertical one, i.e. the unit for the text size is always the shorter dimension of the current pad). However, one can also specify the text size in pixels (by setting the text precision to 3; default is 2). Depending on the text precision, the text may be scalable or of fixed size (in pixels).

In ROOT, the Draw() method does not actually draw the object by itself. Rather, it adds the object to the display list of the pad (so that it gets drawn every time the pad is redrawn) and invokes the Paint() method, that is the real drawing method. For many classes (notably histograms and graphs), the Draw() method also tells the pad that it has been modified, triggering the pad redrawing. However, this is not true for other classes, usually representing minor graphical objects, for example lines. To actual paint them, one needs to call TPad::Modified() method, that signals the pad that it has been modified, so that it needs to be redrawn. For more details, see the How to draw objects document and the introductory documentation to THistPainter.