HighLAND
All you need to know about the DrawingTools

Introduction

DrawingTools is a highland2 class which can be instanciated from a ROOT session to inspect the output file of a highland2 job and easily understand your analysis. The DrawingTools has methods to dump information about your analysis:

In this way you may know at any time how a given highland2 output file was built.

But the main functionality of the DrawingTools, at its name suggests, are the tools for drawing. Indeed, the DrawingTools provide all kind of methods to understand the selection and the systematics:

Setting up the DrawingTools

If you haven't done so yet, you should do under the cmt directory of your top level analysis package:

source setup.sh

such that root knows about all important classes in the framework. Then you can open a root session and create a DrawingTools instance with a root file as input:

root -l
root [0] DawingTools draw("file.root");

In this way the DrawingTools will be configured properly using information in the config tree (selection name, cut names, variables description, systematics, corrections, etc). By default the "T2K" plotting style is chosen. If you don't want to use it you can create the DrawingTools instance with a false as second argument

root [1] DawingTools draw("file.root",false);

You can inmediately have a quick look at the cuts that were applied, at the available categories for color code drawing, etc. This file is only used to congigure the DrawingTools. Now if you want to do plots you should either open a root file (could be the same) or create a DataSample intance with a root file as input. This is recomended, since in that case you can easily handle multiple samples (see drawingtools_multi):

root [2] DataSample data("data.root");
root [3] DataSample mc("mc.root");

Print information on the screen: systematics, cuts, categories, variables ...

Information about variables in the tree

These are the available methods:

/// Explain the meaning of a variable stored in a tree. If no tree name is provided the "default" tree is used
void ExplainVar(std::string name, std::string tree_name = "default") {doc().ExplainVar(name, tree_name);}
/// List all the variables stored in a tree. If no tree name is provided the "default" tree is used
void ListVars(std::string tree_name = "default") {doc().ListVars(tree_name);}

The following line in the root session

root [4] draw.ExplainVar("accum_level")

produces this output on the screen:

Variable name..... accum_level
Stored in tree.... default
Type of variable.. Vector of integer
Size of variable:
1st dimension... 1 (fixed size)
Documentation..... The number of the first cut that was failed.
highland supports running multiple toys (for evaluating systematics), so the index in this vector is the toy index.
If you only have one toy (normal), then you can use accum_level or accum_level[] to access the correct number.

List of corrections applied

The list of corrections applied in the current output file can be dumped as follows:

root [5] draw.DumpCorrections()
-------- List of Corrections -----------------------------------
#: name enabled applied in input
-----------------------------------------------------------------
0: pileup_corr 1 0
1: tpcdedx_data_corr 1 0
2: tpcdedx_mc_corr 1 0
3: tpcexpecteddedx_corr 1 0
4: ignorerightecal_corr 1 0
5: dq_corr 1 0
-----------------------------------------------------------------

where applied in input means that the input file already had the correction. This will be always false when running over oaAnalysis files, while it will be true in general when running over a FlatTree. When the correction is applied in input it will appear as disabled (not to apply it twice).

List of available systematics

The list of available systematics can be shown as follows:

root [6] draw.DumpSystematics()
-------- List of Systematics --------------------
#: name type NPar
--------------------------------------------------
0: kBFieldDist variation 1
1: kMomScale variation 1
2: kMomResol variation 3
3: kTpcPid variation 104
4: kFgdPid variation 4
5: kChargeConf weight 30
6: kTpcClusterEff weight 2
7: kTpcTrackEff weight 2
8: kTpcFgdMatchEff weight 6
9: kFgdTrackEff weight 14
10: kFgdHybridTrackEff weight 24
11: kMichel weight 8
12: kPileUp weight 7
13: kFgdMass weight 2
14: kOOFV weight 18
15: kSIPion weight 3
16: kSandMu weight 1
17: kFluxWeightNu weight 25
18: kFluxWeightAntiNu weight 25
--------------------------------------------------

Those are the systematics added to the SystematicManager (in the DefineSystematics methods) and not the systematics actually run, since those must be enabled in a specific confifuration, as shown below. The systematic type (variation or weight) and the number of systematic parameters are shown.

List of configurations

A configuration is defined by the list of enabled systematics in a given analysis. The list of configurations can be printed:

root [7] draw.DumpConfigurations()
-------- List of Configurations ----------------------------------
#: name NToys enabled NSyst RandomSeed
-------------------------------------------------------------------
0: default 1 1 0 -1
-------------------------------------------------------------------

There will be a tree with the same name as the configuration in the output file. In this case only the default configuration (allways pressent) was run, with 0 systematics, and no random seed (-1). We can print information about a particular configuration:

root [8] draw.DumpConfiguration("default")
Configuration: default *************
enabled: 1
NToys: 1
NSyst: 0
Random seed: -1

We can repeat the same operations with an output file created with the "all_syst" configuration enabled (baseAnalysis.Configurations.EnableAllSystematics = 1 in baseAnalysis.parameters.dat). In this particular example 9 systematics where enabled in baseAnalysis.parameters.dat, and 100 toy experiments were run:

root [9] draw.DumpConfigurations()
-------- List of Configurations ----------------------------------
#: name NToys enabled NSyst RandomSeed
-------------------------------------------------------------------
0: default 1 1 0 -1
1: all_syst 100 1 9 1
-------------------------------------------------------------------
root [10] draw.DumpConfiguration("all_syst")
Configuration: all_syst *************
enabled: 1
NToys: 100
NSyst: 9
Random seed: 1
-------- List of VariationSystematics ------------
#: name pdf NPar
--------------------------------------------------
0: kMomScale unknown 1
1: kTpcPid unknown 104
--------------------------------------------------
-------- List of WeightSystematics ---------------
#: name pdf NPar
--------------------------------------------------
0: kChargeConf unknown 30
1: kTpcTrackEff unknown 2
2: kMichel unknown 8
3: kPileUp unknown 7
4: kFgdMass unknown 2
5: kOOFV unknown 18
6: kSIPion unknown 3
--------------------------------------------------

In this case the list of systematics enabled in the configuration has been printed. Notice that the pdf (Probability Density Function) is labeled as unknown. This is becouse currently the random numbers for toy experiment variations are thrown externally, so individual systematics do not know its PDF. This will be changed in the future, such that we can know from the output file which pdf was used.

List of selections

The user can print on the screen the list of available selections:

root [11] draw.DumpSelections()
-------- List of Selections --------------------------------------------------------------------------------------------
#: name title enabled force break index in accum_level
-------------------------------------------------------------------------------------------------------------------------
0: kTrackerNumuCC inclusive numuCC selection 1 0 0
-------------------------------------------------------------------------------------------------------------------------

In this particular case only one selection was available and enabled (we have run the numuCCAnalysis). force break with 0 value means that the selection is not stopped when a cut is not pass. This is the standard behavior in highland2 (contrary to running directly in psyche) because we are in general interested in studiying the effect of the different cuts. This behaviour can be modified by changing the input argument in the selection constructor. For example, in highland2/numuCCAnalysis/vXrY/src/numuCCAnalysis.cxx, we find the line:

sel().AddSelection("kTrackerNumuCC", "inclusive numuCC selection", new numuCCSelection(false)); // true/false for forcing break

To stop the selection when a cut is not passed we should change false by true. The last field printed on the screen index in accum_level is the index of this selection in the accum_level array. When there are several selections in the same analysis the index will be different for each of them such that we can do plots for events that pass a given cut of a given selection.

List of steps and cuts in a selection

The available methods to dump information about steps or cuts in a selection are:

