Browse Source

Modifies how images are displayed in Notebooks.

  - Adds additional Lepton branches into analysis
  - Fixes FindROOT.cmake to properly rebuild dictionary only when needed
  - Changes canvas in HistCollection to a shared global
Caleb Fangmeier 7 years ago
parent
commit
8c123f116a

+ 35 - 32
analysis/TTTT_Analysis.cpp

@@ -57,8 +57,12 @@ void enable_branches(MiniTreeDataSet& mt){
     mt.track_branch_vec<float>("nLepGood", "LepGood_eta");
     mt.track_branch_vec<float>("nLepGood", "LepGood_phi");
     mt.track_branch_vec<float>("nLepGood", "LepGood_mass");
-    mt.track_branch_vec<float>("nLepGood", "LepGood_mcPt");
-    mt.track_branch_vec<int>("nLepGood", "LepGood_charge");
+    mt.track_branch_vec< int >("nLepGood", "LepGood_charge");
+    mt.track_branch_vec< int >("nLepGood", "LepGood_mcMatchId");
+    mt.track_branch_vec< int >("nLepGood", "LepGood_mcMatchPdgId");
+    mt.track_branch_vec< int >("nLepGood", "LepGood_mcMatchAny");
+    mt.track_branch_vec< int >("nLepGood", "LepGood_mcMatchTau");
+    mt.track_branch_vec< int >("nLepGood", "LepGood_mcPt");
 
     mt.track_branch<int>("nJet");
     mt.track_branch_vec<float>("nJet", "Jet_pt");
@@ -69,30 +73,17 @@ void enable_branches(MiniTreeDataSet& mt){
 
     mt.track_branch<int>("nGenTop");
     mt.track_branch_vec<int>("nGenTop", "GenTop_pdgId");
+    mt.track_branch_vec<float>("nGenTop", "GenTop_pt");
 
     mt.track_branch<int>("nGenPart");
     mt.track_branch_vec<int>("nGenPart", "GenPart_pdgId");
     mt.track_branch_vec<int>("nGenPart", "GenPart_motherIndex");
+    mt.track_branch_vec<int>("nGenPart", "GenPart_motherId");
     mt.track_branch_vec<float>("nGenPart", "GenPart_pt");
     mt.track_branch_vec<float>("nGenPart", "GenPart_eta");
     mt.track_branch_vec<float>("nGenPart", "GenPart_phi");
     mt.track_branch_vec<float>("nGenPart", "GenPart_mass");
 
-/*
-    GenPart_motherId                                                              : Int_t pdgId of the mother of the particle for Hard scattering particles, with ancestry and links
-    GenPart_grandmotherId                                                         : Int_t pdgId of the grandmother of the particle for Hard scattering particles, with ancestry and links
-    GenPart_sourceId                                                              : Int_t origin of the particle (heaviest ancestor) : 6=t, 25=h, 23/24=W/Z for Hard scattering particles, with ancestry and links
-    GenPart_charge                                                                : Float_t charge for Hard scattering particles, with ancestry and links
-    GenPart_status                                                                : Int_t status for Hard scattering particles, with ancestry and links
-    GenPart_isPromptHard                                                          : Int_t isPromptHard for Hard scattering particles, with ancestry and links
-    GenPart_pdgId                                                                 : Int_t pdgId for Hard scattering particles, with ancestry and links
-    GenPart_pt                                                                    : Float_t pt for Hard scattering particles, with ancestry and links
-    GenPart_eta                                                                   : Float_t eta for Hard scattering particles, with ancestry and links
-    GenPart_phi                                                                   : Float_t phi for Hard scattering particles, with ancestry and links
-    GenPart_mass                                                                  : Float_t mass for Hard scattering particles, with ancestry and links
-    GenPart_motherIndex                                                           : Int_t index of the mother in the generatorSummary for Hard scattering particles, with ancestry and links
-*/
-
     mt.track_branch<int>("nBJetLoose40");
     mt.track_branch<int>("nBJetMedium40");
     mt.track_branch<int>("nBJetTight40");
@@ -113,7 +104,13 @@ void declare_values(MiniTreeDataSet& mt){
         FUNC(([](int a, int b){
             return a + b;
         })));
-    apply(add,fv::tuple<int,int>(lookup<int>("nBJetLoose40"), lookup<int>("nBJetMedium40")), "looseplusmedium");
+    auto& sub = GenFunction::register_function<int(int,int)>("sub",
+        FUNC(([](int a, int b){
+            return a - b;
+        })));
+    auto loose_medium = fv::tuple<int,int>(lookup<int>("nBJetLoose40"), lookup<int>("nBJetMedium40"));
+    apply(add,loose_medium, "looseplusmedium");
+    apply(sub,loose_medium, "looseminusmedium");
 
     energies(lorentz_vectors("LepGood_pt", "LepGood_eta", "LepGood_phi", "LepGood_mass", "LepGood_4v"), "LepGood_energy");
     energies(lorentz_vectors("GenPart_pt", "GenPart_eta", "GenPart_phi", "GenPart_mass", "GenPart_4v"), "GenPart_energy");
@@ -146,6 +143,7 @@ void declare_containers(MiniTreeDataSet& mt){
     mt.register_container(new ContainerTH1<int>("loose", "Loose", lookup<int>("nBJetLoose40"), 10, 0, 10));
     mt.register_container(new ContainerTH1<int>("medium", "Medium", lookup<int>("nBJetMedium40"), 10, 0, 10));
     mt.register_container(new ContainerTH1<int>("looseplusmedium", "Loose + Medium", lookup<int>("looseplusmedium"), 10, 0, 10));
+    mt.register_container(new ContainerTH1<int>("looseminusmedium", "Loose - Medium", lookup<int>("looseminusmedium"), 10, -5, 5));
 
     mt.register_container(new ContainerTH1<int>("lepton_count", "Lepton Multiplicity", lookup<int>("nLepGood"), 8, 0, 8));
     mt.register_container(new ContainerTH1<int>("top_quark_count", "Top Quark Multiplicity", lookup<int>("nGenTop"), 8, 0, 8));
@@ -174,26 +172,31 @@ void declare_containers(MiniTreeDataSet& mt){
     mt.register_container(new ContainerTH1<int>("b_jet_count", "B-Jet Multiplicity", lookup<int>("b_jet_count"), 10, 0, 10));
 
 
-    mt.register_container(new ContainerTH1<int>("jet_count_os_dilepton", "Jet Multiplicity - OS Dilepton Events",
-                                                lookup<int>("nJet"), 14, 0, 14));
+    mt.register_container(new ContainerTH1<int>("jet_count_os_dilepton", "Jet Multiplicity - OS Dilepton Events", lookup<int>("nJet"), 14, 0, 14));
     mt.get_container("jet_count_os_dilepton")->add_filter(lookup_filter("os-dilepton"));
-    mt.register_container(new ContainerTH1<int>("jet_count_ss_dilepton", "Jet Multiplicity - SS Dilepton Events",
-                lookup<int>("nJet"), 14, 0, 14));
+
+    mt.register_container(new ContainerTH1<int>("jet_count_ss_dilepton", "Jet Multiplicity - SS Dilepton Events", lookup<int>("nJet"), 14, 0, 14));
     mt.get_container("jet_count_ss_dilepton")->add_filter(lookup_filter("ss-dilepton"));
-    mt.register_container(new ContainerTH1<int>("jet_count_trilepton", "Jet Multiplicity - Trilepton Events",
-                lookup<int>("nJet"), 14, 0, 14));
+
+    mt.register_container(new ContainerTH1<int>("jet_count_trilepton", "Jet Multiplicity - Trilepton Events", lookup<int>("nJet"), 14, 0, 14));
     mt.get_container("jet_count_trilepton")->add_filter(lookup_filter("trilepton"));
 
-    mt.register_container(new ContainerTH1<int>("primary_vert_count", "Number of Primary Vertices",
-                lookup<int>("nVert"), 50, 0, 50));
+    mt.register_container(new ContainerTH1<int>("primary_vert_count", "Number of Primary Vertices", lookup<int>("nVert"), 50, 0, 50));
+
+    mt.register_container(new CounterMany<int>("GenTop_pdgId_counter", lookup<vector<int>>("GenTop_pdgId")));
+    mt.register_container(new CounterMany<int>("GenPart_pdgId_counter", lookup<vector<int>>("GenPart_pdgId")));
+
+    mt.register_container(new Vector<vector< int >>("GenTop_pdgId", lookup<vector< int >>("GenTop_pdgId")));
+    mt.register_container(new Vector<vector<float>>("GenTop_pt",    lookup<vector<float>>("GenTop_pt")));
 
-    mt.register_container(new CounterMany<int>("GenTop_pdg_id", lookup<vector<int>>("GenTop_pdgId")));
-    mt.register_container(new CounterMany<int>("GenPart_pdg_id", lookup<vector<int>>("GenPart_pdgId")));
+    mt.register_container(new Vector<vector< int >>("GenPart_pdgId",          lookup<vector< int >>("GenPart_pdgId")));
+    mt.register_container(new Vector<vector< int >>("GenPart_motherIndex",    lookup<vector< int >>("GenPart_motherIndex")));
+    mt.register_container(new Vector<vector< int >>("GenPart_motherId",       lookup<vector< int >>("GenPart_motherId")));
+    mt.register_container(new Vector<vector<float>>("GenPart_pt",             lookup<vector<float>>("GenPart_pt")));
+    mt.register_container(new Vector<vector<float>>("GenPart_energy",         lookup<vector<float>>("GenPart_energy")));
 
-    mt.register_container(new Vector<vector<int>>("GenPart_pdgId", lookup<vector<int>>("GenPart_pdgId")));
-    mt.register_container(new Vector<vector<int>>("GenPart_motherIndex", lookup<vector<int>>("GenPart_motherIndex")));
-    mt.register_container(new Vector<vector<float>>("GenPart_pt", lookup<vector<float>>("GenPart_pt")));
-    mt.register_container(new Vector<vector<float>>("GenPart_energy", lookup<vector<float>>("GenPart_energy")));
+    mt.register_container(new Vector<vector< int >>("LepGood_mcMatchId",      lookup<vector< int >>("LepGood_mcMatchId")));
+    mt.register_container(new Vector<vector< int >>("LepGood_mcMatchPdgId",   lookup<vector< int >>("LepGood_mcMatchPdgId")));
 }
 
 

+ 2 - 68
cmake/FindROOT.cmake

@@ -170,61 +170,6 @@ ELSE(WIN32)
   ENDIF (ROOT_FOUND)
 ENDIF(WIN32)
 
-
-
-  ###########################################
-  #
-  #       Macros for building ROOT dictionary
-  #
-  ###########################################
-
-MACRO (ROOT_GENERATE_DICTIONARY_OLD )
- 
-   set(INFILES "")    
-
-   foreach (_current_FILE ${ARGN})
-
-     IF (${_current_FILE} MATCHES "^.*\\.h$")
-       IF (${_current_FILE} MATCHES "^.*Link.*$")
-         set(LINKDEF_FILE ${_current_FILE})
-       ELSE (${_current_FILE} MATCHES "^.*Link.*$")
-         set(INFILES ${INFILES} ${_current_FILE})
-       ENDIF (${_current_FILE} MATCHES "^.*Link.*$")
-     ELSEIF (${_current_FILE} MATCHES "^.*\\.hh$")
-       IF (${_current_FILE} MATCHES "^.*Link.*$")
-         set(LINKDEF_FILE ${_current_FILE})
-       ELSE (${_current_FILE} MATCHES "^.*Link.*$")
-         set(INFILES ${INFILES} ${_current_FILE})
-       ENDIF (${_current_FILE} MATCHES "^.*Link.*$")
-     ELSE (${_current_FILE} MATCHES "^.*\\.h$")
-       IF (${_current_FILE} MATCHES "^.*\\.cxx$")
-         set(OUTFILE ${_current_FILE})
-       ELSE (${_current_FILE} MATCHES "^.*\\.cxx$")
-         set(INCLUDE_DIRS ${INCLUDE_DIRS} -I${_current_FILE})   
-       ENDIF (${_current_FILE} MATCHES "^.*\\.cxx$")
-     ENDIF (${_current_FILE} MATCHES "^.*\\.h$")
-     
-   endforeach (_current_FILE ${ARGN})
-   
-#  MESSAGE("INFILES: ${INFILES}")
-#  MESSAGE("OutFILE: ${OUTFILE}")
-#  MESSAGE("LINKDEF_FILE: ${LINKDEF_FILE}")
-#  MESSAGE("INCLUDE_DIRS: ${INCLUDE_DIRS}")
-
-   STRING(REGEX REPLACE "(^.*).cxx" "\\1.h" bla "${OUTFILE}")
-#   MESSAGE("BLA: ${bla}")
-   SET (OUTFILES ${OUTFILE} ${bla})
-
-   ADD_CUSTOM_COMMAND(OUTPUT ${OUTFILES}
-      COMMAND ${ROOT_CINT_EXECUTABLE}
-      ARGS -f ${OUTFILE} -c -p -DHAVE_CONFIG_H ${INCLUDE_DIRS} ${INFILES} ${LINKDEF_FILE} 
-      DEPENDS ${INFILES}
-      )
-
-#   MESSAGE("ROOT_CINT_EXECUTABLE has created the dictionary ${OUTFILE}")
-
-ENDMACRO (ROOT_GENERATE_DICTIONARY_OLD)
-
   ###########################################
   #
   #       Macros for building ROOT dictionary
@@ -238,25 +183,14 @@ MACRO (ROOT_GENERATE_DICTIONARY INFILES LINKDEF_FILE OUTFILE INCLUDE_DIRS_IN)
   foreach (_current_FILE ${INCLUDE_DIRS_IN})
     set(INCLUDE_DIRS ${INCLUDE_DIRS} -I${_current_FILE})   
   endforeach (_current_FILE ${INCLUDE_DIRS_IN})
- 
-
-#  MESSAGE("INFILES: ${INFILES}")
-#  MESSAGE("OutFILE: ${OUTFILE}")
-#  MESSAGE("LINKDEF_FILE: ${LINKDEF_FILE}")
-#  MESSAGE("INCLUDE_DIRS: ${INCLUDE_DIRS}")
-
-  STRING(REGEX REPLACE "^(.*)\\.(.*)$" "\\1.h" bla "${OUTFILE}")
-#  MESSAGE("BLA: ${bla}")
-  SET (OUTFILES ${OUTFILE} ${bla})
-
 
   if (CMAKE_SYSTEM_NAME MATCHES Linux)
-    ADD_CUSTOM_COMMAND(OUTPUT ${OUTFILES}
+    ADD_CUSTOM_COMMAND(OUTPUT ${OUTFILE}
        COMMAND LD_LIBRARY_PATH=${ROOT_LIBRARY_DIR} ROOTSYS=${ROOTSYS} ${ROOT_CINT_EXECUTABLE}
        ARGS -f ${OUTFILE} -c -DHAVE_CONFIG_H ${INCLUDE_DIRS} ${INFILES} ${LINKDEF_FILE} DEPENDS ${INFILES} ${LINKDEF_FILE})
   else (CMAKE_SYSTEM_NAME MATCHES Linux)
     if (CMAKE_SYSTEM_NAME MATCHES Darwin)
-      ADD_CUSTOM_COMMAND(OUTPUT ${OUTFILES}
+      ADD_CUSTOM_COMMAND(OUTPUT ${OUTFILE}
        COMMAND DYLD_LIBRARY_PATH=${ROOT_LIBRARY_DIR} ROOTSYS=${ROOTSYS} ${ROOT_CINT_EXECUTABLE}
        ARGS -f ${OUTFILE} -c -DHAVE_CONFIG_H ${INCLUDE_DIRS} ${INFILES} ${LINKDEF_FILE} DEPENDS ${INFILES} ${LINKDEF_FILE})
     endif (CMAKE_SYSTEM_NAME MATCHES Darwin)

File diff suppressed because it is too large
+ 1 - 1
docs/LinkDef_8hpp_source.html


File diff suppressed because it is too large
+ 1884 - 5738
docs/TTTT_Analysis.html


File diff suppressed because it is too large
+ 1 - 1
docs/api_8hpp_source.html


+ 0 - 2
filval/api.hpp

@@ -46,8 +46,6 @@ namespace fv{
         return new Apply<Ret(ArgTypes...)>(fn, arg, alias);
     }
 
-
-
     template <typename T1, typename T2>
     Pair<T1, T2>* pair(Value<T1>* val1, Value<T2>* val2, const std::string& alias=""){
         return new Pair<T1,T2>(val1, val2, alias);

+ 1 - 0
filval_root/LinkDef.hpp

@@ -4,6 +4,7 @@
 
 #ifdef __CLING__
 #pragma link C++ class std::vector<std::vector<int>>+;
+#pragma link C++ class std::vector<std::vector<unsigned int>>+;
 #pragma link C++ class std::vector<std::vector<float>>+;
 #endif
 

File diff suppressed because it is too large
+ 53 - 138
python/TTTT_Analysis.ipynb


+ 88 - 92
python/utils.py

@@ -1,9 +1,10 @@
 import io
+import os
 import sys
 import itertools as it
-from os.path import dirname, join, abspath, normpath
+from os.path import dirname, join, abspath, normpath, getctime
 from math import ceil, sqrt
-from subprocess import run
+from subprocess import run, PIPE
 from IPython.display import Image
 
 import pydotplus.graphviz as pdp
@@ -12,41 +13,35 @@ import ROOT
 PRJ_PATH = normpath(join(dirname(abspath(__file__)), "../"))
 EXE_PATH = join(PRJ_PATH, "build/main")
 
-PDG = {
-        1:   'd',
-        -1:  'd̄',
-        2:   'u',
-        -2:  'ū',
-        3:   's',
-        -3:  's̄',
-        4:   'c',
-        -4:  'c̄',
-        5:   'b',
-        -5:  'b̄',
-        6:   't',
-        -6:  't̄',
-        11:  'e-',
-        -11: 'e+',
-        12:  'ν_e',
-        -12: 'ῡ_e',
-
-        13:  'μ-',
-        -13: 'μ+',
-        14:  'ν_μ',
-        -14: 'ῡ_μ',
-
-        15:  'τ-',
-        -15: 'τ+',
-        16:  'ν_τ',
-        -16: 'ῡ_τ',
-
-        21:  'gluon',
-        22:  'γ',
-        23:  'Z0',
-        24:  'W+',
-        -24: 'W-',
-        25:  'H',
-      }
+PDG = {1:   'd',   -1:  'd̄',
+       2:   'u',   -2:  'ū',
+       3:   's',   -3:  's̄',
+       4:   'c',   -4:  'c̄',
+       5:   'b',   -5:  'b̄',
+       6:   't',   -6:  't̄',
+
+       11:  'e-',  -11: 'e+',
+       12:  'ν_e', -12: 'ῡ_e',
+
+       13:  'μ-',  -13: 'μ+',
+       14:  'ν_μ', -14: 'ῡ_μ',
+
+       15:  'τ-',  -15: 'τ+',
+       16:  'ν_τ', -16: 'ῡ_τ',
+
+       21:  'gluon',
+       22:  'γ',
+       23:  'Z0',
+       24:  'W+',  -24: 'W-',
+       25:  'H',
+       }
+
+SINGLE_PLOT_SIZE = (600, 450)
+MAX_WIDTH = 1800
+
+SCALE = .75
+CAN_SIZE_DEF = (int(1600*SCALE), int(1200*SCALE))
+CANVAS = ROOT.TCanvas("c1", "", *CAN_SIZE_DEF)
 
 
 def show_event(dataset, idx):
@@ -115,36 +110,50 @@ def normalize_columns(hist2d):
     return normHist
 
 
+
+
 class HistCollection:
-    single_plot_size = (600, 450)
-    max_width = 1800
-
-    scale = .75
-    x_size = int(1600*scale)
-    y_size = int(1200*scale)
-    canvas = ROOT.TCanvas("c1", "", x_size, y_size)
-    # @property
-    # def canvas(self):
-    #     cls = self.__class__
-    #     if not hasattr(cls, "_canvas"):
-    #         scale = .75
-    #         x_size = int(1600*scale)
-    #         y_size = int(1200*scale)
-    #         cls._canvas = ROOT.TCanvas("c1", "", x_size, y_size)
-    #     return cls._canvas
-
-    def __init__(self, sample_name, input_filename,
-                 rebuild_hists=False):
+
+    def __init__(self, sample_name, input_filename):
         self.sample_name = sample_name
-        if rebuild_hists:
-            run([EXE_PATH, "-s", "-f", input_filename])
-        output_filename = input_filename.replace(".root", "_result.root")
-        file = ROOT.TFile.Open(output_filename)
+        self.input_filename = input_filename
+        self.output_filename = self.input_filename.replace(".root", "_result.root")
+        self.conditional_recompute()
+        self.load_objects()
+
+        # Now add these histograms into the current ROOT directory (in memory)
+        # and remove old versions if needed
+        for obj in self.map.values():
+            try:
+                old_obj = ROOT.gDirectory.Get(obj.GetName())
+                ROOT.gDirectory.Remove(old_obj)
+                ROOT.gDirectory.Add(obj)
+            except AttributeError:
+                pass
+        HistCollection.add_collection(self)
+
+    def conditional_recompute(self):
+
+        def recompute():
+            print("Running analysis for sample: ", self.sample_name)
+            if run([EXE_PATH, "-s", "-f", self.input_filename]).returncode != 0:
+                raise RuntimeError(("Failed recompiling analysis code."
+                                    " See log file for more information"))
+
+        if run(["make"], cwd=join(PRJ_PATH, "build"), stdout=PIPE, stderr=PIPE).returncode != 0:
+            raise RuntimeError("Failed recompiling analysis code")
+        if (not os.path.isfile(self.output_filename) or (getctime(EXE_PATH) > getctime(self.output_filename))):
+            recompute()
+        else:
+            print("Loading unchanged result file ", self.output_filename)
+
+    def load_objects(self):
+        file = ROOT.TFile.Open(self.output_filename)
         l = file.GetListOfKeys()
         self.map = {}
         for i in range(l.GetSize()):
             name = l.At(i).GetName()
-            new_name = ":".join((sample_name, name))
+            new_name = ":".join((self.sample_name, name))
             obj = file.Get(name)
             try:
                 obj.SetName(new_name)
@@ -154,31 +163,20 @@ class HistCollection:
             self.map[name] = obj
             setattr(self, name, obj)
         file.Close()
-        # Now add these histograms into the current ROOT directory (in memory)
-        # and remove old versions if needed
-        for obj in self.map.values():
-            try:
-                old_obj = ROOT.gDirectory.Get(obj.GetName())
-                ROOT.gDirectory.Remove(old_obj)
-                ROOT.gDirectory.Add(obj)
-            except AttributeError:
-                pass
-        HistCollection.add_collection(self)
 
     def draw(self, shape=None):
         if shape is None:
             n_plots = len([obj for obj in self.map.values() if hasattr(obj, "Draw") ])
-            if n_plots*self.single_plot_size[0] > self.max_width:
-                shape_x = self.max_width//self.single_plot_size[0]
+            if n_plots*SINGLE_PLOT_SIZE[0] > MAX_WIDTH:
+                shape_x = MAX_WIDTH//SINGLE_PLOT_SIZE[0]
                 shape_y = ceil(n_plots / shape_x)
                 shape = (shape_x, shape_y)
-        self.canvas.Clear()
-        self.canvas.SetCanvasSize(shape[0]*self.single_plot_size[0],
-                                  shape[1]*self.single_plot_size[1])
-        self.canvas.Divide(*shape)
+        CANVAS.Clear()
+        CANVAS.SetCanvasSize(shape[0]*SINGLE_PLOT_SIZE[0], shape[1]*SINGLE_PLOT_SIZE[1])
+        CANVAS.Divide(*shape)
         i = 1
         for hist in self.map.values():
-            self.canvas.cd(i)
+            CANVAS.cd(i)
             try:
                 hist.SetStats(False)
             except AttributeError:
@@ -191,11 +189,10 @@ class HistCollection:
             elif type(hist) in (ROOT.TGraph,):
                 draw_option = "A*"
             else:
-                # print("cannot draw object", hist)
                 continue  # Not a drawable type(probably)
             hist.Draw(draw_option)
             i += 1
-        self.canvas.Draw()
+        CANVAS.Draw()
 
     @classmethod
     def get_hist_set(cls, attrname):
@@ -222,9 +219,9 @@ class HistCollection:
                    _stacks={}):
         labels, hists = cls.get_hist_set(hist_name)
         if draw_canvas:
-            cls.canvas.Clear()
-            cls.canvas.SetCanvasSize(cls.single_plot_size[0],
-                                      cls.single_plot_size[1])
+            CANVAS.Clear()
+            CANVAS.SetCanvasSize(SINGLE_PLOT_SIZE[0],
+                                 SINGLE_PLOT_SIZE[1])
 
         colors = it.cycle([ROOT.kRed, ROOT.kBlue, ROOT.kGreen])
         stack = ROOT.THStack(hist_name+"_stack", title)
@@ -235,7 +232,7 @@ class HistCollection:
         ens = enumerate(zip(hists, labels, colors, normalize_to))
         for i, (hist, label, color, norm) in ens:
             hist_copy = hist
-            hist_copy = hist.Clone(hist.GetName()+"_clone")
+            hist_copy = hist.Clone(hist.GetName()+"_clone" + draw_option)
             hist_copy.SetTitle(label)
             if enable_fill:
                 hist_copy.SetFillColorAlpha(color, 0.75)
@@ -243,16 +240,16 @@ class HistCollection:
             if norm:
                 integral = hist_copy.Integral()
                 hist_copy.Scale(norm/integral, "nosw2")
-                hist_copy.SetStats(False)
+                hist_copy.SetStats(True)
             stack.Add(hist_copy)
         if draw:
             stack.Draw(draw_option)
             if make_legend:
-                cls.canvas.BuildLegend(0.75, 0.75, 0.95, 0.95, "")
+                CANVAS.BuildLegend(0.75, 0.75, 0.95, 0.95, "")
         # prevent stack from getting garbage collected
         _stacks[stack.GetName()] = stack
         if draw_canvas:
-            cls.canvas.Draw()
+            CANVAS.Draw()
         return stack
 
     @classmethod
@@ -266,12 +263,11 @@ class HistCollection:
                 shape = (1, n_hists)
             else:
                 shape = (ceil(sqrt(n_hists)),)*2
-        cls.canvas.SetCanvasSize(cls.single_plot_size[0]*shape[0],
-                                  cls.single_plot_size[1]*shape[1])
-        cls.canvas.Divide(*shape)
+        CANVAS.SetCanvasSize(SINGLE_PLOT_SIZE[0]*shape[0], SINGLE_PLOT_SIZE[1]*shape[1])
+        CANVAS.Divide(*shape)
         for i, hist_name, title in zip(bin_range(n_hists), hist_names, titles):
-            cls.canvas.cd(i)
+            CANVAS.cd(i)
             hists, labels = cls.get_hist_set(hist_name)
             cls.stack_hist(hist_name, title=title, draw=True,
                            draw_canvas=False, **kwargs)
-        cls.canvas.cd(n_hists).BuildLegend(0.75, 0.75, 0.95, 0.95, "")
+        CANVAS.cd(n_hists).BuildLegend(0.75, 0.75, 0.95, 0.95, "")