KAHIBARO
Discord Login Register

9.1. ROOT Plot Styles

TStyle

ROOT controls most visual aspects of plots through the TStyle class. A TStyle object holds default settings for colors, fonts, margins, line widths, marker styles, statistics boxes, and many other drawing options. When you draw a histogram, graph, or function, ROOT consults the current style to decide how it should look, unless you override properties on the individual object.

The central idea is that you define a style once, then ROOT applies it automatically to all objects you draw under that style. This is much more efficient than changing the same properties on every histogram and canvas.

Each ROOT session always has an active style. By default this is gStyle, a global pointer to a TStyle object. You rarely create TStyle instances yourself at the beginning, instead you usually modify gStyle, or you load one of ROOT’s predefined styles and then adjust it.

A typical workflow is to configure gStyle at the start of your macro or session, for example:

cpp
{
  gStyle->SetOptStat(0);          // Disable statistics box
  gStyle->SetTitleFont(42, "XYZ");
  gStyle->SetLabelFont(42, "XYZ");
  gStyle->SetPadLeftMargin(0.14);
  gStyle->SetPadBottomMargin(0.12);
}

Once this code has run, any new canvas and plot will follow these rules unless you change them again.

Many style settings are controlled through Set... methods of TStyle. Some of the most important groups of methods include:

AspectExample methodsTypical use
Statistics boxSetOptStat, SetStatX, SetStatYShow or hide statistics, place the box
Titles and fontsSetTitleFont, SetLabelFont, SetTitleSizeChoose fonts and sizes for axes and titles
Margins and padsSetPadLeftMargin, SetPadBottomMarginReserve space for axes and labels
Colors and fillsSetPalette, SetCanvasColor, SetFrameFillColorChoose color palette and background
Lines and markersSetLineWidth, SetMarkerStyle, SetMarkerSizeGlobal defaults for lines and markers
Log scales and gridsSetPadGridX, SetPadGridYEnable grid lines

Whenever you are unhappy with how a default ROOT plot looks, the first place to adjust it is almost always in a style configuration.

Important rule: Always configure your plotting style (using TStyle and gStyle) near the beginning of your macro or analysis script. This ensures that all plots in a session or analysis are consistent and reduces the need for repeated manual styling of individual objects.

If you want to define a completely custom named style, you can create your own TStyle object, configure it, and then call cd() on it to make it active:

cpp
{
  TStyle *myStyle = new TStyle("myStyle", "My custom ROOT style");
  myStyle->SetOptStat(0);
  myStyle->SetFrameLineWidth(2);
  myStyle->SetTitleFont(42, "XYZ");
  myStyle->SetLabelSize(0.04, "XY");
  myStyle->cd();  // Activate this style
}

After calling cd(), this style becomes the current one, and ROOT treats it similarly to gStyle for all subsequent drawing operations.

Global styles

Global styles define defaults that apply to all objects you draw after the style is set. In practice, this means you alter gStyle or activate a custom TStyle.

A global configuration is well suited when you want a consistent look for every figure in an analysis or publication. You set it once at the beginning of the macro, and the rest of the code focuses on physics rather than cosmetics.

There are two common ways to work with global styles.

First, directly modify gStyle:

cpp
void SetMyGlobalStyle() {
  gStyle->SetOptStat(0);            // No stats box by default
  gStyle->SetOptTitle(0);           // Hide histogram titles if desired
  gStyle->SetCanvasColor(0);        // White canvas
  gStyle->SetPadColor(0);
  gStyle->SetFrameLineWidth(2);
  gStyle->SetLineWidth(2);
  gStyle->SetHistLineWidth(2);
  gStyle->SetTitleFont(42, "XYZ");
  gStyle->SetLabelFont(42, "XYZ");
  gStyle->SetTitleSize(0.05, "XYZ");
  gStyle->SetLabelSize(0.04, "XYZ");
  gStyle->SetPadLeftMargin(0.14);
  gStyle->SetPadRightMargin(0.05);
  gStyle->SetPadBottomMargin(0.13);
  gStyle->SetPadTopMargin(0.06);
}

You would then call SetMyGlobalStyle(); once before creating canvases and histograms.

Second, create a named TStyle and activate it globally using its cd() method:

cpp
void UseMyStyle() {
  static TStyle *myStyle = 0;
  if (!myStyle) {
    myStyle = new TStyle("myStyle", "My global style");
    myStyle->SetOptStat(0);
    myStyle->SetPadGridX(true);
    myStyle->SetPadGridY(true);
    myStyle->SetLegendBorderSize(0);
  }
  myStyle->cd();   // Make this the active global style
}

This pattern is useful if you want to switch between different predefined styles in the same ROOT session.