/// Print to screen the details of cuts for a given branch or selection. Specifying a branch of
/// -1 (the default) will print details for all branches.
/// When there are multiple selections the input index is for the selection
void DumpCuts(int branch=-1);
/// Print to screen the details of steps for a given branch or selection. Specifying a branch of
/// -1 (the default) will print details for all branches.
/// When there are multiple selections the input index is for the selection
void DumpSteps(int branch=-1);
/// Print to screen the details of cuts for a given branch and selection (name). Specifying a branch of
/// -1 (the default) will print details for all branches.
void DumpCuts(const std::string& sel_name, int branch=-1);
/// Print to screen the details of steps for a given branch and selection (name). Specifying a branch of
/// -1 (the default) will print details for all branches.
void DumpSteps(const std::string& sel_name,int branch=-1);
/// Print to screen the details of cuts for a given branch and selection (index). Specifying a branch of
/// -1 (the default) will print details for all branches.
void DumpCuts(Int_t sel_index, int branch);
/// Print to screen the details of steps for a given branch and selection (index). Specifying a branch of
/// -1 (the default) will print details for all branches.
void DumpSteps(Int_t sel_index,int branch);

In the example below, the numuCCAnalysis was run, which contains a single selection with no branches. In this case we don't have to give any argument to the methods:

root [12] draw.DumpSteps()
-------------------------------------------------------------------
Steps for selection 'kTrackerNumuCC' with no branches
-------------------------------------------------------------------
#: type title break branches
-------------------------------------------------------------------
0: cut event quality 1 0
1: cut > 0 tracks 1 0
2: action find leading tracks 0 0
3: action find vertex 0 0
4: action fill_summary 0 0
5: cut quality+fiducial 1 0
6: action find veto track 0 0
7: cut veto 0 0
8: action find oofv track 0 0
9: cut External FGD1 0 0
10: cut muon PID 0 0
-------------------------------------------------------------------
root [13] draw.DumpCuts()
-------------------------------------------------------------------
Cuts for selection 'kTrackerNumuCC' with no branches
-------------------------------------------------------------------
#: type title break branches
-------------------------------------------------------------------
0: cut event quality 1 0
1: cut > 0 tracks 1 0
2: cut quality+fiducial 1 0
3: cut veto 0 0
4: cut External FGD1 0 0
5: cut muon PID 0 0
-------------------------------------------------------------------

For more complicated analysis (with several selections and/or branches) we should specify the selection and the branch.

List of event/track categories

As mentioned above each event has a list of categories associated, which are in general related with the true properties of the event. For example one can plot the momentum distribution of the muon candidate with different colors for each particle type (stacked histogram). In this way we can see how many of our selected muons are in fact true muons. To do so the user have to specify the "particle" category in the corresponding DrawingTools method. There are other categories as true reaction type, detector in which the true interaction happened, etc. The list of categories or info about a specific category can be accessed using the following methods:

/// Print out the list of categories which can be used when plotting stacked histograms
void DumpCategories(){cat().DumpCategories();}
/// Print out the list of categories stored in the given file which can be used when plotting
/// stacked histograms
void DumpCategories(const std::string& file){ReadCategories(file);cat().DumpCategories();if (_config_file!="") ReadCategories(_config_file);}
/// Print the options saved for the given category, including the name of each category, the value
/// stored in the output file for that category, and the colour used to plot the category.
void DumpCategory(std::string category) {cat().DumpCategory(category);}

The list of categories:

root [14] draw.DumpCategories()
-------- Available track categories -------
- particle
- parent
- gparent
- primary
- nutype
- detector
- target
- reaction
- reactionCC (=1 when reaction<4 || reaction==9 for 2p2h)
- reactionnofv
- reactionsand
- reactionsandCC
- topology
- topology_no1pi
- topology_withpi0
- topology_ccpizero
- mectopology
-------- Track categories for FGD2 (if defined) -------
- fgd2<one_of_the_previous>
-------- Track categories for antinu (if defined) -------
same names as previous
-------------------------------------------

As mentioned above, there is also a method to print the available types for a given category, including the details (color, code) for each type:

root [14] draw.DumpCategory("reaction")
-------- Types for 'reaction' category -------
- CCQE (code 0, color 2)
- 2p2h (code 9, color 874)
- RES (code 1, color 3)
- DIS (code 2, color 4)
- COH (code 3, color 7)
- NC (code 4, color 6)
- anti-#nu_{#mu} (code 5, color 31)
- #nu_{e} (code 6, color 65)
- out FGD FV (code 7, color 1)
- other (code 999, color 48)
- no truth (code -1, color 92)
-------------------------------------------

POT information

Information about the POT corresponding to the data being analyses can be accessed with several methods. The simplest options are:

/// Dump the POT information for this sample, provided the header tree
void DumpPOT(TTree* tree);
/// Dump the POT information for this sample, provided an input file name
void DumpPOT(const std::string& file);

These are the available methods using DataSample or Experiment:

/// Dump the POT information for this sample, provided the sample it self
void DumpPOT(DataSample& data);
/// Dump the POT information for this sample, provided an Experiment and a sample group name (run1, run2a, run2w, ...)
void DumpPOT(Experiment& exp, const std::string& samplegroup_name);
/// return the Good POT used to create this DataSample object.
double GetGoodPOT(DataSample& data);
/// return the number of Good spills used to create this DataSample object.
int GetGoodSpills(DataSample& data);
/// Print out the ratio of POTs used to create these DataSample objects.
/// Ratio is set to 1 if either the numerator or denominator are 0.
double GetPOTRatio(DataSample& sample1, DataSample& sample2, double POTsample1_byhand=-1);
/// Print out the ratio of POTs between data and MC in this Experiment
/// Ratio is set to 1 if either the numerator or denominator are 0.
double GetPOTRatio(Experiment& exp);
/// Get the normalisation factor to apply when comparing sample1/sample2. If "pot_norm"
/// is true, then the POT ratio is returned. If not, the value specified by
/// "norm" is returned.
double GetNormalisationFactor(DataSample* sample1, DataSample* sample2, double norm=-1., bool pot_norm=true, const std::string& opt="");

This is one example for a single MC file:

root [15] DataSample mc("mc.root")
root [16] draw.DumpPOT(mc)
Initial POT........... 5e+17
|-- Bad Beam.......... 0
|-- Bad ND280......... 0
|-- Total Good POT.... 5e+17
|-- @ 0KA........... 0
|-- @ 200KA......... 0
|-- @ 250KA......... 0
|-- @ Other power... 0

Purities

// Print the purities for each type in the specified category and for a given selection cut
void PrintPurities(TTree* tree, const std::string& categ, const std::string& cut);

Produces the following output on the screen:

root [15] draw.PrintPurities(default,"reaction","accum_level>5")
Purities
Category reaction
Cut accum_level>5
Events 50283.6
------------------------------------------
CCQE 44.2077 % (22229.2 events)
2p2h 0 % (0 events)
RES 22.4987 % (11313.2 events)
DIS 20.7072 % (10412.3 events)
COH 2.84522 % (1430.68 events)
NC 3.2865 % (1652.57 events)
anti-#nu_{#mu} 0.577795 % (290.536 events)
#nu_{e} 0.295568 % (148.622 events)
out FGD FV 5.53933 % (2785.37 events)
other 0.0467397 % (23.5024 events)
no truth 0 % (0 events)
------------------------------------------

In this particular case the 2p2h category has 0 events becaouse the job was run on production 5 files.

If your microtree has more than one branch or selection, replace accum_level as explained in the next paragraph.

Different plotting functions: 1D, 2D, efficiencies, systematics, data-mc comparisons, etc

The DrawingTools have the following drawing functionality:

The functions shown below are in the class DrawingToolsBase.

In the follwing examples it is used a microtree with just one branch and one selection. For extending to a general case just replace: for microtrees with more than one branch OR more than one selection but without any branches: for functions on the truth tree: accum_level –> accum_level[branchID or selectionID] for functions on the default tree: accum_level –> accum_level[][branchID or selectionID] (the first empty [] is for the toy experiment) for microtrees with more than one selection AND more than one branches: for functions on the truth tree: accum_level –> accum_level[selectionID][branchID] for functions on the default tree: accum_level –> accum_level[][selectionID][branchID] (the first empty [] is for the toy experiment)

There are methods to draw single 1D or 2D distributions, provided the variable(s), the binning, the category to be plotted and the cut:

Draw single distributions

