Crombie Tools
PlotBase.h
Go to the documentation of this file.
1 /**
2  @file PlotBase.h
3 
4  Definition of PlotBase class. Since PlotBase is never initialized directly as a class,
5  the entire class definition is contained in this header file.
6 
7  @author Daniel Abercrombie <dabercro@mit.edu>
8 */
9 
10 #ifndef CROMBIETOOLS_PLOTTOOLS_PLOTBASE_H
11 #define CROMBIETOOLS_PLOTTOOLS_PLOTBASE_H
12 
13 #include <utility>
14 #include <vector>
15 #include <type_traits>
16 
17 #include "TObject.h"
18 #include "TStyle.h"
19 #include "TTree.h"
20 #include "TString.h"
21 #include "TCut.h"
22 #include "TLatex.h"
23 #include "TH1.h"
24 #include "TGraphErrors.h"
25 #include "TCanvas.h"
26 #include "TLegend.h"
27 #include "TColor.h"
28 #include "TLine.h"
29 
30 #include "PlotUtils.h"
31 #include "Debug.h"
32 
33 /**
34  @ingroup plotgroup
35  @class PlotBase
36  Base class for all plotting classes.
37  PlotBase holds much of the parameters used for plotting various kinds of plots.
38  It also holds all of the functions that are used to create and save the canvas.
39 */
40 
41 class PlotBase : virtual public Debug
42 {
43  public:
44  PlotBase();
45  virtual ~PlotBase();
46 
47  /// This function adds a tree pointer, cut, and expression used for generating a line in the plot
48  inline void AddLine ( TTree *tree, TCut cut, TString expr );
49 
50  /// Set a tree and weight concurrently for each line. Best used when a default expression is set.
51  inline void AddTreeWeight ( TTree *tree, TCut cut );
52  /// Set a tree and expression concurrently for each line. Best used when a default weight is set.
53  inline void AddTreeExpr ( TTree *tree, TString expr );
54  /// Set a weight and expression concurrently for each line. Best used when a default tree is set.
55  inline void AddWeightExpr ( TCut cut, TString expr );
56 
57  /// Set entry and color for each line. This uses the default line width and style.
58  inline void AddLegendEntry ( TString LegendEntry, Color_t ColorEntry );
59  /// Set entry, color, width, and style for each line.
60  inline void AddLegendEntry ( TString LegendEntry, Color_t ColorEntry, Int_t LineWidth, Int_t LineStyle );
61 
62  /// This function adds a tree pointer, cut, and expression used for generating a line in the plot
63  inline void AddLine ( TTree *tree, const char* cut, TString expr ) { AddLine(tree, TCut(cut), expr); }
64 
65  /// Set a tree and weight concurrently for each line. Best used when a default expression is set.
66  inline void AddTreeWeight ( TTree *tree, const char* cut ) { AddTreeWeight(tree, TCut(cut)); }
67  /// Set a weight and expression concurrently for each line. Best used when a default tree is set.
68  inline void AddWeightExpr ( const char* cut, TString expr ) { AddWeightExpr(TCut(cut), expr); }
69 
70  /// Sets the name of the canvas created by PlotBase.
71  inline void SetCanvasName ( TString name ) { fCanvasName = name; }
72  /// Sets the size of the output canvas.
73  inline void SetCanvasSize ( Int_t width, Int_t height ) { fCanvasWidth = width; fCanvasHeight = height; }
74  /// Sets the offset of the Y-axis title as a ratio of the default offset
75  inline void SetAxisTitleOffset ( Float_t offset ) { fTitleOffset = offset; }
76  /// Sets the fontsize of the axis labels
77  inline void SetFontSize ( Float_t fontSize ) { fFontSize = fontSize; }
78  /// Forces the minimum and maximum values of the Y-axis in the plot.
79  inline void SetAxisMinMax ( Float_t min, Float_t max ) { fAxisMin = min; fAxisMax = max; }
80 
81  /// Set the default tree pointer for each line in the plot
82  inline void SetDefaultTree ( TTree *tree ) { fDefaultTree = tree; }
83  /// Set the default weight for each line in the plot.
84  inline void SetDefaultWeight ( TCut cut ) { fDefaultCut = cut; }
85  inline void SetDefaultCut ( const char* cut ) { SetDefaultWeight(TCut(cut)); }
86  /// Set the default weight for each line in the plot.
87  inline void SetDefaultWeight ( const char* cut ) { SetDefaultWeight(TCut(cut)); }
88  /// Set the default expression to be plotted on the x-axis for each line in the plot
89  inline void SetDefaultExpr ( TString expr ) { fDefaultExpr = expr; }
90 
91  /// Get the default weight.
92  inline TCut GetDefaultWeight () const { return fDefaultCut; }
93 
94  /// Can store multiple trees at once for plots. Each tree plots its own line.
95  inline void SetTreeList ( std::vector<TTree*> treelist ) { fInTrees = treelist; }
96  /// Set a tree for a single line.
97  inline void AddTree ( TTree *tree ) { fInTrees.push_back(tree); }
98  /// Set a weight for a single line.
99  inline void AddWeight ( TCut cut ) { fInCuts.push_back(cut); }
100  /// Set a weight for a single line.
101  inline void AddWeight ( const char* cut ) { AddWeight(TCut(cut)); }
102  /// Set an x expression for a single line.
103  inline void AddExpr ( TString expr ) { fInExpr.push_back(expr); }
104 
105  /// Reset the list of trees used to makes lines
106  inline void ResetTree () { fInTrees.clear(); }
107  /// Reset the list of weights used to makes lines
108  inline void ResetWeight () { fInCuts.clear(); }
109  /// Reset the list of expressions used to makes lines
110  inline void ResetExpr () { fInExpr.clear(); }
111 
112  /// Set the default line width.
113  inline void SetDefaultLineWidth ( Int_t width ) { fDefaultLineWidth = width; }
114  /// Set the default line style.
115  inline void SetDefaultLineStyle ( Int_t style ) { fDefaultLineStyle = style; }
116  /// Set this to true to feature error bars in the plots.
117  inline void SetIncludeErrorBars ( Bool_t include ) { fIncludeErrorBars = include; }
118 
119  /// Used for vertical position of legend.
120  enum LegendY {
121  kUpper = 0, ///< Places the plot legend on the upper part of the canvas
122  kLower, ///< Places the plot legend on the lower part of the canvas
123  };
124  /// Used for horizontal position of legend.
125  enum LegendX {
126  kLeft = 0, ///< Places the plot legend on the left part of the canvas
127  kRight, ///< Places the plot legend on the right part of the canvas
128  };
129  /// Set the legend location using LegendY and LegendX enums.
130  inline void SetLegendLocation ( LegendY yLoc, LegendX xLoc, Double_t xWidth = 0.3, Double_t yWidth = 0.2 );
131  /// Set the legend location manually.
132  inline void SetLegendLimits ( Double_t lim1, Double_t lim2, Double_t lim3, Double_t lim4 )
133  { l1 = lim1; l2 = lim2; l3 = lim3; l4 = lim4; }
134 
135  /// Set the legend border size.
136  inline void SetLegendBorderSize ( Int_t size ) { fLegendBorderSize = size; }
137  /// If true, the legend will be filled with a solid background.
138  inline void SetLegendFill ( Bool_t fill ) { fLegendFill = fill; }
139 
140  /// Resets the legend entries for each line.
141  inline void ResetLegend () { fLegendEntries.clear(); fLineColors.clear();
142  fLineWidths.clear(); fLineStyles.clear(); }
143 
144  /// Set one of the lines to be plotted as data.
145  inline void SetDataIndex ( Int_t data ) { fDataIndex = data; }
146  /// If true, a ratio pad will be drawn underneath.
147  inline void SetMakeRatio ( Bool_t ratio ) { fMakeRatio = ratio; }
148  /// Set which line will be '1' in the ratio plot.
149  inline void SetRatioIndex ( Int_t ratio ) { fRatioIndex = ratio; }
150 
151  /**
152  Add a line to show in the ratio plot.
153  The line is specified by its index. If this list is empty, all of the lines appear in the ratio pad.
154  */
155  inline void AddRatioLine ( Int_t line ) { fRatioLines.push_back(line); }
156  /// Force the minimum and maximum values of the ratio pad.
157  inline void SetRatioMinMax ( Float_t min, Float_t max ) { fRatioMin = min; fRatioMax = max; }
158  /// Set the y axis label of the ratio pad.
159  inline void SetRatioTitle ( TString title ) { fRatioTitle = title; }
160  /// Set horizontal dotted lines on the ratio pad.
161  inline void SetRatioGrid ( Int_t grid ) { fRatioGrid = grid; }
162  /// Sets the divisions of the ratio y axis.
163  inline void SetRatioDivisions ( Int_t divisions, Bool_t optimize = true ) { fRatioDivisions = divisions;
164  fOptimDivisions = optimize; }
165  /// Force a line to draw first on the plot, if desired.
166  inline void SetDrawFirst ( Int_t first ) { fDrawFirst = first; }
167 
168  /// Call this before plotting to only write plots to .pdf files.
169  inline void OnlyPDF () { bPNG = false; bC = false; }
170  /// Call this before plotting to only write plots to .png files.
171  inline void OnlyPNG () { bPDF = false; bC = false; }
172 
173  /// Set the luminosity label.
174  inline void SetLumiLabel ( TString lumi ) { fLumiLabel = lumi; }
175  /// Set the luminosity format.
176  inline void SetLumiLabelFormat ( TString format ) { fLumiLabelFormat = format; }
177  /// Set the luminosity lable with a float in fb.
178  inline void SetLumiLabel ( Float_t lumi ) { fLumiLabel = TString::Format(fLumiLabelFormat, lumi); }
179  /// Set the type of CMS label for the plot
180  inline void SetCMSLabel ( TString type ) { fCMSLabel = type; }
181  /// Adds a dotted line in order to show cuts.
182  inline void AddCutLine ( Double_t loc, bool is_vert = true ) { fCutLines.push_back(std::make_pair(loc, is_vert)); }
183  /// Resets the number of cut lines to plot
184  inline void ResetCutLines () { fCutLines.resize(0); }
185  /// Sets the style for the cut lines.
186  inline void SetCutLineStyle ( Color_t color, Int_t width, Int_t style ) { fCutColor = color; fCutWidth = width;
187  fCutStyle = style; }
188  /// Add branches that contain independent systematic uncertainties to show in the plots
189  inline void AddSystematicBranch ( TString branch ) { fSystematicBranches.push_back(branch); }
190  /// Reset list of branches that contain systematics
191  inline void ResetSystematics () { fSystematicBranches.resize(0); }
192 
193  /// Set additional drawing options to force all lines to have
194  void SetDrawOpts ( TString options ) { fDrawOpts = options; }
195 
196  void SetLeftMargin ( float left ) { fLeftMargin = left; }
197 
198  protected:
199  /// Get a temporary name for a histogram
200  TString TempHistName () { TString tempName; tempName.Form("Hist_%d", fPlotCounter++); return tempName; }
201  UInt_t fPlotCounter = 0; ///< This is used so that making scratch plots does not overlap
202 
203  TTree* fDefaultTree = NULL; ///< Default Tree if needed
204  TCut fDefaultCut = ""; ///< Default cut if needed
205  TString fDefaultExpr = ""; ///< Default resolution expression if needed
206 
207  Double_t l1 = 0.6; ///< First X value of legend location
208  Double_t l2 = 0.7; ///< First Y value of legend location
209  Double_t l3 = 0.9; ///< Second X value of legend location
210  Double_t l4 = 0.9; ///< Second Y value of legend location
211  Int_t fLegendBorderSize = 0; ///< Border size of legend
212 
213  std::vector<TTree*> fInTrees; ///< Holds all the trees for each line if needed
214  std::vector<TCut> fInCuts; ///< Holds the cuts for the trees if needed
215  std::vector<TString> fInExpr; ///< Holds multiple resolution expressions if needed
216  std::vector<TString> fSystematicBranches; ///< Vector of branches to apply as systematic uncertainties
217 
218  Bool_t fIncludeErrorBars = true; ///< Option to include error bars
219 
220  /**
221  Minimum value of the y-axis.
222  If fAxisMin is the same value as fAxisMax,
223  then both values are ignored and the axis height
224  is determined by the first line plotted.
225  */
226  Float_t fAxisMin = 0.0;
227  Float_t fAxisMax = 0.0; ///< Maximum value of the y-axis.
228 
229  Int_t fDataIndex = -1; ///< Index in the plotter of the data line
230  Bool_t fMakeRatio = false; ///< Bool to make a ratio plot on bottom of image
231  Int_t fRatioIndex = -1; ///< Pick which line to set as 1 in ratio plot
232  Float_t fRatioMin = 0.0; ///< Minimum of the ratio pad
233  Float_t fRatioMax = 0.0; ///< Maximum of the ratio pad
234  TString fRatioTitle; ///< Label of the ratio pad
235  Int_t fRatioGrid;
238  std::vector<Int_t> fRatioLines; ///< Vector of line indices to show up in the ratio pad
239 
240  std::vector<TString> fLegendEntries; ///< Number of legend entries should match number of lines
241 
242  /// Takes number of bins, min and max, and dumps it into an already allocated array
243  inline void ConvertToArray ( Int_t NumXBins, Double_t MinX, Double_t MaxX, Double_t *XBins );
244 
245  /// This is the powerhouse of all the plotting tools. Everything happens here.
246  template<class T> void BaseCanvas ( TString FileBase, std::vector<T*> theLines, TString XLabel,
247  TString YLabel, Bool_t logY = false, Bool_t logX = false );
248 
249  Bool_t bPDF = true; ///< If true, BaseCanvas will create a .pdf file
250  Bool_t bPNG = true; ///< If true, BaseCanvas will create a .png file
251  Bool_t bC = true; ///< If true, BaseCanvas will create a .C macro
252 
253  private:
254  TString fCanvasName = "canvas"; ///< The name of the output canvas
255  Int_t fCanvasWidth = 600; ///< The width of the output canvas
256  Int_t fCanvasHeight = 600; ///< The height of the output canvas
257  Float_t fTitleOffset = 1.0; ///< The offset of the Y-axis title to account for large numbers
258  Float_t fFontSize = 0.04; ///< The size of the font used in the axis titles
259  Int_t fDefaultLineWidth = 2; ///< Line width to make all plots
260  Int_t fDefaultLineStyle = 1; ///< Line style to use on all plots
261 
262  std::vector<Color_t> fLineColors; ///< Colors of each of the lines
263  std::vector<Int_t> fLineWidths; ///< Widths of each of the lines
264  std::vector<Int_t> fLineStyles; ///< Styles of each of the lines
265 
266  Bool_t fLegendFill = false; ///< Gives fill option to legend drawing
267  Int_t fDrawFirst; ///< Can force one of the lines to be drawn first
268 
269  TString fLumiLabelFormat = "%.1f"; ///< Format used for changing lumi numbers into string
270  TString fLumiLabel = ""; ///< Label used to show luminosity
271  TString fCMSLabel = ""; ///< Label to give next to CMS on plots
272 
273  /// Use this to get certain draw options correct (for data, for example)
274  template<class T> void LineDrawing ( std::vector<T*> theLines, Int_t index, Bool_t same );
275  std::vector<TObject*> fDeleteThese; ///< Vector of object pointers to free memory at the end
276 
277  /// Options for lines
278  template<class T> TString GetOpts ( T* );
279 
280  std::vector<std::pair<Double_t, bool>> fCutLines; ///< Locations for dashed lines for cuts, and bools for verticality
281  Color_t fCutColor = kRed; ///< Color of the cuts lines
282  Int_t fCutWidth = 2; ///< Width of the cuts lines
283  Int_t fCutStyle = 2; ///< Style of the cuts lines
284  Double_t fCutYMin = 0.0; ///< Minimum value of cut line y
285  Double_t fCutYMax = 0.0; ///< Maximum value of cut line y
286  Double_t fCutXMin = 0.0; ///< Minimum value of cut line x
287  Double_t fCutXMax = 0.0; ///< Maximum value of cut line x
288 
289  TString fDrawOpts = ""; ///< The options that all lines are drawn with
290  float fLeftMargin = 0.0;
291 
292  /// Draws the cuts lines
293  void DrawCutLines ();
294 
295 };
296 
297 //--------------------------------------------------------------------
299  fRatioTitle("Ratio"),
300  fRatioGrid(0),
301  fRatioDivisions(504),
302  fOptimDivisions (true),
303  fDrawFirst(-1)
304 { }
305 
306 //--------------------------------------------------------------------
308 { }
309 
310 //--------------------------------------------------------------------
311 void PlotBase::AddLine(TTree *tree, TCut cut, TString expr)
312 {
313  // Check for defaults. If none, set the values for each line.
314  if (fDefaultTree != NULL) {
315  Message(eError, "Default tree already set! Check configuration...");
316  exit(1);
317  }
318  if (fDefaultCut != "") {
319  Message(eError, "Default cut already set! Check configuration...");
320  exit(1);
321  }
322  if (fDefaultExpr != "") {
323  Message(eError, "Default resolution expression already set! Check configuration...");
324  exit(1);
325  }
326  fInTrees.push_back(tree);
327  fInCuts.push_back(cut);
328  fInExpr.push_back(expr);
329 }
330 
331 //--------------------------------------------------------------------
332 void PlotBase::AddTreeWeight(TTree *tree, TCut cut)
333 {
334  // Check for defaults. If none, set the values for each line.
335  if (fDefaultTree != NULL) {
336  Message(eError, "Default tree already set! Check configuration...");
337  exit(1);
338  }
339  if (fDefaultCut != "") {
340  Message(eError, "Default cut already set! Check configuration...");
341  exit(1);
342  }
343  if (fDefaultExpr == "") {
344  Message(eError, "Please set default resolution expression first!");
345  exit(1);
346  }
347  fInTrees.push_back(tree);
348  fInCuts.push_back(cut);
349 }
350 
351 //--------------------------------------------------------------------
352 void PlotBase::AddTreeExpr(TTree *tree, TString expr)
353 {
354  // Check for defaults. If none, set the values for each line.
355  if (fDefaultTree != NULL) {
356  Message(eError, "Default tree already set! Check configuration...");
357  exit(1);
358  }
359  if (fDefaultCut == "") {
360  Message(eError, "Please set default cut first!");
361  exit(1);
362  }
363  if (fDefaultExpr != "") {
364  Message(eError, "Default resolution expression already set! Check configuration...");
365  exit(1);
366  }
367  fInTrees.push_back(tree);
368  fInExpr.push_back(expr);
369 }
370 
371 //--------------------------------------------------------------------
372 void PlotBase::AddWeightExpr(TCut cut, TString expr)
373 {
374  // Check for defaults. If none, set the values for each line.
375  if (fDefaultTree == NULL) {
376  Message(eError, "Please set default tree first!");
377  exit(1);
378  }
379  if (fDefaultCut != "") {
380  Message(eError, "Default cut already set! Check configuration...");
381  exit(1);
382  }
383  if (fDefaultExpr != "") {
384  Message(eError, "Default resolution expression already set! Check configuration...");
385  exit(1);
386  }
387  fInCuts.push_back(cut);
388  fInExpr.push_back(expr);
389 }
390 
391 //--------------------------------------------------------------------
392 
393 /**
394  This function is designed to be lazy about putting legends
395  There are nice enums, like kUpper, kLower and kLeft, kRight
396  The width and height are then fractions of the canvas
397 */
398 
399 void PlotBase::SetLegendLocation(LegendY yLoc, LegendX xLoc, Double_t xWidth, Double_t yWidth)
400 {
401  if (xLoc == kLeft) {
402  l1 = 0.15;
403  l3 = 0.15 + xWidth;
404  }
405  else {
406  l3 = 0.9;
407  l1 = 0.9 - xWidth;
408  }
409 
410  if (yLoc == kUpper) {
411  l4 = 0.9;
412  l2 = 0.9 - yWidth;
413  }
414  else {
415  l2 = 0.15;
416  l4 = 0.15 + yWidth;
417  }
418 }
419 
420 //--------------------------------------------------------------------
421 void PlotBase::AddLegendEntry(TString LegendEntry, Color_t ColorEntry )
422 {
423  fLegendEntries.push_back(LegendEntry);
424  fLineColors.push_back(ColorEntry);
425  fLineWidths.push_back(fDefaultLineWidth);
426  fLineStyles.push_back(fDefaultLineStyle);
427 }
428 
429 //--------------------------------------------------------------------
430 void
431 PlotBase::AddLegendEntry(TString LegendEntry, Color_t ColorEntry, Int_t LineWidth, Int_t LineStyle)
432 {
433  fLegendEntries.push_back(LegendEntry);
434  fLineColors.push_back(ColorEntry);
435  fLineWidths.push_back(LineWidth);
436  fLineStyles.push_back(LineStyle);
437 }
438 
439 //--------------------------------------------------------------------
440 void
441 PlotBase::ConvertToArray(Int_t NumXBins, Double_t MinX, Double_t MaxX, Double_t *XBins)
442 {
443  Double_t binWidth = (MaxX - MinX)/NumXBins;
444  for (Int_t i0 = 0; i0 < NumXBins + 1; i0++)
445  XBins[i0] = MinX + i0 * binWidth;
446 }
447 
448 //--------------------------------------------------------------------
449 void
451  // Draw the cuts lines
452  for (UInt_t iCut = 0; iCut != fCutLines.size(); ++iCut) {
453  Message(eInfo, "Drawing a cut line at %f.", fCutLines[iCut].first);
454 
455  TLine *aCutLine;
456 
457  if (fCutLines[iCut].second)
458  aCutLine = new TLine(fCutLines[iCut].first, fCutYMin, fCutLines[iCut].first, fCutYMax);
459  else
460  aCutLine = new TLine(fCutXMin, fCutLines[iCut].first, fCutXMax, fCutLines[iCut].first);
461 
462  aCutLine->SetLineColor(fCutColor);
463  aCutLine->SetLineWidth(fCutWidth);
464  aCutLine->SetLineStyle(fCutStyle);
465  fDeleteThese.push_back(aCutLine);
466  aCutLine->Draw("same");
467  }
468 }
469 
470 //--------------------------------------------------------------------
471 
472 /**
473  The options for anything derived from a TH1 is "hist".
474  The options for anything derived from a TGraphErrors is "3".
475 */
476 
477 template<class T>
478 TString PlotBase::GetOpts(T*)
479 {
480  Message(eDebug, "All options come with: %s", fDrawOpts.Data());
481 
482  if (fDrawOpts != "")
483  return fDrawOpts;
484 
485  if (std::is_base_of<TH1, T>::value)
486  return fDrawOpts + "hist";
487  else if (std::is_base_of<TGraph, T>::value)
488  return fDrawOpts + "l3";
489  else
490  return fDrawOpts + "";
491 }
492 
493 //--------------------------------------------------------------------
494 
495 /**
496  This is used instead of Draw for lines so that the draw options are set in one place
497 */
498 
499 template<class T>
500 void PlotBase::LineDrawing(std::vector<T*> theLines, Int_t index, Bool_t same)
501 {
502  DisplayFunc(__func__);
503  Message(eDebug, "There are %i lines ... Currently drawing %i",
504  theLines.size(), index);
505  Message(eDebug, "Drawing with same set: %s", same ? "true" : "false");
506 
507  if (!same) {
508  fCutYMin = theLines[index]->GetMinimum();
509  fCutYMax = theLines[index]->GetMaximum();
510  fCutXMin = theLines[index]->GetXaxis()->GetXmin();
511  fCutXMax = theLines[index]->GetXaxis()->GetXmax();
512  }
513 
514  TString options = GetOpts(theLines[index]);
515 
516  Message(eDebug, "Plotting: %i, Data Index: %i, Options: %s",
517  index, fDataIndex, options.Data());
518  Message(eDebug, "Line color: %i", theLines[index]->GetLineColor());
519  Message(eDebug, "Fill color: %i", theLines[index]->GetFillColor());
520 
521  if (index == fDataIndex)
522  options = "PE";
523  if (options != "")
524  options += ",";
525  if (!std::is_base_of<TGraph, T>::value)
526  options += "same";
527 
528  if (fRatioIndex != -1 && index != fDataIndex) {
529  T* tempLine = reinterpret_cast<T*>(theLines[fRatioIndex]->Clone());
530 
531  Message(eDebug, "Created templine for error bars at %p from line at %p",
532  tempLine, theLines[fRatioIndex]);
533 
534  tempLine->SetFillColor(kGray);
535  tempLine->SetFillStyle(3001);
536 
537  if (!same && index == fRatioIndex) {
538  tempLine->Draw("e2");
539  Message(eDebug, "Drew error bars");
540  }
541 
542  theLines[index]->Draw(options);
543  tempLine->Draw("e2,same");
544  fDeleteThese.push_back(tempLine);
545  }
546 
547  else {
548  Message(eDebug, "Not drawing error separately.");
549  Message(eDebug, "Full options: %s", options.Data());
550  theLines[index]->Draw(options);
551  }
552 }
553 
554 //--------------------------------------------------------------------
555 
556 /**
557  Main macro of the plotters.
558 */
559 
560 template<class T>
561 void PlotBase::BaseCanvas(TString FileBase, std::vector<T*> theLines,
562  TString XLabel, TString YLabel, Bool_t logY, Bool_t logX)
563 {
564  DisplayFunc(__func__);
565  Message(eInfo, "File Name : %s", FileBase.Data());
566  Message(eInfo, "Number of Lines : %i", theLines.size());
567  Message(eInfo, "X Axis Label : %s", XLabel.Data());
568  Message(eInfo, "Y Axis Label : %s", YLabel.Data());
569 
570  gStyle->SetOptStat(0);
571 
572  // Font size and size of ratio plots are set here
573  // Can make this configurable, but don't think I need to
574  Float_t ratioFrac = 0.7;
575 
576  UInt_t NumPlots = theLines.size();
577  // Initialize the canvas and legend
578  TCanvas *theCanvas = new TCanvas(fCanvasName, fCanvasName, fCanvasWidth, fCanvasHeight);
579  SetupCanvas(this, theLines, theCanvas, fAxisMin, fAxisMax, XLabel, YLabel);
580  theCanvas->SetTitle(";" + XLabel + ";" + YLabel);
581  TLegend *theLegend = new TLegend(l1, l2, l3, l4);
582  theLegend->SetBorderSize(fLegendBorderSize);
583  theLegend->SetFillStyle(0);
584 
585  // We will check for the largest line to plot first
586  float maxValue = 0;
587  UInt_t plotFirst = 0;
588 
589  // Check that legend entries were added correctly
590  // No legend is needed if there is only a single line
591  if (theLines.size() != 1 && theLines.size() != fLegendEntries.size()) {
592 
593  Message(eError, "Number of lines and number of legend entries do not match!");
594  exit(1007);
595 
596  }
597 
598  Message(eDebug, "About to draw lines.");
599 
600  // Loop through the lines
601  for (UInt_t iLine = 0; iLine != NumPlots; ++iLine) {
602 
603  // Set title of lines and format
604  theLines[iLine]->SetTitle(";"+XLabel+";"+YLabel);
605  theLines[iLine]->GetYaxis()->SetTitleOffset(fTitleOffset);
606 
607  // If there's an axis requirement, set that here
608  if (fAxisMin != fAxisMax) {
609 
610  theLines[iLine]->SetMinimum(fAxisMin);
611  theLines[iLine]->SetMaximum(fAxisMax);
612 
613  }
614 
615  if (static_cast<int>(iLine) != fDataIndex) {
616 
617  if (theLines.size() == 1 && fLineColors.size() == 0) {
618 
619  theLines[iLine]->SetLineWidth(fDefaultLineWidth);
620  theLines[iLine]->SetLineStyle(fDefaultLineStyle);
621 
622  }
623  else {
624 
625  theLines[iLine]->SetLineWidth(fLineWidths[iLine]);
626  theLines[iLine]->SetLineStyle(fLineStyles[iLine]);
627  theLines[iLine]->SetLineColor(fLineColors[iLine]);
628  if (std::is_base_of<TGraph, T>::value)
629  theLines[iLine]->SetFillColor(fLineColors[iLine]);
630 
631  }
632 
633  }
634  else
635  theLines[iLine]->SetMarkerStyle(8);
636 
637  if (theLines.size() != 1) {
638 
639  // Add a formated legend entry
640  if (fLegendFill && static_cast<int>(iLine) < fDataIndex)
641  theLegend->AddEntry(theLines[iLine], fLegendEntries[iLine], "f");
642  else
643  theLegend->AddEntry(theLines[iLine], fLegendEntries[iLine], "lp");
644 
645  }
646 
647  // If the first draw is not set by user, check if maximum to draw first
648  if (fDrawFirst == -1) {
649  Double_t checkMax = theLines[iLine]->GetMaximum();
650 
651  if (checkMax > maxValue) {
652  maxValue = checkMax;
653  plotFirst = iLine;
654  }
655  }
656  }
657 
658  // If there will be a ratio plot, the make an upper pad
659  if (fMakeRatio) {
660 
661  TPad *pad1 = new TPad("pad1", "pad1", 0, 1.0 - ratioFrac, 1, 1.0);
662  if (fLeftMargin)
663  pad1->SetLeftMargin(fLeftMargin);
664 
665  pad1->SetBottomMargin(0.025);
666  pad1->Draw();
667  pad1->cd();
668 
669  // Change the size of the font accordingly
670  for (UInt_t iLine = 0; iLine != NumPlots; ++iLine) {
671 
672  theLines[iLine]->GetYaxis()->SetTitleSize(fFontSize/ratioFrac);
673  theLines[iLine]->GetYaxis()->SetLabelSize(fFontSize/ratioFrac);
674  theLines[iLine]->GetYaxis()->SetTitleOffset(fTitleOffset);
675  theLines[iLine]->GetXaxis()->SetTitleSize(0);
676  theLines[iLine]->GetXaxis()->SetLabelSize(0);
677 
678  }
679 
680  if (logX)
681  pad1->SetLogx();
682 
683  // Assume that log Y is only in the case of the top plot of ratio
684  if (logY)
685  pad1->SetLogy();
686 
687  }
688 
689  // If the first draw was not specified by the user, use the maximum found before
690 
691  Message(eDebug, "Variable fDrawFirst: %i, plotFirst: %i", fDrawFirst, plotFirst);
692 
693  Message(eDebug, "About to draw first line.");
694 
695  if (fDrawFirst == -1)
696  LineDrawing(theLines, plotFirst, false);
697  else
698  LineDrawing(theLines, fDrawFirst, false);
699 
700  // Then loop through all the other lines to draw
701  Message(eDebug, "About to loop through lines.");
702  for (UInt_t iLine = 0; iLine != NumPlots; ++iLine)
703  LineDrawing(theLines, iLine, true);
704 
705  // Draw the data again at the end to ensure it's on top
706  if (fDataIndex != -1) {
707  Message(eDebug, "Redrawing data.");
708  LineDrawing(theLines, fDataIndex, true);
709  }
710 
711  if (theLines.size() != 1) {
712  Message(eDebug, "Drawing legend.");
713  theLegend->Draw();
714  }
715 
716  gPad->RedrawAxis();
717  DrawCutLines();
718 
719  // If not a ratio plot, set the canvas to log
720  if (!fMakeRatio) {
721 
722  if (logX)
723  theCanvas->SetLogx();
724  if (logY)
725  theCanvas->SetLogy();
726 
727  } else { // Otherwise, go on the make the second pad and ratio plots
728 
729  Message(eDebug, "Making ratio pad.");
730 
731  theCanvas->cd();
732  TPad *pad2 = new TPad("pad2", "pad2", 0, 0, 1, 1 - ratioFrac);
733  if (fLeftMargin)
734  pad2->SetLeftMargin(fLeftMargin);
735 
736  pad2->SetTopMargin(0.05);
737  pad2->SetBottomMargin(0.4);
738 
739  if (fRatioGrid > 0)
740  pad2->SetGridy(fRatioGrid);
741 
742  pad2->Draw();
743  pad2->cd();
744 
745  // We take the line equal to '1' and copy it
746  T *ratioLine = reinterpret_cast<T*>(theLines[fRatioIndex]->Clone("ValueHolder"));
747  Message(eDebug, "Created ratio line at %p from ration index %i at %p",
748  ratioLine, fRatioIndex, theLines[fRatioIndex]);
749  SetZeroError(ratioLine);
750 
751  // Then we make a set of lines that are divided by the ratio line
752  std::vector<T*> newLines = GetRatioToLine(theLines, ratioLine);
753 
754  Message(eDebug, "Ratio lines created with size %i compared to %i",
755  newLines.size(), theLines.size());
756 
757  // Now we do formatting for all of the lines
758  for (UInt_t iLine = 0; iLine != NumPlots; ++iLine) {
759 
760  newLines[iLine]->GetXaxis()->SetTitleSize(fFontSize/(1 - ratioFrac));
761  newLines[iLine]->GetYaxis()->SetTitleSize(fFontSize/(1 - ratioFrac));
762  newLines[iLine]->GetXaxis()->SetLabelSize(fFontSize/(1 - ratioFrac));
763  newLines[iLine]->GetYaxis()->SetLabelSize(fFontSize/(1 - ratioFrac));
764  newLines[iLine]->GetYaxis()->SetTitleOffset((1 - ratioFrac)/ratioFrac * fTitleOffset);
765  newLines[iLine]->GetYaxis()->SetNdivisions(fRatioDivisions, fOptimDivisions);
766  newLines[iLine]->GetYaxis()->SetTitle(fRatioTitle);
767  newLines[iLine]->GetYaxis()->CenterTitle();
768 
769  if (fRatioMin != fRatioMax) {
770 
771  newLines[iLine]->SetMinimum(fRatioMin);
772  newLines[iLine]->SetMaximum(fRatioMax);
773 
774  }
775 
776  newLines[iLine]->SetFillColor(0);
777 
778  }
779 
780  // If we only want some lines (like top of stack and data) just draw those
781  // I know I looped over all the lines, but the performance hit is negligible and it makes for less buggy code
782  if (fRatioLines.size() != 0) {
783 
784  // Make the ratio line much less distinguished
785  newLines[fRatioIndex]->SetLineColor(1);
786  Message(eDebug, "Creating ratio line first.");
787  LineDrawing(newLines, fRatioIndex, false);
788 
789  for (UInt_t iLine = 0; iLine != fRatioLines.size(); ++iLine) {
790  Message(eDebug, "Drawing line %i of %i for ratio lines.", fRatioLines[iLine], newLines.size());
791  LineDrawing(newLines, fRatioLines[iLine], true);
792  }
793 
794  }
795  // Otherwise draw everything
796  else {
797 
798  LineDrawing(newLines, plotFirst, false);
799 
800  for (UInt_t iLine = 0; iLine < NumPlots; iLine++)
801  LineDrawing(newLines, iLine, true);
802 
803  }
804 
805  // There is no log Y on the ratio plot
806  if (logX)
807  pad2->SetLogx();
808 
809  gPad->RedrawAxis();
810  DrawCutLines();
811 
812  }
813 
814  theCanvas->cd();
815 
816  if (fLumiLabel != "") {
817 
818  TLatex* latex2 = new TLatex();
819  latex2->SetNDC();
820  latex2->SetTextSize(0.035);
821  latex2->SetTextAlign(31);
822  latex2->DrawLatex(0.90, 0.96, fLumiLabel + " fb^{-1} (13 TeV)");
823  fDeleteThese.push_back(latex2);
824 
825  }
826 
827  if (fCMSLabel != "") {
828 
829  TLatex* latex3 = new TLatex();
830  latex3->SetNDC();
831  latex3->SetTextSize(0.035);
832  latex3->SetTextFont(62);
833  latex3->SetTextAlign(11);
834  latex3->DrawLatex(0.19, 0.96, "CMS");
835  latex3->SetTextSize(0.030);
836  latex3->SetTextFont(52);
837  latex3->SetTextAlign(11);
838 
839  latex3->DrawLatex(0.27, 0.96, fCMSLabel);
840 
841  fDeleteThese.push_back(latex3);
842 
843  }
844 
845  // Now save the picture we just finished making
846  if (bC)
847  theCanvas->SaveAs(FileBase+".C");
848  if (bPNG)
849  theCanvas->SaveAs(FileBase+".png");
850  if (bPDF)
851  theCanvas->SaveAs(FileBase+".pdf");
852 
853  // Cleanup
854  delete theLegend;
855  delete theCanvas;
856 
857  for (UInt_t iDelete = 0; iDelete != fDeleteThese.size(); ++iDelete)
858  delete fDeleteThese[iDelete];
859 
860  fDeleteThese.clear();
861 
862 }
863 
864 #endif