ROOT also provides some utility functions and scripts containing styles that are common in experiments or publications. For example, you might encounter macros that define “ATLAS”, “CMS”, or “BELLE” style. These macros typically set gStyle or define a TStyle that is then selected with cd(). The principle is always the same: one global style drives the default appearance for all plots.

Global styles often control behavior you might not immediately think of as “style”. For example, gStyle->SetOptFit(1); makes ROOT automatically print fit results on the plot after using TH1::Fit or TGraph::Fit. gStyle->SetPalette(kViridis); changes the default color map for 2D histograms and surfaces. These changes apply to anything you draw after the style is set, which is convenient if you want all 2D plots to use the same palette.

When working with global styles, it is important to remember that style settings are stateful. If you run several macros in the same ROOT session, style changes from one macro will affect the next. For reproducible analysis, it is good practice to explicitly set the global style inside each macro or script so that it does not inherit an unknown style from a previous session.

Important rule: For reproducible and predictable plots, always assume that style state may be arbitrary when your macro starts. Reinitialize the global style (for example by calling gROOT->Reset() followed by your own style configuration, or by explicitly configuring gStyle) at the beginning of each plotting macro.

Global styles work best for:

  1. Setting font families and sizes consistently.
  2. Defining default margins and canvas background colors.
  3. Choosing common line widths and marker sizes.
  4. Controlling default statistics and fit info.
  5. Selecting a standard color palette for all 2D plots.

Once you have a reliable global style, your plots will look consistent, and you will only need to adjust details in special cases.

Object-specific styles

Sometimes you want a particular histogram or graph to look different from the global defaults. For example, you might want thicker lines for a reference distribution, different colors for several histograms drawn on the same axes, or special markers for data points compared to model predictions.

In these cases you override the global style by setting style properties directly on individual objects. Every drawable object in ROOT inherits from TAttLine, TAttFill, TAttMarker, or related attribute classes, which provide methods such as:

Histograms additionally have convenience methods like SetStats, SetTitle, and SetAxis* settings via their axes.

A simple example of object-specific styling for two histograms might be:

cpp
TH1F *h1 = new TH1F("h1", "h1", 100, 0, 10);
TH1F *h2 = new TH1F("h2", "h2", 100, 0, 10);
// Fill histograms here
// Apply object-specific styles
h1->SetLineColor(kRed);
h1->SetLineWidth(2);
h2->SetLineColor(kBlue);
h2->SetLineStyle(2);   // Dashed
h2->SetLineWidth(2);
// Draw
h1->Draw();            // Draw first
h2->Draw("SAME");      // Overlay second

Although the global style might define default line colors, widths, and marker styles, these calls on h1 and h2 override those defaults only for these particular histograms.

Object-specific styling is also important when you create multiplot figures. Each dataset must stand out clearly from the others, for example by using different colors and markers. You might define a simple rule such as:

Object typeColorMarker styleLine style
DataBlack20Solid
SimulationRed24Solid
BackgroundBlue25Dashed

You then implement this rule with object-specific settings on each histogram or TGraph, while leaving the global style to handle fonts, margins, and other shared aspects.

Text objects and legends also support object-specific styles. For example:

cpp
TLatex *label = new TLatex(0.2, 0.85, "Preliminary");
label->SetNDC();              // Use normalized device coordinates
label->SetTextFont(42);
label->SetTextSize(0.05);
label->SetTextColor(kRed+1);
TLegend *leg = new TLegend(0.6, 0.7, 0.88, 0.88);
leg->SetBorderSize(0);        // No border around legend
leg->SetFillStyle(0);         // Transparent background

These properties only affect the specific TLatex and TLegend instances, regardless of the global style.

When mixing global and object-specific styles, ROOT applies them in a simple way: object-specific settings always win over the global defaults. The global style sets initial values for attributes, and then any object-specific calls modify them for that particular object.

This behavior suggests a clear strategy. Use the global style for the “baseline” look of your analysis, such as fonts, canvas colors, and margins. Then use object-specific styles sparingly for distinctions between individual datasets or annotations within a plot.

Important rule: Use global styles for consistency and object-specific styles only to highlight differences between datasets or to add special annotations. Object-specific settings override global defaults, so overusing them can make plots inconsistent and difficult to maintain.

If you find yourself repeatedly applying the same object-specific settings (for example, every “data” histogram always gets the same color and marker), it is often better to wrap that in a small function:

cpp
void StyleDataHistogram(TH1 *h) {
  h->SetLineColor(kBlack);
  h->SetMarkerColor(kBlack);
  h->SetMarkerStyle(20);
  h->SetLineWidth(2);
}

You can then call StyleDataHistogram(hData); on each relevant object. This keeps object-specific styling organized, avoids duplication, and keeps the rest of your analysis code focused on the physics.

Views: 10

Comments

Please login to add a comment.

Don't have an account? Register now!