// Draw a single variable "var" in given tree with the specified binning. A cut can be applied using variables in the tree.
// The stacked histogram colors will refer to the specified category. If no category is specified only the total will be plotted.
// A normalization factor can be applied to the histogram contents. By default errors are scaled when thenormalization factor is not 1.
void Draw(TTree* tree, const std::string& var, int nx, double xmin, double xmax, const std::string& categ="all",
const std::string& cut="", const std::string& root_opt="", const std::string& opt="", double norm=1,bool scale_errors=true);
// The same for a 2D histogram
void Draw(TTree* tree, const std::string& var, int nx, double xmin, double xmax, int ny, double ymin, double ymax,
const std::string& categ="all", const std::string& cut="", const std::string& root_opt="", const std::string& opt="", double norm=1,bool scale_errors=true);

For example, a typical 1D distribution is:

root [16] draw.SetTitleX("muon candidate momentum (MeV/c)")
root [17] draw.Draw(default,"selmu_mom",50,0,5000,"topology","accum_level>5")
selmu_mom_topology.png

The syntax for drawing 2D plots follows ROOT's convention. The string you pass as the var option should be of the form

"y_var:x_var"

You can read this as plot y_var as a function of x_var. As an example of 2D distribution:

root [18] draw.SetTitleX("muon candidate cos(theta)")
root [19] draw.SetTitleY("muon candidate momentum (MeV/c)")
root [20] draw.Draw(default,"selmu_mom:selmu_costheta",10,0,1,50,0,5000,"all","accum_level>5","colz")
selmu_mom_vs_costheta.png

The 'cut' argument

The cut argument will normally just be used to select events passing a given cut, such as

"accum_level>2"

However, this can be any cut string that ROOT supports. You can reference any variable stored in the micro-tree, so could do something like this to only look at events passing the first 3 cuts and that have a momentum greater than 300 MeV (assuming your momentum variable is called selmu_mom).

"accum_level>2 && selmu_mom>300"

The same applies to the var argument, where you can combine multiple variables into a single one.

Vector and matrix variables

If you have saved vector variables in your output tree, for example to save a direction as a 3D array, you can access the components of the vector using the following syntax:

"dir[0]"

The argument in square brackets denotes the element of the vector you are accessing. You can combine vector variables and 2D plots to create, for example, 2D distributions of where interactions occur, using

"pos[1]:pos[0]"

which will create an X-Y plot. To make this pretty, you should pass "COLZ" as the root_opt argument when callign Draw().

You can also store matrix variables (with two indices) and 3D matrix variables (with three indices). The way of plotting those variables is similar to vectors, but you should specify the appropriate number of indices.

Imagine you have the position of all tpc segements in your muon candidate stored as matrix variable (selmu_tpc_pos), in which the first index corresponds to a given TPC and the second index to the component of the position. If you want to plot the y position of the first TPC you should use:

"selmu_tpc_pos[0][1]"

If on the contrary you want to plot the y position for all tpc segments:

"selmu_tpc_pos[][1]"

where the empty brackets is interpreted by ROOT and "all" components. A similar format is used for 3D matrix variables. You can use combinations as:

"var[][][2]"
"var[1][][2]"
"var[][1][2]"
"var[1][1][2]"

Draw ratios, efficiencies, purities and significances

These are the available methods, both for uniform and variable binning:

/// 1D Ratio between two independent cuts (the denominator cut is cut2, the numerator cut is cut1)
void DrawRatio(TTree* tree, const std::string& var, int nbins, double* xbins,
const std::string& cut1, const std::string& cut2, const std::string& root_opt="", const std::string& opt="", const std::string& leg="");
void DrawRatio(TTree* tree, const std::string& var, int nx, double xmin, double xmax,
const std::string& cut1, const std::string& cut2, const std::string& root_opt="", const std::string& opt="", const std::string& leg="");
// 1D Efficiency (ratio between dependent cuts: the denominator cut is cut2, the numerator cut is cut1+cut2, meaning
// that the numerator is a subsample of the denominator and multinomial errors should be used)
// This method can be used to plot the efficiency of a given cut (default tree),
// the selection efficiency (truth tree) or the selection purity (default tree).
// This method uses TGraphAsymmErrors
void DrawEff(TTree* tree, const std::string& var, int nbins, double* xbins, const std::string& cut1, const std::string& cut2,
const std::string& root_opt="", const std::string& opt="", const std::string& leg="");
void DrawEff(TTree* tree, const std::string& var, int nx, double xmin, double xmax, const std::string& cut1, const std::string& cut2,
const std::string& root_opt="", const std::string& opt="", const std::string& leg="");
/// ratio between two Efficiencies
void DrawDoubleEff(TTree* tree1, TTree* tree2, const std::string& var, int nx, double* xbins,
const std::string& cut1, const std::string& cut2, const std::string& root_opt="", const std::string& opt="", const std::string& leg="");
void DrawDoubleEff(TTree* tree1, TTree* tree2, const std::string& var, int nx, double xmin, double xmax,
const std::string& cut1, const std::string& cut2, const std::string& root_opt="", const std::string& opt="", const std::string& leg="");
/// 1D significance
void DrawSignificance(TTree* tree, const std::string& var, int nbins, double* xbins, const std::string& cut1, const std::string& cut2,
double norm=1, double rel_syst=0,const std::string& root_opt="", const std::string& opt="", const std::string& leg="");
void DrawSignificance(TTree* tree, const std::string& var, int nbins, double xmin, double xmax, const std::string& cut1, const std::string& cut2,
double norm=1, double rel_syst=0,const std::string& root_opt="", const std::string& opt="", const std::string& leg="");

For example we can draw the selection efficiency using the truth tree. In this example the denominator will contain all true numu CC events while the numerator will contain all true numu CC events that are selected:

root [18] draw.SetTitleX("true muon momentum (MeV/c)")
root [19] draw.SetTitleY("numu CC selection efficiency")
root [20] draw.DrawEff(truth,"truemu_truemom",50,0,5000,"accum_level>5","reactionCC==1")
numuCC_eff.png

And the selection purity using the default tree. In this case we use the same method but exchange the cut order. The denominator will contain all selected events while the numerator will contsin all selected events that are true numu cc.

draw.SetTitleX("muon candidate momentum (MeV/c)")
draw.SetTitleY("numu CC selection purity")
draw.DrawEff(default,"selmu_mom",50,0,5000,"reactionCC==1","accum_level>5")
numuCC_pur.png

Draw number of events, efficiency and purity as a function of the cut

These are the available methods:

/// Draw the number of events passing the selection as a function of the cut
void DrawEventsVSCut(TTree* tree, const std::string& cut_norm="", int first_cut=-1, int last_cut=-1,
const std::string& root_opt="", const std::string& opt="", const std::string& leg="");
/// Draw the number of events passing the selection as a function of the cut, for a given branch
void DrawEventsVSCut(TTree* tree, int branch, const std::string& cut_norm="", int first_cut=-1, int last_cut=-1,
const std::string& root_opt="", const std::string& opt="", const std::string& leg="");
/// Draw the number of events passing the selection as a function of the cut, for a given selection and branch
void DrawEventsVSCut(TTree* tree, int isel, int branch, const std::string& cut_norm="", int first_cut=-1, int last_cut=-1,
const std::string& root_opt="", const std::string& opt="", const std::string& leg="");
/// Draw the ratio between two trees as a function of the cut
void DrawRatioVSCut(TTree* tree1, TTree* tree2, const std::string& precut="", int first_cut=-1, int last_cut=-1,
const std::string& root_opt="", const std::string& opt="", const std::string& leg="", double norm=1.);
/// Draw the ratio between two trees as a function of the cut for a given branch
void DrawRatioVSCut(TTree* tree1, TTree* tree2, int branch, const std::string& precut="", int first_cut=-1, int last_cut=-1,
const std::string& root_opt="", const std::string& opt="", const std::string& leg="", double norm=1.);
/// Draw the ratio between two trees as a function of the cut for a given selection and branch
void DrawRatioVSCut(TTree* tree1, TTree* tree2, int isel, int branch, const std::string& precut="", int first_cut=-1, int last_cut=-1,
const std::string& root_opt="", const std::string& opt="", const std::string& leg="", double norm=1.);
/// Draw the selection efficiency as a function of the cut. Must use the truth tree as input
void DrawEffVSCut(TTree* tree, const std::string& signal="", const std::string& precut="", int first_cut=-1, int last_cut=-1,
const std::string& root_opt="", const std::string& opt="", const std::string& leg="");
/// Draw the selection efficiency as a function of the cut for a given branch. Must use the truth tree as input
void DrawEffVSCut(TTree* tree, int branch, const std::string& signal="", const std::string& precut="", int first_cut=-1, int last_cut=-1,
const std::string& root_opt="", const std::string& opt="", const std::string& leg="");
/// Draw the selection efficiency as a function of the cut for a given selection and branch. Must use the truth tree as input
void DrawEffVSCut(TTree* tree, int isel, int branch, const std::string& signal="", const std::string& precut="", int first_cut=-1, int last_cut=-1,
const std::string& root_opt="", const std::string& opt="", const std::string& leg="");
/// Draw the selection purity as a function of the cut. Must use the default tree as input
void DrawPurVSCut(TTree* tree, const std::string& signal="", const std::string& precut="", int first_cut=-1, int last_cut=-1,
const std::string& root_opt="", const std::string& opt="", const std::string& leg="");
/// Draw the selection purity as a function of the cut for a given branch. Must use the default tree as input
void DrawPurVSCut(TTree* tree, int branch, const std::string& signal="", const std::string& precut="", int first_cut=-1, int last_cut=-1,
const std::string& root_opt="", const std::string& opt="", const std::string& leg="");
/// Draw the selection purity as a function of the cut for a given selection and branch. Must use the default tree as input
void DrawPurVSCut(TTree* tree, int isel, int branch, const std::string& signal="", const std::string& precut="", int first_cut=-1, int last_cut=-1,
const std::string& root_opt="", const std::string& opt="", const std::string& leg="");

All those methods exist also for DataSample. There are other methods, which take two DataSamples:

/// Draw the ratio between two trees as a function of the cut
void DrawRatioVSCut(DataSample& sample1, DataSample& sample2, const std::string& precut="", int first_cut=-1, int last_cut=-1,
const std::string& root_opt="", const std::string& opt="", const std::string& leg="", double norm=-1., bool pot_norm=true);
void DrawRatioVSCut(DataSample& sample1, DataSample& sample2, int branch, const std::string& precut="", int first_cut=-1, int last_cut=-1,
const std::string& root_opt="", const std::string& opt="", const std::string& leg="", double norm=-1., bool pot_norm=true);
void DrawRatioVSCut(DataSample& sample1, DataSample& sample2, int isel, int branch, const std::string& precut="", int first_cut=-1, int last_cut=-1,
const std::string& root_opt="", const std::string& opt="", const std::string& leg="", double norm=-1., bool pot_norm=true);
void DrawEffPurVSCut(DataSample& sample, const std::string& signal, const std::string& precut="", int first_cut=-1, int last_cut=-1,
const std::string& root_opt="", const std::string& opt="", const std::string& leg="");
void DrawEffPurVSCut(DataSample& sample, int branch, const std::string& signal, const std::string& precut="", int first_cut=-1, int last_cut=-1,
const std::string& root_opt="", const std::string& opt="", const std::string& leg="");
void DrawEffPurVSCut(DataSample& sample, int isel, int branch, const std::string& signal, const std::string& precut="", int first_cut=-1, int last_cut=-1,
const std::string& root_opt="", const std::string& opt="", const std::string& leg="");
void DrawEffPurVSCut(DataSample& sample, int isel, int branch, const std::string& signal, const std::string& precut,
int first_cut_pur, int last_cut_pur, int first_cut_eff, int last_cut_eff,
const std::string& root_opt="", const std::string& opt="", const std::string& leg="");

And here some examples:

root [21] draw.DrawEventsVSCut(default)
events_vs_cut.png

As you can see the first two cuts have no effect because we only saved in the micro-tree events with accum_level>2 (SetMinAccumLevelToSave). We can remove those cuts from the plot as follows:

root [22] draw.DrawEventsVSCut(default,"",2)

what means that only cuts starting from cut number 2 (quality+fiducial) will be shown:

events_vs_cut_fromcut2.png
root [23] draw.SetTitleY("numu CC selection purity")
root [24] draw.DrawPurVSCut(default,"reactionCC==1")
numuCC_pur_vs_cut.png
root [25] draw.SetTitleY("numu CC selection efficiency")
root [26] draw.DrawEffVSCut(truth,"reactionCC==1")
numuCC_eff_vs_cut.png

The example below needs a DataSample to handle simultaneously the default and truth trees. More information about DataSample can be found below

root [27] DataSample mc("mc.root")
root [28] draw.SetTitleY("")
root [29] draw.DrawEffPurVSCut(mc,"reactionCC==1")
numuCC_effpur_vs_cut.png

Drawing statistical and systematic errors

A detailed description of systematic errors and how to draw them can be found an the systematics page. Here we just list the available drawing methods.

To plot relative or absolute errors as a faction of any variable:

// Draw absolute and relative errors for a given selection and binning provided a micro-tree.
// The option opt allows chosing statistical or systematics errors (or both).
Double_t DrawErrors(TTree* tree, const std::string& var, int nx, double xmin, double xmax,
const std::string& cut="", const std::string& root_opt="", const std::string& opt="", const std::string& leg="", double norm=1, bool scale_errors=false);
Double_t DrawRelativeErrors(TTree* tree, const std::string& var, int nx, double xmin, double xmax,
const std::string& cut="", const std::string& root_opt="", const std::string& opt="", const std::string& leg="", double norm=1, bool scale_errors=false);
Double_t DrawErrors(TTree* tree, const std::string& var, int nx, double* xbins,
const std::string& cut="", const std::string& root_opt="", const std::string& opt="", const std::string& leg="", double norm=1, bool scale_errors=false);
Double_t DrawRelativeErrors(TTree* tree, const std::string& var, int nx, double* xbins,
const std::string& cut="", const std::string& root_opt="", const std::string& opt="", const std::string& leg="", double norm=1, bool scale_errors=false);
// compare two different trees
Double_t DrawRelativeErrors(TTree* tree1, TTree* tree2, const std::string& var, int nx, double xmin, double xmax,
const std::string& cut="", const std::string& root_opt="", const std::string& opt="", const std::string& leg="", double norm=1, bool scale_errors=false);
Double_t DrawRelativeErrors(TTree* tree1, TTree* tree2, const std::string& var, int nx, double* xbins,
const std::string& cut="", const std::string& root_opt="", const std::string& opt="", const std::string& leg="", double norm=1, bool scale_errors=false);
// Draw absolute and relative errors for a given selection and binning provided an Experiment
Double_t DrawErrors(Experiment& exp, const std::string& groupName, const std::string& mcSampleName, const std::string& var, int nx, double xmin, double xmax,
const std::string& cut="", const std::string& root_opt="", const std::string& opt="", const std::string& leg="", bool scale_errors=false);
Double_t DrawRelativeErrors(Experiment& exp, const std::string& groupName, const std::string& mcSampleName, const std::string& var, int nx, double xmin, double xmax,
const std::string& cut="", const std::string& root_opt="", const std::string& opt="", const std::string& leg="", bool scale_errors=false);
Double_t DrawErrors(Experiment& exp, const std::string& groupName, const std::string& mcSampleName, const std::string& var, int nx, double* xbins,
const std::string& cut="", const std::string& root_opt="", const std::string& opt="", const std::string& leg="", bool scale_errors=false);
Double_t DrawRelativeErrors(Experiment& exp, const std::string& groupName, const std::string& mcSampleName, const std::string& var, int nx, double* xbins,
const std::string& cut="", const std::string& root_opt="", const std::string& opt="", const std::string& leg="", bool scale_errors=false);
// Draw absolute and relative errors for a given selection and binning provided an Experiment,
// and for a given MC sample ("magnet", "sand") in a sample group (i.e. "run3")
Double_t DrawErrors(Experiment& exp, const std::string& var, int nx, double xmin, double xmax,
const std::string& cut="", const std::string& root_opt="", const std::string& opt="", const std::string& leg="", bool scale_errors=false);
Double_t DrawRelativeErrors(Experiment& exp, const std::string& var, int nx, double xmin, double xmax,
const std::string& cut="", const std::string& root_opt="", const std::string& opt="", const std::string& leg="", bool scale_errors=false);
Double_t DrawErrors(Experiment& exp, const std::string& var, int nx, double* xbins,
const std::string& cut="", const std::string& root_opt="", const std::string& opt="", const std::string& leg="", bool scale_errors=false);
Double_t DrawRelativeErrors(Experiment& exp, const std::string& var, int nx, double* xbins,
const std::string& cut="", const std::string& root_opt="", const std::string& opt="", const std::string& leg="", bool scale_errors=false);

We can select statistical errors, systematics or both using the appropriate options (see the options Options for Drawing methods). If no option is given statistical errors will be plotted. We can also draw the covariance matrix:

/// Draw covariance matrix given a tree
void DrawCovMatrix(TTree* tree, const std::string& var, int nx, double xmin, double xmax,
const std::string& cut="", const std::string& root_opt="", const std::string& uopt="");
void DrawCovMatrix(TTree* tree, const std::string& var, int nx, double* xbins,
const std::string& cut="", const std::string& root_opt="", const std::string& uopt="");
/// Draw covariance matrix given an experiment; and for a given MC sample ("magnet", "sand") in a sample group (i.e. "run3"). MC information will be used
void DrawCovMatrix(Experiment& exp,const std::string& groupName, const std::string& mcSampleName, const std::string& var, int nx, double* xbins,
const std::string& cut="", const std::string& root_opt="", const std::string& uopt="");
void DrawCovMatrix(Experiment& exp,const std::string& groupName, const std::string& mcSampleName, const std::string& var, int nx, double xmin, double xmax,
const std::string& cut="", const std::string& root_opt="", const std::string& uopt="");
/// Draw covariance matrix given an experiment; MC information will be used
void DrawCovMatrix(Experiment& exp, const std::string& var, int nx, double* xbins,
const std::string& cut="", const std::string& root_opt="", const std::string& uopt="");
void DrawCovMatrix(Experiment& exp, const std::string& var, int nx, double xmin, double xmax,
const std::string& cut="", const std::string& root_opt="", const std::string& uopt="");
/// Returns covariance matrix given a tree
const TMatrixD& GetCovMatrix(TTree* tree, const std::string& var, int nx, double* xbins,
const std::string& cut="", const std::string& uopt="");
const TMatrixD& GetCovMatrix(TTree* tree, const std::string& var, int nx, double xmin, double xmax,
const std::string& cut="", const std::string& uopt="");
/// Returns covariance matrix given an experiment; and for a given MC sample ("magnet", "sand") in a sample group (i.e. "run3"). MC information will be used
const TMatrixD& GetCovMatrix(Experiment& exp,const std::string& groupName, const std::string& mcSampleName, const std::string& var, int nx, double xmin, double xmax,
const std::string& cut="", const std::string& root_opt="", const std::string& uopt="");
const TMatrixD& GetCovMatrix(Experiment& exp,const std::string& groupName, const std::string& mcSampleName, const std::string& var, int nx, double* xbins,
const std::string& cut="", const std::string& root_opt="", const std::string& uopt="");
/// Returns covariance matrix given an experiment; MC information will be used
const TMatrixD& GetCovMatrix(Experiment& exp, const std::string& var, int nx, double xmin, double xmax,
const std::string& cut="", const std::string& root_opt="", const std::string& uopt="");
const TMatrixD& GetCovMatrix(Experiment& exp, const std::string& var, int nx, double* xbins,
const std::string& cut="", const std::string& root_opt="", const std::string& uopt="");

Toy experiments plots

In addition to the methods above to draw systematic errors there are methods to check the distribution of toy experiments:

/// This method draws the distribution of the number of selected events for all toys (one entry per toy in the histogram), provided a cut
/// This is useful to check that the systematic error bars correspond to the RMS of this distribution
void DrawToys(TTree* tree, const std::string& cut="", const std::string& root_opt="", const std::string& opt="", const std::string& leg="");
/// This method draws the distribution of the ratio of number of selected events between two samples for all toys (one entry per toy in the histogram),
/// provided a cut (the same for numerator and denominator)
void DrawToysRatio(TTree* tree1, TTree* tree2, const std::string& cut="",
const std::string& root_opt="", const std::string& opt="", const std::string& leg="", double norm=1);
/// This method draws the distribution of the ratio of number of selected events between two samples for all toys (one entry per toy in the histogram),
/// provided two cuts, one for the numerator and another for the denominator
void DrawToysRatioTwoCuts(TTree* tree1, TTree* tree2, const std::string& cut1, const std::string& cut2,
const std::string& root_opt="", const std::string& opt="", const std::string& leg="",double norm=1);

Comparison between two data samples

In this case either you open two root files containg the output of two different analyses for two data samples (data.root, mc.root), and copy simultaneously in memory the micro-trees we want a use to compare, or use DataSample, which handles multiple data samples for you (see below)

// 1D comparison for variable "var". The normalization factor is relevant now
void Draw(TTree* tree1, TTree* tree2, const std::string& var, int nx, double xmin, double xmax,
const std::string& categ="all", const std::string& cut="", const std::string& root_opt="", const std::string& opt="", double norm=1,
// 2D comparison for variable "var"
void Draw(TTree* tree1, TTree* tree2, const std::string& var, int nx, double xmin, double xmax, int ny, double ymin, double ymax,
const std::string& categ="all", const std::string& cut="",
const std::string& root_opt="", const std::string& opt="", double norm=1, bool scale_errors=false);
// Ratio between the two data samples with the same cut
void DrawRatio(TTree* tree1, TTree* tree2, const std::string& var, int nx, double xmin, double xmax,
const std::string& cut="", const std::string& root_opt="", const std::string& opt="", const std::string& leg="", double norm=1);
// Ratio between the two data samples with different cuts
void DrawRatioTwoCuts(TTree* tree1, TTree* tree2, const std::string& var, int nx, double xmin, double xmax,
const std::string& cut1, const std::string& cut2,
const std::string& root_opt="", const std::string& opt="", const std::string& leg="", double norm=1);

Using DataSample to easily handle multiple data samples

All functions above are also available using DataSample as input instead of a single tree. For example for a data-MC comparison:

void Draw(DataSample& sample1, DataSample& sample2, const std::string& var, int nx, double xmin, double xmax,
const std::string& categ="all", const std::string& cut="",
const std::string& root_opt="", const std::string& opt="",bool scale_errors=false, double norm=1, bool pot_norm=true);

where sample1 and sample 2 will be created using two different micro-tree files (output of highland analyses):

DataSample sample1("sample1.root");
DataSample sample2("sample2.root");

In this case the normalization factor will be computed automatically (unless we specify the contrary in the last argument) from the header tree in both DataSample. Those extended functions are part of DrawingTools, which inherits from DrawingToolsBase. The code and figure below show an example:

root [1] DrawingTools draw("data.root")
root [2] DataSample mc("mc.root")
root [3] DataSample data("data.root")
root [4] draw.SetTitleX("muon candidate momentum (MeV/c)")
root [5] draw.Draw(data,mc,"selmu_mom",50,0,5000,"topology","accum_level>5")
selmu_mom_datamc_topology.png

Now we list all available methods for samples comparison:

// Draw a single distribution of "var" for sample1 and sample2 superimposed. The total is shown for sample1 (usually data)
// while the breakdown in types for the specified category (categ) is shown for the second sample (usually MC)
// By default POT normalization is used, altho a scalling factor for the second sample can be introduced (norm). In that case
// the last argument (pot_norm) should be false
void Draw(DataSample& sample1, DataSample& sample2, const std::string& var, int nx, double xmin, double xmax,
const std::string& categ="all", const std::string& cut="",
const std::string& root_opt="", const std::string& opt="", double norm=1, bool scale_errors=false, bool pot_norm=true);
// The same for a 2D distribution
void Draw(DataSample& sample1, DataSample& sample2, const std::string& var, int nx, double xmin, double xmax, int ny, double ymin, double ymax,
const std::string& categ="all", const std::string& cut="",
const std::string& root_opt="", const std::string& opt="", double norm=1, bool scale_errors=false, bool pot_norm=true);
// Draw the ratio between sample1 and sample2 as a function of "var" provided a different cut for each of the samples
// The same comments about normalization apply to this method. In this case a legent can be added since we might be
// interested in plotting several rations in the same canvas
void DrawRatioTwoCuts(DataSample& sample1, DataSample& sample2, const std::string& var, int nx, double xmin, double xmax,
const std::string& cut1, const std::string& cut2,
const std::string& root_opt="", const std::string& opt="", const std::string& leg_name="", double norm=1, bool pot_norm=true);
// Draw the ratio between sample1 and sample2 as a function of "var" provided the same cut for both samples
void DrawRatio(DataSample& sample1, DataSample& sample2, const std::string& var, int nx, double xmin, double xmax,
const std::string& cut="",
const std::string& root_opt="", const std::string& opt="", const std::string& leg_name="", double norm=1, bool pot_norm=true);

The plot below shows the data/MC ratio as a function of the muon candidate momentum for different cuts. Here we also learn how to change the legend position to the bottom-left ("bl") corner:

root [9] draw.SetLegendPos("bl")
root [9] draw.SetTitleX("muon candidate momentum (MeV/c)")
root [8] draw.SetTitleY("data/MC ratio")
root [6] draw.DrawRatio(data,mc,"selmu_mom",10,0,5000,"accum_level>5","","","after all cuts")
root [7] draw.DrawRatio(data,mc,"selmu_mom",10,0,5000,"accum_level>4","same","","before PID cut")
root [7] Draw.DrawRatio(data,mc,"selmu_mom",10,0,5000,"accum_level>2","same","","before quality+fiducial cut")

Data MC comparison plots can be also done using the Experiment class (see below).

selmu_mom_datamc_ratio.png

Using Experiment to easily handle multiple data taking periods

The Experiment class allows to make data-MC comparison plots with separated data-MC sample pairs for each data taking period, taking into account the proper POT normalization between data and MC for each run.

We can define an Experiment as a collection of SampleGroup's, where each sample group would correspond to a different data taking period. A SampleGroup would contain several samples (DataSample), one for real data and several for MC ("magnet", "sand", etc). The code below creates an Experiment, suitable for nd280 data:

// Create an experiment with name "nd280"
Experiment exp("nd280");
// Create data samples for the different periods
DataSample* data1 = new DataSample("data1.root");
DataSample* data2w = new DataSample("data2w.root");
DataSample* data2a = new DataSample("data2a.root");
DataSample* data3 = new DataSample("data3.root");
DataSample* data4 = new DataSample("data4.root");
// Create magnet MC samples for the different periods
DataSample* mc1 = new DataSample("mc1.root");
DataSample* mc2w = new DataSample("mc2w.root");
DataSample* mc2a = new DataSample("mc2a.root");
DataSample* mc3 = new DataSample("mc3.root");
DataSample* mc4 = new DataSample("mc4.root");
// Create sand muons MC samples for the differenr periods. Last namber should be 1 for sand muons
DataSample* sand1 = new DataSample("mc1_sand.root", 1);
DataSample* sand2w = new DataSample("mc2w_sand.root",1);
DataSample* sand2a = new DataSample("mc2a_sand.root",1);
DataSample* sand3 = new DataSample("mc3_sand.root", 1);
DataSample* sand4 = new DataSample("mc4_sand.root", 1);
// Now create SampleGroup's for each period and add the corresponding data and MC samples
SampleGroup run1("run1");
run1.AddDataSample(data1);
run1.AddMCSample("magnet",mc1);
run1.AddMCSample("sand",sand1);
SampleGroup run2w("run2w");
run2w.AddDataSample(data2w);
run2w.AddMCSample("magnet",mc2w);
run2w.AddMCSample("sand",sand2w);
SampleGroup run2a("run2a");
run2a.AddDataSample(data2a);
run2a.AddMCSample("magnet",mc2a);
run2a.AddMCSample("sand",sand2a);
SampleGroup run3("run3");
run3.AddDataSample(data3);
run3.AddMCSample("magnet",mc3);
run3.AddMCSample("sand",sand3);
SampleGroup run4("run4");
run4.AddDataSample(data4);
run4.AddMCSample("magnet",mc4);
run4.AddMCSample("sand",sand4);
exp.AddSampleGroup("run1", run1);
exp.AddSampleGroup("run2w",run2w);
exp.AddSampleGroup("run2a",run2a);
exp.AddSampleGroup("run3", run3);
exp.AddSampleGroup("run4", run4);

Once the Experiment is defined plots can be made:

// Data-MC comparison plots using a vector of pairs of data and MC samples (Experiment), properly normalised to each other.
void Draw(Experiment& exp, const std::string& var, int nx, double xmin, double xmax,
const std::string& categ="all", const std::string& cut="", const std::string& root_opt="", const std::string& opt="",bool scale_errors=false);
// Data-MC comparison plots using a single pair of data and MC samples from the Experiment properly normalised to each other.
void Draw(Experiment& exp, const std::string& groupName, const std::string& var, int nx, double xmin, double xmax,
const std::string& categ="all", const std::string& cut="", const std::string& root_opt="", const std::string& opt="",bool scale_errors=false);
// Data-MC comparison plots using a single pair of data and MC samples, and a single MC sample (i.e. only "magnet" or "sand") properly normalised to each other.
void Draw(Experiment& exp, const std::string& groupName, const std::string& mcSampleName, const std::string& var, int nx, double xmin, double xmax,
const std::string& categ="all", const std::string& cut="", const std::string& root_opt="", const std::string& opt="",bool scale_errors=false);

In the later two functions, groupName and mcSampleName can take the value "all". For example

root [6] draw.Draw(exp,"run2w","sand","selmu_mom",50,0,5000,"reaction","accum_level>5")

would plot Run 2 water for data and the corresponding sand muon MC only properly normalized, while

root [7] draw.Draw(exp,"all","sand","selmu_mom",50,0,5000,"reaction","accum_level>5")

would plot all data runs and the corresponding sand muon MC only properly normalized for each run.

Configuration for plots: binning, options, style, ...

Variable binning

All functions above for which binning should be specified have the corresponding function with variable binning. In that case

int nx, double xmin, double xmax

should be substituded by

int nx, double* xbins

and

int nx, double xmin, double xmax , int ny, double ymin, double ymax

should be substituded by

int nx, double* xbins, int ny, double* ybins

For example:

root [8] draw.SetTitleX("muon candidate momentum (MeV/c)")
root [9] draw.SetTitleY("# entries / (100 MeV/c)")
root [10] double pbins[15] = {0, 200, 300, 400, 500, 600, 700, 800, 900, 1000, 1250, 1500, 2000, 3000, 5000};
root [11] draw.Draw(data,mc,"selmu_mom",14,pbins,"topology","accum_level>5")

produces the following plot:

selmu_mom_datamc_topology_varbin.png

By default, to keep a nice plot appearence, bin contents are normalized to the bin width. If we want disable that feature we should use the option "NOVARBIN":

root [12] draw.SetTitleY("# entries")
root [13] draw.Draw(data,mc,"selmu_mom",14,pbins,"topology","accum_level>5",1,"","NOVARBIN")
selmu_mom_datamc_topology_novarbin.png

Options for Drawing methods

Most functions described above take the following arguments:

The list of DrawingTools options can be printed on the screen with the command:

root [14] draw.ListOptions()

The available options are defined in the DrawingUtils.cxx file:

drawUtils::AddOption("SCALETODATA","Scale the MC covariance matrix to data POT when using Experiment");
drawUtils::AddOption("NOCHOP", "??");
drawUtils::AddOption("E0", "Error style option for second sample. Does the same as the root option e0");
drawUtils::AddOption("E1", "Error style option for second sample. Does the same as the root option e1");
drawUtils::AddOption("E2", "Error style option for second sample. Does the same as the root option e2");
drawUtils::AddOption("E3", "Error style option for second sample. Does the same as the root option e3");
drawUtils::AddOption("E4", "Error style option for second sample. Does the same as the root option e4");
drawUtils::AddOption("E5", "Error style option for second sample. Does the same as the root option e5");
drawUtils::AddOption("E6", "Error style option for second sample. Does the same as the root option e6");
drawUtils::AddOption("ETOT", "When drawing with color codes, draw also the total error for the stacked histogram");
drawUtils::AddOption("NOTOTERROR","Don't draw the total error (stat+syst) but only the statistical or systematic error");
drawUtils::AddOption("NOSTERROR", "Don't draw the statistical error but only the total error, and also the systematic error when SYSTERROR options is also used");
drawUtils::AddOption("SYSTERROR", "Don't draw the statistical error but only the systematic error, together with the total");
drawUtils::AddOption("DUMP", "Print on the secreen the histo or graph contents");
drawUtils::AddOption("NODRAW", "Don't draw anything. You should use the option DUMP to see the results");
drawUtils::AddOption("ST", "When using DrawErrors or DrawRelativeErrors only statistical errors are plotted. In combination with SYS, SSYS or WSYS adds statisticak and systematic errors in quadrature");
drawUtils::AddOption("SYS", "draw all systematics. Error bars correspond to the RMS of all toy experiments");
drawUtils::AddOption("SSYS", "Draw only standard systematics (reconstructed observable variations)");
drawUtils::AddOption("WSYS", "Draw only weight systematics");
drawUtils::AddOption("WSi", "Draw only the specified (ith) weight systematic(s) (\" WS0 WS3 ... \")");
drawUtils::AddOption("NWSi", "Exclude the specified (ith) weight systematic(s) (\"NWS0 NWS1 ... \")");
drawUtils::AddOption("WCi", "Draw only the specified (ith) weight correction(s) (\" WC0 WC3 ... \")");
drawUtils::AddOption("NWCi", "Exclude the specified (ith) weight correction(s) (\"NWC0 NWC1 ... \")");
drawUtils::AddOption("WCORR", "Apply Weight corrections only (not weight systematics)");
drawUtils::AddOption("RELATIVE", "When computing the covariance matrix divide by the average in each bin such that a relative covariance is computed");
drawUtils::AddOption("NOLEG", "No legend is drawn");
drawUtils::AddOption("PUR", "The purity is printed on the screen and on the legend");
drawUtils::AddOption("EFF", "The efficiency-like ratio plot (out of two histograms, pass and total) is drawn, internal option");
drawUtils::AddOption("NOST2", "The stat box for the second sample is not shown");
drawUtils::AddOption("NOSTAT", "No stat box is shown");
drawUtils::AddOption("NOMIN", "The minimum in Y is not used");
drawUtils::AddOption("NOVARBIN", "Plotting with variable binning, bin entries are normalized by bin width. This option disables this feature.");
drawUtils::AddOption("NOTOYW", "No toy weight is applied for toy experiments. All toys will have the same weight 1.");
drawUtils::AddOption("NOW", "None of the weights (flux and pileup) are applied to the event");
drawUtils::AddOption("NOFLUXW", "No flux weight is applied to the event");
drawUtils::AddOption("NOPILEUPW", "No pile up weight is applied to the event");
drawUtils::AddOption("NODATA", "The data is not shown in the plot");
drawUtils::AddOption("NOMC", "The MC is not shown in the plot");
drawUtils::AddOption("NODEFAULT", "By default the -999 default is plotted unless this option is used");
drawUtils::AddOption("UNDER", "Underflow entries are added to the first bin");
drawUtils::AddOption("OVER", "Overflow entries are added to the last bin");
drawUtils::AddOption("PROFX", "For 2D histos a Profile histogram in X is drawn");
drawUtils::AddOption("PROFY", "For 2D histos a Profile histogram in Y is drawn");
drawUtils::AddOption("AREA", "For 1D histos normalization to 1 (if there is only one sample) or to the area of the first sample. In this normalization procedure the whole range of the variable allowed by 'cut' parameter is taken into account");
drawUtils::AddOption("AREA1", "For 1D histos normalization to 1. In this normalization procedure the whole range of the variable allowed by 'cut' parameter is taken into account");
drawUtils::AddOption("AREA100", "For 1D histos normalization to 100. In this normalization procedure the whole range of the variable allowed by 'cut' parameter is taken into account");
drawUtils::AddOption("POTNORM", "Normalize the MC to the POT given as input normalization factor, regardless of the data POT (interprete valid norm factor as a POT value)");
drawUtils::AddOption("NOPOTNORM", "Disable POT normalization. Second sample is not scaled");
drawUtils::AddOption("IGNOREEMPTY", "Do not put categories without entries in the legend");
drawUtils::AddOption("DRAWALLMC", "Draw with black contour a histogram for all MC entries (works only while plotting histogram stack)");
drawUtils::AddOption("DRAWALLCUTS", "Draw all cuts even if they are below the MinAccumLevelToSave when doing plots VSCuts");
drawUtils::AddOption("NOINFO", "Dont dump on the screen histogram info when using the Draw methods");
drawUtils::AddOption("SHOWSAND", "Show the sand mu type even when it is empty");
drawUtils::AddOption("SHOWNOTRUTH", "Show the NO TRUTH type even when it is empty");
drawUtils::AddOption("RATIO", "Draw the Data/MC ratio underneath the stack plot");

Explaination of a specific option can be printed as follows:

root [13] draw.ExplainOption("PUR")
PUR: The purity is printed on the screen

Notice that several options can be combined. For example "ST SYS" will plot error bars as the sum in quadrature of statistical and systematic errors.

Command line style options

You can change the plot appearence by changing several attributes, such that the position of the legend, the X and Y labels, etc. Once a given attribute is set it will have effect on all subsequent plots. This are the available methods:

/// Set the height (in normalized coordinates: NDC) of each legend entry
void SetLegendEntryHeight(double h){drawUtils::legendEntryHeight=h;}
/// Set position and size of the legend
void SetLegendParam(double a, double b, double c, double d);
/// Set legend/small legend position by double (-999 keep current value)
/// or by string ("l"=left, "r"=right , "c"=center, "t"=top, "b"=bottom)
void SetLegendPos(double x=-999, double y=-999);
void SetLegendPos(std::string pos);
/// Set legend/small legend size, width and height (if -999 keep same value)
void SetLegendSize(double w = -999, double h = -999);
void SetSmallLegendSize(double w = -999, double h = -999){if (w != -999) _legendSmallSize[0] = w; if (h != -999) _legendSmallSize[1] = h;}
/// Get position/size of the legend/small legend
double GetLegendX() { return _legendPos[0]; }
double GetLegendY() { return _legendPos[1]; }
double GetLegendW() { return _legendSize[0]; }
double GetLegendH() { return _legendSize[1]; }
double GetSmallLegendX() { return _legendPos[0]+_legendSize[0]-_legendSmallSize[0]; }
double GetSmallLegendY() { return _legendPos[1]+_legendSize[1]-_legendSmallSize[1]; }
double GetSmallLegendW() { return _legendSmallSize[0]; }
double GetSmallLegendH() { return _legendSmallSize[1]; }
/// Set the stat option (by int or string)
void SetOptStat(int opt){ _stat_option=opt; }
void SetOptStat(Option_t *stat);
/// Set/Get the stat box size
double GetStatW() { return gStyle->GetStatH(); }
double GetStatH() { return gStyle->GetStatW(); }
void SetStatSize(double w = -999, double h = -999) {if (w != -999) gStyle->SetStatW(w); if (h != -999) gStyle->SetStatH(h);}
/// Set/Get the stat box position (if -999 keep same value)
double GetStatX() { return gStyle->GetStatX(); }
double GetStatY() { return gStyle->GetStatY(); }
void SetStatPos(double x = -999, double y = -999);
/// Change the fill style
void SetStackFillStyle(int FillStyle) { _stack_fill_style= FillStyle;};
/// Make each histogram in the stack have a different fill style.
void SetDifferentStackFillStyles(bool diff = true) { _different_fill_styles = diff; };
/// change the marker style
void SetMarkerStyle(int style) { _marker_style = style; }
/// change the marker size
void SetMarkerSize(double size) { _marker_size = size; }
/// Set the fill style of the current histogram..
void SetFillStyle(int style) { _fill_style = style; }
/// Set the line width of the current histogram..
void SetLineWidth(int width) { _line_width = width; }
/// Set the line color of the current histogram..
void SetLineColor(int color) { _line_color = color; }
void SetLineColor(EColor kColor) { _line_color = kColor; }
/// Set the line color of the current histogram..
void SetFillColor(int color) { _fill_color = color; }
void SetFillColor(EColor kColor) { _fill_color = kColor; }
/// Set the color for the MC error bars
void SetMCErrorColor(EColor kColor) { _mcerror_color = kColor; }
void SetMCErrorColor(int color) { _mcerror_color = color; }
void SetMCStatErrorColor(EColor kColor) { _mcstaterror_color = kColor; }
void SetMCStatErrorColor(int color) { _mcstaterror_color = color; }
/// Set the auto colors when superimposing histograms
void SetAutoColors(int colors[],int ncolors);
/// Set the auto Markers when superimposing histograms
void SetAutoMarkers(int markers[], int nmarkers);
/// Setter and Getter for params controlling the efficiency calculation
const std::string& GetEffDivideParams() { return _eff_params;}
void SetEffDivideParams(const std::string& params);
/// Setter of default params
void SetDefaultEffDivideParams();
/// Set the title in X
void SetTitleX(const std::string& titleX){_titleX=titleX;}
/// Set the title in Y
void SetTitleY(const std::string& titleY){_titleY=titleY;}
/// Set the title that appears at the top of the plot.
void SetTitle(const std::string& title){_title=title;}
/// Set the label for the data when drawing comparison plots. Defaults to "Data".
/// Setting it to "" (empty string) will disable adding it to the legend.
void SetDataLabel(const std::string& label, Color_t color = kBlack) {_data_label = label; _data_color = color;}
/// Set the label for the mc when drawing comparison plots. Defaults to "MC all".
/// Setting it to "" (empty string) will disable adding it to the legend.
void SetAllMCLabel(const std::string& label, Color_t color = kBlack) {_allmc_label = label; _allmc_color = color;}
/// Set the label for the mc with only statistical errors when drawing comparison plots. Defaults to "MC all (stat)".
/// Setting it to "" (empty string) will disable adding it to the legend.
void SetAllMCStatLabel(const std::string& label){_allmcstat_label=label;}
/// Set the label for the mc with only systematic errors when drawing comparison plots. Defaults to "MC all (syst)".
/// Setting it to "" (empty string) will disable adding it to the legend.
void SetAllMCSystLabel(const std::string& label){_allmcstat_label=label;}
/// Set the minimum of the Y-axis. By default the minimum is set to 0.
/// Call SetMinY() to revert to the default behaviour.
void SetMinY(double minY=0);
/// Set the maximum of the Y-axis. By default the maximum is set automatically by the DrawingTools.
/// Call SetMaxY() to revert to the default behaviour.
void SetMaxY(double maxY=0){_maxY = maxY;}
/// Set the minimum and maximum of the Y-axis. See the documentation of SetMinY and SetMaxY for the
/// default behaviour. Call SetRangeY() to revert to the default behaviour.
void SetRangeY(double minY=0, double maxY=0) {SetMinY(minY); SetMaxY(maxY);}
/// Set the current histogram to be drawn with a logarithmic Y axis.
void SetLogY(bool logY = true);
/// Set the current 2D histogram to be drawn with a logarithmic Z axis (works only for category "all").
void SetLogZ(bool logZ = true);
/// Set the maximum value in Y relative to the bin with maximum content
void SetRelativeMaxY(double maxY){_relativeMaxY=maxY;}
/// Gets the root error style from the user option
std::string GetErrorStyle(const std::string& opt);
/// switch on/off 2p2h type for reaction histos
void SetDraw2p2h(bool draw = true){_draw_2p2h=draw;}

Cut lines and regions

Cut lines can be drawn over previously-drawn histograms. There are functions for drawing horizontal or vertical lines (with an optional arrow indicating the direction fo the cut), as well as cut regions for 2D plots (with the option for only drawing certain sides of the box, should the cut be "open"). By default the cut lines are constrained to stay within the boundary of the current axes. If a legend has already been drawn on the current pad, it is re-drawn so it is on top of the cut line).

The available methods to draw cut lines and regions are listed below:

/// Draw a vertical line at the specified X value, spanning the currently-drawn histogram.
/// See note in DrawCutLine() about legends being re-drawn when calling this function.
/// If addarrow is set to true, then an arrow indicating the direction of the cut is drawn.
/// arrowdir respects the following options:
/// l : Draw the arrow pointing to the left
/// r : Draw the arrow pointing to the right (default)
/// arrowpos specifies the fractional length along the cut line to draw the arrow at, measuring
/// from the bottom of the line. Defaults to half way along.
void DrawCutLineVertical(double xval, bool addarrow = false, std::string arrowdir = "l", double arrowpos = 0.5);
/// Draw a horizontal line at the specified Y value, spanning the currently-drawn histogram.
/// See note in DrawCutLine() about legends being re-drawn when calling this function.
/// If addarrow is set to true, then an arrow indicating the direction of the cut is drawn.
/// arrowdir respects the following options:
/// u : Draw the arrow pointing upwards (default)
/// d : Draw the arrow pointing downwards
/// arrowpos specifies the fractional length along the cut line to draw the arrow at, measuring
/// from the left end of the line. Defaults to half way along.
void DrawCutLineHorizontal(double yval, bool addarrow = false, std::string arrowdir = "u", double arrowpos = 0.5);
/// Draw an abritary line between two points. If a legend had already been created by the
/// DrawingTools, and drawn on the current pad, it is re-drawn. This means that the line
/// does not cover it up.
void DrawCutLine(double xmin, double ymin, double xmax, double ymax);
/// Draw a box defined by the minimum and maximum points. The opt parameter specifies,
/// among other things, which sides of the box to draw:
/// t : draw the (t)op of the box
/// b : draw the (b)ottom of the box
/// l : draw the (l)eft of the box
/// r : draw the (r)ight of the box
/// nochop : Don't constrain the sides of the box to stay within the current axes.
///
/// See note in DrawCutLine() about legends being re-drawn when calling this function.
void DrawCutRegion(double xmin, double ymin, double xmax, double ymax, std::string opt = "tblr");
/// Draw an arrow between two points. If a legend had already been created by the
/// DrawingTools, and drawn on the current pad, it is re-drawn. This means that the line
/// does not cover it up.
void DrawCutArrow(double xmin, double ymin, double xmax, double ymax);
/// Set the color of lines drawn with the DrawCut* functions.
void SetCutLineColor(int col) { _cut_line_col = col; }
void SetCutLineColor(EColor kCol) { _cut_line_col = kCol; }
/// Set the width of lines drawn with the DrawCut* functions.
void SetCutLineWidth(int width) {_cut_line_width = width;}

For example we can plot the muon candidate MIP likelihood before the PID cut and add an arrow to show which cut is made:

root [14] draw.SetTitleX("muon candidate MIP likelihood")
root [15] draw.Draw(data,mc,"selmu_likemip",50,0,1,"particle","accum_level>4")
root [16] draw.DrawCutLineVertical(200,true,"r")
cutarrow.png

Create file with event numbers for a given selection

There are function to extract the the event numbers for a given selection, which can be very useful to create skimmed files:

// Print the event number of a specific selection
void PrintEventNumbers(TTree* tree, const std::string& cut, const std::string& file="", int refana=-1);
void PrintEventNumbers(DataSample& sample, const std::string& cut, const std::string& file, int refana=-1);

When calling the following function:

root [14] draw.PrintEventNumbers(default,"mu_mom>100 && mu_mom<200","events.list")

the file events.list is produced with the following content:

90200000,0,607
90200000,0,918
90200000,0,2142
90200000,0,2716
90200000,0,3312
90200000,0,3546
90200000,0,4746
90200000,0,6095
90200000,0,6187

where the first number is the run, the second subrun and the third the event number.