Преглед на файлове

Updates plotting script

Caleb Fangmeier преди 5 години
родител
ревизия
5966038569
променени са 4 файла, в които са добавени 672 реда и са изтрити 187 реда
  1. 143 0
      docs/reports/report_2018_07_31.md
  2. 259 0
      docs/reports/report_2018_08_16.md
  3. 269 187
      plotting/eff_plots.py
  4. 1 0
      plotting/requirements.txt

Файловите разлики са ограничени, защото са твърде много
+ 143 - 0
docs/reports/report_2018_07_31.md


+ 259 - 0
docs/reports/report_2018_08_16.md

@@ -0,0 +1,259 @@
+Authors: Caleb Fangmeier
+Date: August 16, 2018
+
+[TOC]
+
+# Fixing hit-skipping in ElectronNHitSeedProducer
+
+When the `ElectronNHitSeedProducer` was written for HLT, it had a limitation wherein hit-skipping was not allowed. What does this mean? The pixel-matching procedure has two sets of inputs.
+
+  1. A collection of ECAL superclusters
+  2. A collection of pixel seeds which are pairs/triplets/quadruplets of individual
+  pixel hits on different layers. The individual sets of hits may or may not be disjoint
+  depending on the configuration of the seed creation steps. Nominally, however, they *are* disjoint.
+
+A supercluster matches with a pixel seed if the pixel-match procedure matches the supercluster with at least N hits in the seed, where N is
+
+  - 3 if the track passes through 4+ active layers of pixels
+  - 2 otherwise.
+
+  > Note: This isn't strictly true since the old pixel match routine only ever requires 2 hits.
+
+The old (current Offline) matching scheme (using `ElectronSeedProducer`), allows for skipping hits in the pixel seed to get to this minimal number of matches. For example, if the seed contains four barrel hits denominated by B1, B2, and B3, the matching procedure could match with B1 and B3 (skipping B2) to get the required two matched hits.
+
+The new pixel matching scheme lacked the ability to skip B2 so it would match only B1, falling short of the required two hits. The hack to avoid this issue is to create pixel seeds from all pairs and triplets of hits. So, in the above example, there would be, excepting a few edge cased, four seeds created:
+
+  1. B1, B2
+  2. B2, B3
+  3. B1, B3
+  4. B1, B2, B3
+
+Remember, B2 is the hit that fails to match with the super-cluster, but the supercluster would still end up matching with seed 3 so now this track will not be missed.
+
+There are a couple issues with this hack, however.
+
+  - There are an awful lot more seeds that get created since all combinations are tried.
+  - The hits in the seeds are not disjoint so cross-cleaning should be employed downstream to avoid double counting.
+
+A fix to avoid these issues is to just enable hit-skipping in the new pixel matching code. Appendices [A](#a-hit-skipping-patch) and [B](#b-hit-skipping-code) has a diff and the straight code to implement this. There is also a complementary change to the configuration to get rid of the "make all pairs/triplets" step and instead hook up the `ElectronNHitSeedProducer` with the standard set of pixel seeds from general tracking.
+
+# Performance Studies
+
+I'm going to first compare the effect of the hit skipping on the new seeding. Then I'll compare performance with the old seeding.
+
+<div class="row">
+<div class="col-*-6 row_fig">
+fig!::
+</div>
+<div class="col-*-6 row_fig">
+</div>
+</div>
+
+fig!::tracking_roc_curve_dR|Tracking Efficiency with $\Delta R$ truth-matching
+
+
+# Appendices
+
+## A: Hit-Skipping Patch
+
+Here is the patch for `/RecoEgamma/EgammaElectronAlgos/src/TrajSeedMatcher.cc` to enable hit-skipping.
+
+```patch
+diff --git a/RecoEgamma/EgammaElectronAlgos/src/TrajSeedMatcher.cc b/RecoEgamma/EgammaElectronAlgos/src/TrajSeedMatcher.cc
+index 506895a..75dad73 100644
+--- a/RecoEgamma/EgammaElectronAlgos/src/TrajSeedMatcher.cc
++++ b/RecoEgamma/EgammaElectronAlgos/src/TrajSeedMatcher.cc
+@@ -26,6 +26,7 @@ TrajSeedMatcher::TrajSeedMatcher(const edm::ParameterSet& pset):
+   minNrHitsValidLayerBins_(pset.getParameter<std::vector<int> >("minNrHitsValidLayerBins"))
+ {
+   useRecoVertex_ = pset.getParameter<bool>("useRecoVertex");
++  allowHitSkipping_ = pset.getParameter<bool>("allowHitSkipping");
+   navSchoolLabel_ = pset.getParameter<std::string>("navSchool");
+   detLayerGeomLabel_ = pset.getParameter<std::string>("detLayerGeom");
+   const auto cutsPSets=pset.getParameter<std::vector<edm::ParameterSet> >("matchingCuts");
+@@ -52,6 +53,7 @@ edm::ParameterSetDescription TrajSeedMatcher::makePSetDescription()
+ {
+   edm::ParameterSetDescription desc;
+   desc.add<bool>("useRecoVertex",false);
++  desc.add<bool>("allowHitSkipping", false);
+   desc.add<std::string>("navSchool","SimpleNavigationSchool");
+   desc.add<std::string>("detLayerGeom","hltESPGlobalDetLayerGeometry");
+   desc.add<std::vector<int> >("minNrHitsValidLayerBins",{4});
+@@ -113,6 +115,7 @@ TrajSeedMatcher::compatibleSeeds(const TrajectorySeedCollection& seeds, const Gl
+   for(const auto& seed : seeds) {
+     std::vector<SCHitMatch> matchedHitsNeg = processSeed(seed,candPos,vprim,energy,-1);
+     std::vector<SCHitMatch> matchedHitsPos = processSeed(seed,candPos,vprim,energy,+1);
++
+     int nrValidLayersPos = 0;
+     int nrValidLayersNeg = 0;
+     if(matchedHitsNeg.size()>=2){
+@@ -128,28 +131,15 @@ TrajSeedMatcher::compatibleSeeds(const TrajectorySeedCollection& seeds, const Gl
+ 
+     int nrValidLayers = std::max(nrValidLayersNeg,nrValidLayersPos);
+     size_t nrHitsRequired = getNrHitsRequired(nrValidLayers);
+-    //so we require the number of hits to exactly match, this is because we currently do not
+-    //do any duplicate cleaning for the input seeds
+-    //this means is a hit pair with a 3rd hit will appear twice (or however many hits it has)
+-    //so if you did >=nrHitsRequired, you would get the same seed multiple times
+-    //ideally we should fix this and clean our input seed collection so each seed is only in once
+-    //also it should be studied what impact having a 3rd hit has on a GsfTrack
+-    //ie will we get a significantly different result seeding with a hit pair 
+-    //and the same the hit pair with a 3rd hit added
+-    //in that case, perhaps it should be >=
+-    if(matchedHitsNeg.size()==nrHitsRequired ||
+-       matchedHitsPos.size()==nrHitsRequired){
++
++    if(matchedHitsNeg.size()>=nrHitsRequired ||
++       matchedHitsPos.size()>=nrHitsRequired){
+       matchedSeeds.push_back({seed,matchedHitsPos,matchedHitsNeg,nrValidLayers});
+     }
+-    
+-
+   }
+   return matchedSeeds;
+ }
+ 
+-//checks if the hits of the seed match within requested selection
+-//matched hits are required to be consecutive, as soon as hit isnt matched,
+-//the function returns, it doesnt allow skipping hits
+ std::vector<TrajSeedMatcher::SCHitMatch>
+ TrajSeedMatcher::processSeed(const TrajectorySeed& seed, const GlobalPoint& candPos,
+                              const GlobalPoint & vprim, const float energy, const int charge)
+@@ -159,32 +149,36 @@ TrajSeedMatcher::processSeed(const TrajectorySeed& seed, const GlobalPoint& cand
+ 
+   FreeTrajectoryState trajStateFromVtx = FTSFromVertexToPointFactory::get(*magField_, candPos, vprim, energy, charge);
+   PerpendicularBoundPlaneBuilder bpb;
+-  TrajectoryStateOnSurface initialTrajState(trajStateFromVtx,*bpb(trajStateFromVtx.position(), 
+-								  trajStateFromVtx.momentum()));
+- 
++  TrajectoryStateOnSurface initialTrajState(trajStateFromVtx, *bpb(trajStateFromVtx.position(), trajStateFromVtx.momentum()));
+   std::vector<SCHitMatch> matchedHits;
++  FreeTrajectoryState firstHitFreeTraj;
++  GlobalPoint prevHitPos;
++  GlobalPoint vertex;
++  for (size_t hitNr=0;hitNr<matchingCuts_.size() && hitNr<seed.nHits();hitNr++) {
++    bool matched = false;
++    if (matchedHits.size() == 0) {  // First hit is special
+       SCHitMatch firstHit = matchFirstHit(seed, initialTrajState, vprim, *backwardPropagator_);
+       firstHit.setExtra(candEt, candEta, candPos.phi(), charge, 1);
+       if (passesMatchSel(firstHit, 0)) {
++        matched = true;
+         matchedHits.push_back(firstHit);
+-
+         //now we can figure out the z vertex
+         double zVertex = useRecoVertex_ ? vprim.z() : getZVtxFromExtrapolation(vprim,firstHit.hitPos(),candPos);
+-    GlobalPoint vertex(vprim.x(),vprim.y(),zVertex);
+-    
+-    FreeTrajectoryState firstHitFreeTraj = FTSFromVertexToPointFactory::get(*magField_, firstHit.hitPos(), 
+-									    vertex, energy, charge) ;
+- 
+-    GlobalPoint prevHitPos = firstHit.hitPos();
+-    for(size_t hitNr=1;hitNr<matchingCuts_.size() && hitNr<seed.nHits();hitNr++){
++        vertex = GlobalPoint(vprim.x(), vprim.y(), zVertex);
++        firstHitFreeTraj = FTSFromVertexToPointFactory::get(*magField_, firstHit.hitPos(), vertex, energy, charge);
++        prevHitPos = firstHit.hitPos();
++      }
++    } else {  // All subsequent hits are handled the same
+       SCHitMatch hit = match2ndToNthHit(seed, firstHitFreeTraj, hitNr, prevHitPos, vertex, *forwardPropagator_);
+       hit.setExtra(candEt,candEta,candPos.phi(),charge,1);
+-      if(passesMatchSel(hit,hitNr)){
++      if (passesMatchSel(hit, matchedHits.size())) {
++        matched = true;
+         matchedHits.push_back(hit);
+         prevHitPos = hit.hitPos();
+-      }else break;
+       }
+     }
++    if (!matched and !allowHitSkipping_) break;
++  }
+   return matchedHits;
+ }
+ 
+```
+
+## B: Hit-Skipping Code
+
+And Here is the relevant code on its own.
+
+```c++
+std::vector<TrajSeedMatcher::SeedWithInfo>
+TrajSeedMatcher::compatibleSeeds(const TrajectorySeedCollection& seeds, const GlobalPoint& candPos,
+                                 const GlobalPoint & vprim, const float energy)
+{
+  if(!forwardPropagator_ || !backwardPropagator_ || !magField_.isValid()){
+    throw cms::Exception("LogicError") <<__FUNCTION__<<" can not make pixel seeds as event setup has not properly been called";
+  }
+
+  clearCache();
+
+  std::vector<SeedWithInfo> matchedSeeds;
+  for(const auto& seed : seeds) {
+    std::vector<SCHitMatch> matchedHitsNeg = processSeed(seed,candPos,vprim,energy,-1);
+    std::vector<SCHitMatch> matchedHitsPos = processSeed(seed,candPos,vprim,energy,+1);
+
+    int nrValidLayersPos = 0;
+    int nrValidLayersNeg = 0;
+    if(matchedHitsNeg.size()>=2){
+      nrValidLayersNeg = getNrValidLayersAlongTraj(matchedHitsNeg[0],
+                                                   matchedHitsNeg[1],
+                                                   candPos,vprim,energy,-1);
+    }
+    if(matchedHitsPos.size()>=2){
+      nrValidLayersPos = getNrValidLayersAlongTraj(matchedHitsPos[0],
+                                                   matchedHitsPos[1],
+                                                   candPos,vprim,energy,+1);
+    }
+
+    int nrValidLayers = std::max(nrValidLayersNeg,nrValidLayersPos);
+    size_t nrHitsRequired = getNrHitsRequired(nrValidLayers);
+
+    if(matchedHitsNeg.size()>=nrHitsRequired ||
+       matchedHitsPos.size()>=nrHitsRequired){
+      matchedSeeds.push_back({seed,matchedHitsPos,matchedHitsNeg,nrValidLayers});
+    }
+  }
+  return matchedSeeds;
+}
+
+std::vector<TrajSeedMatcher::SCHitMatch>
+TrajSeedMatcher::processSeed(const TrajectorySeed& seed, const GlobalPoint& candPos,
+                             const GlobalPoint & vprim, const float energy, const int charge)
+{
+  const float candEta = candPos.eta();
+  const float candEt = energy*std::sin(candPos.theta());
+
+  FreeTrajectoryState trajStateFromVtx = FTSFromVertexToPointFactory::get(*magField_, candPos, vprim, energy, charge);
+  PerpendicularBoundPlaneBuilder bpb;
+  TrajectoryStateOnSurface initialTrajState(trajStateFromVtx, *bpb(trajStateFromVtx.position(), trajStateFromVtx.momentum()));
+  std::vector<SCHitMatch> matchedHits;
+  FreeTrajectoryState firstHitFreeTraj;
+  GlobalPoint prevHitPos;
+  GlobalPoint vertex;
+  for (size_t hitNr=0;hitNr<matchingCuts_.size() && hitNr<seed.nHits();hitNr++) {
+    bool matched = false;
+    if (matchedHits.size() == 0) {  // First hit is special
+      SCHitMatch firstHit = matchFirstHit(seed, initialTrajState, vprim, *backwardPropagator_);
+      firstHit.setExtra(candEt, candEta, candPos.phi(), charge, 1);
+      if (passesMatchSel(firstHit, 0)) {
+        matched = true;
+        matchedHits.push_back(firstHit);
+        //now we can figure out the z vertex
+        double zVertex = useRecoVertex_ ? vprim.z() : getZVtxFromExtrapolation(vprim,firstHit.hitPos(),candPos);
+        vertex = GlobalPoint(vprim.x(), vprim.y(), zVertex);
+        firstHitFreeTraj = FTSFromVertexToPointFactory::get(*magField_, firstHit.hitPos(), vertex, energy, charge);
+        prevHitPos = firstHit.hitPos();
+      }
+    } else {  // All subsequent hits are handled the same
+      SCHitMatch hit = match2ndToNthHit(seed, firstHitFreeTraj, hitNr, prevHitPos, vertex, *forwardPropagator_);
+      hit.setExtra(candEt,candEta,candPos.phi(),charge,1);
+      if (passesMatchSel(hit, matchedHits.size())) {
+        matched = true;
+        matchedHits.push_back(hit);
+        prevHitPos = hit.hitPos();
+      }
+    }
+    if (!matched and !allowHitSkipping_) break;
+  }
+  return matchedHits;
+}
+```

+ 269 - 187
plotting/eff_plots.py

@@ -1,5 +1,6 @@
 #!/usr/bin/env python
 from itertools import product
+from argparse import ArgumentParser
 import numpy as np
 import matplotlib.pyplot as plt
 
@@ -123,12 +124,23 @@ def load_samples():
     global samples
     if samples is None:
         print("loading samples")
-        samples = {(proc, wp): root_open(f'../hists/{proc}-{wp}.root') for proc, wp in product(procs, wps)}
+        samples = {}
+        for proc, wp, config in product(procs, wps, configs):
+            samples[(proc, wp, config)] = root_open(f'../hists/{proc}-{wp}-{config}.root')
+            # if 'old' in wp:
+            #     samples[(proc, wp)] = root_open(f'../hists/with_skipping/{proc}-{wp}.root')
+            # elif 'noskip' in wp:
+            #     wpkey = wp.replace('-noskip', '')
+            #     samples[(proc, wp)] = root_open(f'../hists/no_skipping/{proc}-{wpkey}.root')
+            # elif 'skip' in wp:
+            #     wpkey = wp.replace('-skip', '')
+            #     samples[(proc, wp)] = root_open(f'../hists/with_skipping/{proc}-{wpkey}.root')
     return samples
 
 
 def calc_window(et, eta, hit, variable, cut_sel):
     idx = min(hit-1, 2)
+    cut_sel = cut_sel.replace('-skip', '').replace('-noskip', '')
     cuts = matching_cuts[cut_sel][idx]
     if 'etaBins' in cuts:
         for eta_idx, bin_high in enumerate(cuts['etaBins']):
@@ -265,6 +277,10 @@ def plot_residuals_eta(sample, hit, variable):
 @mpb.decl_fig
 def plot_hit_vs_layer(sample, region):
     load_samples()
+    if region == 'BPIX':
+        region = 'barrel'
+    if region == 'FPIX':
+        region = 'forward'
     h = Hist2D(samples[sample][f'hit_vs_layer_{region}'])
     plot_2d(h, colz_fmt='2.0f')
     plt.xlabel('Layer #')
@@ -282,12 +298,13 @@ def plot_roc_curve(pfx, ext=''):
         return hist_integral_ratio(num, den)
     rows = []
     row_labels = []
-    for proc in procs:
+    for i, proc in enumerate(procs):
+        plt.subplot(len(procs), 1, i+1)
         row_labels.append(procs[proc])
         row_labels.extend(['']*(len(wps)-1))
-        for wp in wps:
-            sample = samples[(proc, wp)]
-            sample_name = f'{proc}-{wp}'
+        for wp, config in product(wps, configs):
+            sample = samples[(proc, wp, config)]
+            sample_name = f'{proc}-{wp}-{config}'
             eff, eff_err = get_num_den(sample, f'{pfx}_eff_v_phi{ext}')
             pur, pur_err = get_num_den(sample, f'{pfx}_pur_v_phi{ext}')
             if show_fr:
@@ -297,17 +314,27 @@ def plot_roc_curve(pfx, ext=''):
                              rf'${eff*100:0.2f}\pm{eff_err*100:0.2f}\%$',
                              rf'${pur*100:0.2f}\pm{pur_err*100:0.2f}\%$',
                              rf'${fr*100:0.2f}\pm{fr_err*100:0.2f}\%$'])
-
-            plt.errorbar([pur], [eff], xerr=[pur_err], yerr=[eff_err],
-                         label=sample_name, marker='o', color=color(proc, wp))
-    center_text(0.3, 0.3, r'$p_T>20$ and $|\eta|<2.5$')
-    plt.axis('equal')
-    plt.xlim((0.5, 1.02))
-    plt.ylim((0.5, 1.02))
+            if config == 'skip-pileup':
+                marker = 'o'
+            elif config == 'noskip':
+                marker = '*'
+            else:
+                marker = '^'
+
+            # plt.errorbar([pur], [eff], xerr=[pur_err], yerr=[eff_err],
+            #              label=sample_name, marker=marker, color=color(proc, wp))
+            plt.scatter([pur], [eff], label=sample_name, marker=marker, color=color(proc, wp))
+
+        # center_text(0.3, 0.3, r'$p_T>20$ and $|\eta|<2.5$')
+        # plt.axis('equal')
+        # plt.xlim((0.5, 1.02))
+        # plt.ylim((0.5, 1.02))
+        plt.xlim((0, 1.02))
+        plt.ylim((0.7, 1.02))
+        plt.ylabel('Efficiency')
+        plt.grid()
+        plt.legend(loc='lower right', ncol=2, fancybox=True, numpoints=1)
     plt.xlabel('Purity')
-    plt.ylabel('Efficiency')
-    plt.grid()
-    plt.legend(loc='lower right')
 
     col_labels = ['Sample', 'Working Point', 'Efficiency', 'Purity']
     if show_fr:
@@ -317,16 +344,23 @@ def plot_roc_curve(pfx, ext=''):
 
 @mpb.decl_fig
 def plot_kinematic_eff(pref, ext='', ylim=(None, None), norm=None, label_pfx='', incl_sel=True,
-                       bins_pt=None, bins_eta=None, bins_phi=None,
+                       bins_pt=None, bins_eta=None, bins_phi=None, bins_PU=None,
                        xlim_pt=(None, None), xlim_eta=(None, None), xlim_phi=(None, None),
-                       is_ratio=False):
+                       is_ratio=False, config=None):
     load_samples()
+    # Figure out if this one has v_PU
+    has_PU =  f'{pref}_v_PU{ext}' in list(samples.values())[0]
+
     ax_pt = plt.subplot(221)
     ax_eta = plt.subplot(222)
     ax_phi = plt.subplot(223)
+    if has_PU:
+        ax_PU = plt.subplot(224)
     errors = True
-    for (proc, wp), sample in samples.items():
-        sample_name = f'{proc}-{wp}'
+    for (proc, wp, config_), sample in samples.items():
+        if config is not None and config_ != config:
+            continue
+        sample_name = f'{proc}-{wp}-{config_}'
         l = sample_name
         c = color(proc, wp)
 
@@ -345,11 +379,13 @@ def plot_kinematic_eff(pref, ext='', ylim=(None, None), norm=None, label_pfx='',
                     h = h / (norm*h.integral)
                 if bins:
                     h.rebin(bins)
-            hist_plot(h, include_errors=errors, label=l, color=c)
+            hist_plot(h, include_errors=errors, label=l, color=c, linestyle=style(config_))
 
         do_plot(ax_pt, f'{pref}_v_pt{ext}', bins_pt)
         do_plot(ax_eta, f'{pref}_v_eta{ext}', bins_eta)
         do_plot(ax_phi, f'{pref}_v_phi{ext}', bins_phi)
+        if has_PU:
+            do_plot(ax_PU, f'{pref}_v_PU{ext}', [-0.5, 20, 30, 40, 50, 60, 70, 80, 100.5])
 
     plt.sca(ax_pt)
     if not incl_sel: center_text(0.5, 0.15, r'$|\eta|<2.5$')
@@ -368,9 +404,19 @@ def plot_kinematic_eff(pref, ext='', ylim=(None, None), norm=None, label_pfx='',
     plt.xlabel(fr"{label_pfx} $\phi$")
     plt.ylim(ylim)
     plt.xlim(xlim_phi)
-    plt.tight_layout()
-    plt.legend(loc='upper left', bbox_to_anchor=(0.6, 0.45), bbox_transform=plt.gcf().transFigure,
-               prop={'size': 20})
+
+    if has_PU:
+        plt.sca(ax_PU)
+        if not incl_sel: center_text(0.5, 0.15, r'$p_T>20$ and $|\eta|<2.5$')
+        plt.xlabel("# Pile-up Interactions")
+        plt.ylim(ylim)
+        plt.tight_layout()
+        plt.sca(ax_eta)
+        plt.legend(loc='best', prop={'size': 10})
+    else:
+        plt.tight_layout()
+        plt.legend(loc='upper left', bbox_to_anchor=(0.6, 0.45), bbox_transform=plt.gcf().transFigure,
+                   prop={'size': 20})
 
 
 @mpb.decl_fig
@@ -378,8 +424,11 @@ def plot_ecal_rel_res():
     load_samples()
     for sample_name, sample in samples.items():
         h = Hist1D(sample['ecal_energy_resolution'])
-        h = h / h.integral
-        hist_plot(h, label=sample_name)
+        try:
+            h = h / h.integral
+            hist_plot(h, label=sample_name)
+        except ZeroDivisionError:
+            pass
     plt.xlabel(r"ECAL $E_T$ relative error")
     plt.legend()
 
@@ -403,7 +452,7 @@ def plot_res_contour(proc, hit_number, var, layers, ext='_TrackMatched'):
         cuts = [calc_window(et, 0, hit_number, var, wp) for et in ets]
         plt.plot(cuts, ets, color='k', label='Cut Value')
 
-    for ax, wp in zip(axs, ['new-default', 'new-wide']):
+    for ax, wp in zip(axs, ['new-default-noskip', 'new-wide-noskip']):
         do_plot(ax, (proc, wp))
 
     plt.sca(axs[-1])
@@ -413,17 +462,20 @@ def plot_res_contour(proc, hit_number, var, layers, ext='_TrackMatched'):
 @mpb.decl_fig
 def simple_dist(hist_name, rebin=(), norm=1, xlabel="", ylabel="", xlim=None, ylim=None, line_width=1):
     load_samples()
-    for (proc, wp), sample in samples.items():
-        sample_name = f'{proc}-{wp}'
+    for (proc, wp, config), sample in samples.items():
+        sample_name = f'{proc}-{wp}-{config}'
         h = Hist1D(sample[hist_name])
         if rebin:
             h.rebin(*rebin)
 
         mean = np.sum(h.counts * h.bin_centers) / h.integral
-        if norm is not None:
-            h = h * (norm / h.integral)
-        hist_plot(h, label=f'{sample_name} ($\\mu={mean:.2f}$)',
-                  color=color(proc, wp), line_width=line_width)
+        try:
+            if norm is not None:
+                h = h * (norm / h.integral)
+            hist_plot(h, label=f'{sample_name} ($\\mu={mean:.2f}$)',
+                      color=color(proc, wp), line_width=line_width)
+        except ZeroDivisionError:
+            pass
     if xlim:
         plt.xlim(xlim)
     if ylim:
@@ -434,116 +486,94 @@ def simple_dist(hist_name, rebin=(), norm=1, xlabel="", ylabel="", xlim=None, yl
 
 
 @mpb.decl_fig
-def simple_dist2d(hist_name, proc, wp, xlabel="", ylabel="", xlim=None, ylim=None, norm=None):
+def simple_dist2d(hist_name, proc, wp, config, norm=None, colz_fmt='g', clear_zero=False, **kwargs):
     load_samples()
-    sample = samples[(proc, wp)]
-    # sample_name = f'{proc}-{wp}'
+    sample = samples[(proc, wp, config)]
     h = Hist2D(sample[hist_name])
     if norm is not None:
         h = h * (norm / h.integral)
-    plot_2d(h, colz_fmt='g')
-    if xlim:
-        plt.xlim(xlim)
-    if ylim:
-        plt.ylim(ylim)
-    plt.xlabel(xlabel)
-    plt.ylabel(ylabel)
+    if clear_zero:
+        h.counts[0, 0] = 0
+    plot_2d(h, colz_fmt=colz_fmt, cmap='viridis', **kwargs)
 
 
-def all_cut_plots(refresh=True, publish=False):
+def all_cut_plots(build=True, publish=False):
 
     figures = {
-        'tracking_roc_curve': (plot_roc_curve, ('tracking',)),
-        'tracking_roc_curve_dR': (plot_roc_curve, ('tracking',), {'ext': '_dR'}),
-        'seeding_roc_curve': (plot_roc_curve, ('seed',)),
-
-        'number_of_seeds': (simple_dist, ('n_seeds',),
-                            dict(xlabel='Number of Seeds', rebin=(50, -0.5, 200.5))),
-        'number_of_good_seeds': (simple_dist, ('n_good_seeds',),
-                                 dict(xlabel='Number of Seeds', rebin=(50, -0.5, 200.5))),
-        'number_of_scls': (simple_dist, ('n_scl',),
-                           dict(xlabel='Number of Super-Clusters', xlim=(-0.5, 25.5))),
-        'number_of_good_scls': (simple_dist, ('n_good_scl',),
-                                dict(xlabel='Number of Super-Clusters', xlim=(-0.5, 25.5))),
-
-        'number_of_sim_els': (simple_dist, ('n_good_sim',),
-                              dict(xlabel='Number of prompt(ish) electrons', xlim=(-0.5, 20.5))),
-        'number_of_gsf_tracks': (simple_dist, ('n_gsf_track',),
-                                 dict(xlabel='Number of reco electrons', xlim=(-0.5, 20.5))),
-
-        'number_of_prompt': (simple_dist, ('n_prompt',),
-                             dict(xlabel='Number of prompt electrons', xlim=(-0.5, 20.5))),
-        'number_of_nonprompt': (simple_dist, ('n_nonprompt',),
-                                dict(xlabel='Number of nonprompt electrons', xlim=(-0.5, 20.5))),
-
-        'number_of_matched': (simple_dist, ('n_matched',),
-                              dict(xlabel='Number of matched electrons', xlim=(-0.5, 10.5), line_width=4)),
-        'number_of_merged': (simple_dist, ('n_merged',),
-                             dict(xlabel='Number of merged electrons', xlim=(-0.5, 10.5), line_width=4)),
-        'number_of_lost': (simple_dist, ('n_lost',),
-                           dict(xlabel='Number of lost electrons', xlim=(-0.5, 10.5), line_width=4)),
-        'number_of_split': (simple_dist, ('n_split',),
-                            dict(xlabel='Number of split electrons', xlim=(-0.5, 10.5), line_width=4)),
-        'number_of_faked': (simple_dist, ('n_faked',),
-                            dict(xlabel='Number of faked electrons', xlim=(-0.5, 10.5), line_width=4)),
-        'number_of_flipped': (simple_dist, ('n_flipped',),
-                              dict(xlabel='Number of flipped electrons', xlim=(-0.5, 10.5), line_width=4)),
-        'matched_dR': (simple_dist, ('matched_dR',),
-                       dict(xlabel='dR between sim and reco')),
-        'matched_dpT': (simple_dist, ('matched_dpT',),
-                        dict(xlabel='dpT between sim and reco')),
-
-        'number_of_matched_dR': (simple_dist, ('n_matched_dR',),
-                                 dict(xlabel='Number of matched electrons - dR Matched', xlim=(-0.5, 10.5),
-                                      line_width=4)),
-        'number_of_merged_dR': (simple_dist, ('n_merged_dR',),
-                                dict(xlabel='Number of merged electrons - dR Matched', xlim=(-0.5, 10.5),
-                                     line_width=4)),
-        'number_of_lost_dR': (simple_dist, ('n_lost_dR',),
-                              dict(xlabel='Number of lost electrons - dR Matched', xlim=(-0.5, 10.5),
-                                   line_width=4)),
-        'number_of_split_dR': (simple_dist, ('n_split_dR',),
-                               dict(xlabel='Number of split electrons - dR Matched', xlim=(-0.5, 10.5),
-                                    line_width=4)),
-        'number_of_faked_dR': (simple_dist, ('n_faked_dR',),
-                               dict(xlabel='Number of faked electrons - dR Matched', xlim=(-0.5, 10.5),
-                                    line_width=4)),
-        'number_of_flipped_dR': (simple_dist, ('n_flipped_dR',),
-                                 dict(xlabel='Number of flipped electrons - dR Matched', xlim=(-0.5, 10.5),
-                                      line_width=4)),
-        'matched_dR_dR': (simple_dist, ('matched_dR_dR',),
-                          dict(xlabel='dR between sim and reco - dR Matched')),
-        'matched_dpT_dR': (simple_dist, ('matched_dpT_dR',),
-                           dict(xlabel='dpT between sim and reco - dR Matched')),
-
-        'tm_corr': (simple_dist2d, ('tm_corr', 'zee', 'old-default'),
-                    dict(xlabel='Seed Matched', ylabel='Track Matched', norm=1)),
-
-        'ecal_rel_res': plot_ecal_rel_res,
-        'hit_v_layer_BPIX_new-default_zee': (plot_hit_vs_layer, (('zee', 'new-default'), 'barrel')),
-        'hit_v_layer_FPIX_new-default_zee': (plot_hit_vs_layer, (('zee', 'new-default'), 'forward')),
-        'hit_v_layer_BPIX_new-default_tt': (plot_hit_vs_layer, (('tt', 'new-default'), 'barrel')),
-        'hit_v_layer_FPIX_new-default_tt': (plot_hit_vs_layer, (('tt', 'new-default'), 'forward')),
-        'hit_v_layer_BPIX_new-wide_zee': (plot_hit_vs_layer, (('zee', 'new-wide'), 'barrel')),
-        'hit_v_layer_FPIX_new-wide_zee': (plot_hit_vs_layer, (('zee', 'new-wide'), 'forward')),
-        'hit_v_layer_BPIX_new-wide_tt': (plot_hit_vs_layer, (('tt', 'new-wide'), 'barrel')),
-        'hit_v_layer_FPIX_new-wide_tt': (plot_hit_vs_layer, (('tt', 'new-wide'), 'forward')),
-
-
-        'good_sim_kinem': (plot_kinematic_eff, ('good_sim',),
-                           dict(norm=1, ylim=(0, None), bins_eta=30, bins_phi=30)),
-        'gsf_track_kinem': (plot_kinematic_eff, ('gsf_track',),
-                            dict(norm=1, ylim=(0, None), bins_eta=30, bins_phi=30)),
-        'seed_kinem': (plot_kinematic_eff, ('seed',),
-                       dict(norm=1, ylim=(0, None), bins_eta=30, bins_phi=30)),
-        'scl_kinem': (plot_kinematic_eff, ('scl',),
-                      dict(norm=1, ylim=(0, None), bins_eta=30, bins_phi=30)),
-        'prompt_kinem': (plot_kinematic_eff, ('prompt',),
-                         dict(norm=1, ylim=(0, None), bins_pt=30, bins_eta=30, bins_phi=30)),
-        'nonprompt_kinem': (plot_kinematic_eff, ('nonprompt',),
-                            dict(norm=1, ylim=(0, None), xlim_pt=(0, 5), bins_eta=30, bins_phi=30)),
+        'tracking_roc_curve': plot_roc_curve('tracking'),
+        'tracking_roc_curve_dR': plot_roc_curve('tracking', ext='_dR'),
+        'seeding_roc_curve': plot_roc_curve('seed'),
+
+        # 'number_of_seeds': simple_dist('n_seeds', xlabel='Number of Seeds', rebin=(50, -0.5, 200.5)),
+        # 'number_of_good_seeds': simple_dist('n_good_seeds', xlabel='Number of Seeds', rebin=(50, -0.5, 200.5)),
+        # 'number_of_scls': simple_dist('n_scl', xlabel='Number of Super-Clusters', xlim=(-0.5, 25.5)),
+        # 'number_of_good_scls': simple_dist('n_good_scl', xlabel='Number of Super-Clusters', xlim=(-0.5, 25.5)),
+        #
+        # 'number_of_sim_els': simple_dist('n_good_sim', xlabel='Number of prompt(ish) electrons', xlim=(-0.5, 20.5)),
+        # 'number_of_gsf_tracks': simple_dist('n_gsf_track', xlabel='Number of reco electrons', xlim=(-0.5, 20.5)),
+        #
+        # 'number_of_prompt': simple_dist('n_prompt', xlabel='Number of prompt electrons', xlim=(-0.5, 20.5)),
+        # 'number_of_nonprompt': simple_dist('n_nonprompt', xlabel='Number of nonprompt electrons', xlim=(-0.5, 20.5)),
+        #
+        # 'number_of_matched': simple_dist('n_matched', xlabel='Number of matched electrons',
+        #                                  xlim=(-0.5, 10.5), line_width=4),
+        # 'number_of_merged': simple_dist('n_merged', xlabel='Number of merged electrons',
+        #                                 xlim=(-0.5, 10.5), line_width=4),
+        # 'number_of_lost': simple_dist('n_lost', xlabel='Number of lost electrons',
+        #                               xlim=(-0.5, 10.5), line_width=4),
+        # 'number_of_split': simple_dist('n_split', xlabel='Number of split electrons',
+        #                                xlim=(-0.5, 10.5), line_width=4),
+        # 'number_of_faked': simple_dist('n_faked', xlabel='Number of faked electrons',
+        #                                xlim=(-0.5, 10.5), line_width=4),
+        # 'number_of_flipped': simple_dist('n_flipped', xlabel='Number of flipped electrons',
+        #                                  xlim=(-0.5, 10.5), line_width=4),
+        # 'matched_dR': simple_dist('matched_dR', xlabel='dR between sim and reco'),
+        # 'matched_dpT': simple_dist('matched_dpT', xlabel='dpT between sim and reco'),
+        #
+        #
+        # 'number_of_matched_dR': simple_dist('n_matched_dR', xlabel='Number of matched electrons - dR Matched',
+        #                                     xlim=(-0.5, 10.5), line_width=4),
+        # 'number_of_merged_dR': simple_dist('n_merged_dR', xlabel='Number of merged electrons - dR Matched',
+        #                                    xlim=(-0.5, 10.5), line_width=4),
+        # 'number_of_lost_dR': simple_dist('n_lost_dR', xlabel='Number of lost electrons - dR Matched',
+        #                                  xlim=(-0.5, 10.5), line_width=4),
+        # 'number_of_split_dR': simple_dist('n_split_dR', xlabel='Number of split electrons - dR Matched',
+        #                                   xlim=(-0.5, 10.5), line_width=4),
+        # 'number_of_faked_dR': simple_dist('n_faked_dR', xlabel='Number of faked electrons - dR Matched',
+        #                                   xlim=(-0.5, 10.5), line_width=4),
+        # 'number_of_flipped_dR': simple_dist('n_flipped_dR', xlabel='Number of flipped electrons - dR Matched',
+        #                                     xlim=(-0.5, 10.5), line_width=4),
+        # 'matched_dR_dR': simple_dist('matched_dR_dR', xlabel='dR between sim and reco - dR Matched'),
+        # 'matched_dpT_dR': simple_dist('matched_dpT_dR', xlabel='dpT between sim and reco - dR Matched'),
+        #
+        # # 'tm_corr': simple_dist2d('tm_corr', 'dy', 'old-default', xlabel='Seed Matched', ylabel='Track Matched', norm=1),
+        #
+        # 'ecal_rel_res': plot_ecal_rel_res(),
+        # # 'hit_v_layer_BPIX_new-default_dy': plot_hit_vs_layer(('dy', 'new-default-skip'), 'barrel'),
+        # # 'hit_v_layer_FPIX_new-default_dy': plot_hit_vs_layer(('dy', 'new-default-skip'), 'forward'),
+        # # 'hit_v_layer_BPIX_new-default_tt': plot_hit_vs_layer(('tt', 'new-default-skip'), 'barrel'),
+        # # 'hit_v_layer_FPIX_new-default_tt': plot_hit_vs_layer(('tt', 'new-default-skip'), 'forward'),
+        # # 'hit_v_layer_BPIX_new-wide_dy': plot_hit_vs_layer(('dy', 'new-wide-skip'), 'barrel'),
+        # # 'hit_v_layer_FPIX_new-wide_dy': plot_hit_vs_layer(('dy', 'new-wide-skip'), 'forward'),
+        # # 'hit_v_layer_BPIX_new-wide_tt': plot_hit_vs_layer(('tt', 'new-wide-skip'), 'barrel'),
+        # # 'hit_v_layer_FPIX_new-wide_tt': plot_hit_vs_layer(('tt', 'new-wide-skip'), 'forward'),
+        #
+        #
+        # 'seed_kinem': plot_kinematic_eff('seed', norm=1, ylim=(0, None), bins_eta=30, bins_phi=30),
+        # 'scl_kinem': plot_kinematic_eff('scl', norm=1, ylim=(0, None), bins_eta=30, bins_phi=30),
+        # 'prompt_kinem': plot_kinematic_eff('prompt', norm=1, ylim=(0, None), bins_pt=30, bins_eta=30, bins_phi=30),
+        # 'nonprompt_kinem': plot_kinematic_eff('nonprompt', norm=1, ylim=(0, None), xlim_pt=(0, 5),
+        #                                       bins_eta=30, bins_phi=30),
     }
 
+    for config in configs:
+        figures[f'good_sim_kinem_{config}'] = plot_kinematic_eff('good_sim', norm=1, ylim=(0, None),
+                                                                 bins_eta=30, bins_phi=30, config=config)
+        figures[f'gsf_track_kinem_{config}'] = plot_kinematic_eff('gsf_track', norm=1, ylim=(0, None),
+                                                                  bins_eta=30, bins_phi=30, config=config)
+
+    # for proc, wp, region in product(procs, wps, ('BPIX', 'FPIX')):
+    #     figures[f'hit_v_layer_{region}_{wp}_{proc}'] = plot_hit_vs_layer((proc, wp), region)
 
     def add_num_den(key, func, args, kwargs):
         base_ext = kwargs.get('ext', '')
@@ -551,69 +581,99 @@ def all_cut_plots(refresh=True, publish=False):
         kwargs['bins_pt'] = kwargs.get('bins_pt', bins_pt_)
         kwargs['bins_eta'] = kwargs.get('bins_eta', 15)
         kwargs['bins_phi'] = kwargs.get('bins_phi', 15)
-        figures[key] = (func, args, dict(**kwargs, ylim=(0, 1.1), is_ratio=True))
+        figures[key] = func(*args, ylim=(0, 1.1), is_ratio=True, **kwargs)
         kwargs_ = kwargs.copy()
         kwargs_['ext'] = base_ext+'_num'
-        figures[key+'_num'] = (func, args, kwargs_)
+        figures[key+'_num'] = func(*args, **kwargs_)
         kwargs_ = kwargs.copy()
         kwargs_['ext'] = base_ext+'_den'
-        figures[key+'_den'] = (func, args, kwargs_)
+        figures[key+'_den'] = func(*args, **kwargs_)
 
-    add_num_den('tracking_eff', plot_kinematic_eff, ('tracking_eff',), dict(incl_sel=False))
-    add_num_den('tracking_pur', plot_kinematic_eff, ('tracking_pur',), dict(incl_sel=False))
+    # add_num_den('tracking_eff', plot_kinematic_eff, ('tracking_eff',), dict(incl_sel=False))
+    # add_num_den('tracking_pur', plot_kinematic_eff, ('tracking_pur',), dict(incl_sel=False))
     add_num_den('tracking_eff_dR', plot_kinematic_eff, ('tracking_eff',), dict(ext='_dR', incl_sel=False))
     add_num_den('tracking_pur_dR', plot_kinematic_eff, ('tracking_pur',), dict(ext='_dR', incl_sel=False))
-    add_num_den('prompt_eff', plot_kinematic_eff, ('prompt_eff',), dict(incl_sel=False))
-    add_num_den('prompt_pur', plot_kinematic_eff, ('prompt_pur',), dict(incl_sel=False))
+    # add_num_den('prompt_eff', plot_kinematic_eff, ('prompt_eff',), dict(incl_sel=False))
+    # add_num_den('prompt_pur', plot_kinematic_eff, ('prompt_pur',), dict(incl_sel=False))
     add_num_den('prompt_eff_dR', plot_kinematic_eff, ('prompt_eff',), dict(ext='_dR', incl_sel=False))
     add_num_den('prompt_pur_dR', plot_kinematic_eff, ('prompt_pur',), dict(ext='_dR', incl_sel=False))
-    add_num_den('nonprompt_eff', plot_kinematic_eff, ('nonprompt_eff',), dict(incl_sel=False))
-    add_num_den('nonprompt_pur', plot_kinematic_eff, ('nonprompt_pur',), dict(incl_sel=False))
+    # add_num_den('nonprompt_eff', plot_kinematic_eff, ('nonprompt_eff',), dict(incl_sel=False))
+    # add_num_den('nonprompt_pur', plot_kinematic_eff, ('nonprompt_pur',), dict(incl_sel=False))
     add_num_den('nonprompt_eff_dR', plot_kinematic_eff, ('nonprompt_eff',), dict(ext='_dR', incl_sel=False))
     add_num_den('nonprompt_pur_dR', plot_kinematic_eff, ('nonprompt_pur',), dict(ext='_dR', incl_sel=False))
 
     add_num_den('seeding_eff', plot_kinematic_eff, ('seed_eff',), dict(incl_sel=False))
     add_num_den('seeding_pur', plot_kinematic_eff, ('seed_pur',), dict(incl_sel=False))
-
-    add_num_den('fake_rate_incl', plot_kinematic_eff, ('fake_rate_incl',), {})
-    add_num_den('fake_rate_no_e_match_incl', plot_kinematic_eff, ('fake_rate_no_e_match_incl',), {})
-    add_num_den('partial_fake_rate_incl', plot_kinematic_eff, ('partial_fake_rate_incl',), {})
-    add_num_den('full_fake_rate_incl', plot_kinematic_eff, ('full_fake_rate_incl',), {})
-    add_num_den('clean_fake_rate_incl', plot_kinematic_eff, ('clean_fake_rate_incl',), {})
-
-    add_num_den('fake_rate', plot_kinematic_eff, ('fake_rate',), dict(incl_sel=False))
-    add_num_den('fake_rate_no_e_match', plot_kinematic_eff, ('fake_rate_no_e_match',), dict(incl_sel=False))
-    add_num_den('partial_fake_rate', plot_kinematic_eff, ('partial_fake_rate',), dict(incl_sel=False))
-    add_num_den('full_fake_rate', plot_kinematic_eff, ('full_fake_rate',), dict(incl_sel=False))
-    add_num_den('clean_fake_rate', plot_kinematic_eff, ('clean_fake_rate',), dict(incl_sel=False))
-
-    hit_layers = [(1, 1), (1, 2), (2, 2), (2, 3), (3, 3), (3, 4)]
-    for proc, wp, (hit, layer), var, subdet in product(['zee', 'tt'], ['new-default', 'new-wide'],
-                                                       hit_layers,
-                                                       ['dPhi', 'dRz'], ['BPIX', 'FPIX']):
-        figures.update({
-            f'res_{subdet}_L{layer}_H{hit}_{var}_{proc}_{wp}':
-                (plot_residuals, ((proc, wp), layer, hit, var, subdet))})
-
-    rel_layers = {1: [('BPIX', 1), ('BPIX', 2), ('FPIX', 1), ('FPIX', 2)],
-                  2: [('BPIX', 2), ('BPIX', 3), ('FPIX', 2), ('FPIX', 3)],
-                  3: [('BPIX', 3), ('BPIX', 4), ('FPIX', 3)], }
-    for proc, hit, var in product(['zee', 'tt'], [1, 2, 3], ['dPhi', 'dRz']):
-        figures.update({
-            f'resall_H{hit}_{var}_{proc}': (plot_res_contour, (proc, hit, var, rel_layers[hit]))})
-
-    for proc, wp, hit, var in product(['zee', 'tt'], ['new-default', 'new-wide'], [1, 2, 3], ['dPhi', 'dRz']):
-        figures.update({
-            f'res_v_eta_H{hit}_{var}_{proc}_{wp}': (plot_residuals_eta, ((proc, wp), hit, var))})
-
-    mpb.render(figures, refresh=refresh)
+    #
+    # add_num_den('fake_rate_incl', plot_kinematic_eff, ('fake_rate_incl',), {})
+    # add_num_den('fake_rate_no_e_match_incl', plot_kinematic_eff, ('fake_rate_no_e_match_incl',), {})
+    # add_num_den('partial_fake_rate_incl', plot_kinematic_eff, ('partial_fake_rate_incl',), {})
+    # add_num_den('full_fake_rate_incl', plot_kinematic_eff, ('full_fake_rate_incl',), {})
+    # add_num_den('clean_fake_rate_incl', plot_kinematic_eff, ('clean_fake_rate_incl',), {})
+    #
+    # add_num_den('fake_rate', plot_kinematic_eff, ('fake_rate',), dict(incl_sel=False))
+    # add_num_den('fake_rate_no_e_match', plot_kinematic_eff, ('fake_rate_no_e_match',), dict(incl_sel=False))
+    # add_num_den('partial_fake_rate', plot_kinematic_eff, ('partial_fake_rate',), dict(incl_sel=False))
+    # add_num_den('full_fake_rate', plot_kinematic_eff, ('full_fake_rate',), dict(incl_sel=False))
+    # add_num_den('clean_fake_rate', plot_kinematic_eff, ('clean_fake_rate',), dict(incl_sel=False))
+    #
+    # # hit_layers = [(1, 1), (1, 2), (2, 2), (2, 3), (3, 3), (3, 4)]
+    # # for proc, wp, (hit, layer), var, subdet in product(['dy', 'tt'], ['new-default-noskip', 'new-wide-noskip'],
+    # #                                                    hit_layers, ['dPhi', 'dRz'], ['BPIX', 'FPIX']):
+    # #     figures[f'res_{subdet}_L{layer}_H{hit}_{var}_{proc}_{wp}'] = plot_residuals((proc, wp), layer, hit, var, subdet)
+    #
+    # # rel_layers = {1: [('BPIX', 1), ('BPIX', 2), ('FPIX', 1), ('FPIX', 2)],
+    # #               2: [('BPIX', 2), ('BPIX', 3), ('FPIX', 2), ('FPIX', 3)],
+    # #               3: [('BPIX', 3), ('BPIX', 4), ('FPIX', 3)], }
+    # # for proc, hit, var in product(['dy', 'tt'], [1, 2, 3], ['dPhi', 'dRz']):
+    # #     figures[f'resall_H{hit}_{var}_{proc}'] = plot_res_contour(proc, hit, var, rel_layers[hit])
+    #
+    # # for proc, wp, hit, var in product(['dy', 'tt'], ['new-default-noskip', 'new-wide-noskip'], [1, 2, 3], ['dPhi', 'dRz']):
+    # #     figures[f'res_v_eta_H{hit}_{var}_{proc}_{wp}'] = plot_residuals_eta((proc, wp), hit, var)
+    #
+    # # figures = {}
+    #
+    def add_simple_plot(proc, wp, config, plot_name, xlabel, ylabel, is2d=False, xlim=None, ylim=None, clear_zero=False):
+        if is2d:
+            figures[f'{plot_name}_{proc}_{wp}_{config}'] = \
+                simple_dist2d(plot_name, proc, wp, config, colz_fmt='', xlabel=xlabel, ylabel=ylabel, do_profile=True,
+                              xlim=xlim, ylim=ylim, clear_zero=clear_zero)
+        else:
+            figures[f'{plot_name}_{proc}_{wp}_{config}'] = \
+                simple_dist(plot_name, proc, wp, config, xlabel=xlabel, ylabel=ylabel, xlim=xlim, ylim=ylim)
+
+    for proc, wp, config, in product(procs, wps, configs):
+        # add_simple_plot(proc, wp, 'n_pileup')
+        add_simple_plot(proc, wp, config, 'n_initseeds_v_PU', '# Initial Seeds', '# In-Time Pileup', True)
+        add_simple_plot(proc, wp, config, 'n_seeds_v_PU', '# Seeds', '# In-Time Pileup', True)
+        add_simple_plot(proc, wp, config, 'n_good_seeds_v_PU', '# Seeds', '# In-Time Pileup', True, xlim=(-0.5, 40.5))
+        add_simple_plot(proc, wp, config, 'n_tracks_v_PU', '# GSF Tracks', '# In-Time Pileup', True, xlim=(-0.5, 20.5))
+        # add_simple_plot(proc, wp, config, 'n_pv_v_PU', '# PV', '# In-Time Pileup', True, xlim=(-0.5, 50.5))  # garbage
+
+        # add_simple_plot(proc, wp, config, 'n_seeds_v_tPU', '# Seeds', '# True Pileup', True)
+        # add_simple_plot(proc, wp, config, 'n_good_seeds_v_tPU', '# Seeds', '# True Pileup', True, xlim=(-0.5, 40.5))
+        # add_simple_plot(proc, wp, config, 'n_tracks_v_tPU', '# GSF Tracks', '# True Pileup', True, xlim=(-0.5, 20.5))
+        # add_simple_plot(proc, wp, config, 'n_pv_v_tPU', '# PV', '# True Pileup', True, xlim=(-0.5, 50.5))
+
+        # add_simple_plot(proc, wp, config, 'n_seeds_v_n_scl', '# Seeds', '# Super Clusters', True,
+        #                 xlim=(-0.5, 20.5), ylim=(-0.5, 20.5), clear_zero=False)
+        add_simple_plot(proc, wp, config, 'n_good_seeds_v_n_scl', '# Good Seeds', '# Super Clusters', True,
+                        xlim=(-0.5, 20.5), ylim=(-0.5, 20.5), clear_zero=False)
+    #     add_simple_plot(proc, wp, config, 'n_good_seeds_v_n_good_scl', '# Good Seeds', '# Good Super Clusters', True,
+    #                     xlim=(-0.5, 20.5), ylim=(-0.5, 20.5), clear_zero=False)
+    #     add_simple_plot(proc, wp, config, 'n_initseeds_v_PU', '# Initial Seeds', '# In-Time Pileup', True,
+    #                     xlim=None, ylim=None, clear_zero=False)
+    #     add_simple_plot(proc, wp, config, 'n_initseeds_v_tPU', '# Initial Seeds', '# True Pileup', True,
+    #                     xlim=None, ylim=None, clear_zero=False)
+
+    mpb.render(figures, build=build)
     mpb.generate_report(figures, 'Electron Seeding Studies',
                         output=f'hists.html',
                         source=__file__)
 
-    # mpb.generate_report(figures, 'Update',
+    # mpb.generate_report(figures, 'Fixing Hit Skipping',
     #                     output='report.html',
-    #                     body='../docs/reports/report_2018_05_30.md')
+    #                     body='../docs/reports/report_2018_08_16.md')
     if publish:
         mpb.publish()
 
@@ -624,35 +684,57 @@ def color(proc, wp):
     def f(name):
         return XKCD_COLORS['xkcd:'+name]
 
+    wp = wp.replace('-skip', '')
+    wp = wp.replace('-noskip', '')
+    wp = wp.replace('-pileup', '')
     return {
-        ('zee', 'new-extra-narrow'): f('kelly green'),
-        ('tt',  'new-extra-narrow'): f('grey green'),
-        ('zee', 'new-default'):      f('red'),
+        ('dy', 'new-extra-narrow'): f('indigo'),
+        ('tt',  'new-extra-narrow'): f('bright purple'),
+        ('dy', 'new-default'):      f('red'),
         ('tt',  'new-default'):      f('pink'),
-        ('zee', 'new-wide'):         f('strong blue'),
+        ('dy', 'new-wide'):         f('strong blue'),
         ('tt',  'new-wide'):         f('bright blue'),
-        ('zee', 'new-extra-wide'):   f('indigo'),
-        ('tt',  'new-extra-wide'):   f('bright purple'),
-        ('zee', 'old-default'):      f('black'),
+        ('dy', 'new-extra-wide'):   f('kelly green'),
+        ('tt',  'new-extra-wide'):   f('green'),
+        ('dy', 'old-default'):      f('black'),
         ('tt',  'old-default'):      f('blue grey'),
     }[(proc, wp)]
 
+def style(config):
+    return {
+        'noskip': '-',
+        'skip': '--',
+        'skip-pileup': '-.',
+    }[config]
+
 
 if __name__ == '__main__':
+    parser = ArgumentParser('Electron Seeding Efficiency Plot Maker')
+    parser.add_argument('--build', action='store_true')
+    parser.add_argument('--publish', action='store_true')
+    args = parser.parse_args()
     set_defaults()
     mpb.configure(output_dir='seeding_studies',
                   multiprocess=True,
                   publish_remote="caleb@fangmeier.tech",
                   publish_dir="/var/www/eg",
-                  publish_url="eg.fangmeier.tech/",
+                  publish_url="eg.fangmeier.tech",
+                  early_abort=True,
                   )
     procs = {
-        'zee': r'$Z\rightarrow e^+e^-$',
+        'dy': r'Drell-Yan',
         'tt': r'$t\bar{t}$'
     }
+    configs = [
+        'noskip',
+        'skip',
+        'skip-pileup',
+    ]
     wps = {
+        'old-default': 'Old-Method Seeding',
+        # 'new-narrow': 'HLT Settings',
         'new-default': 'HLT Settings',
         'new-wide': 'Wide Settings',
-        'old-default': 'Old Seeding',
+        # 'new-extra-wide': 'Extra Wide Settings',
     }
-    all_cut_plots(refresh=True, publish=False)
+    all_cut_plots(build=args.build, publish=args.publish)

+ 1 - 0
plotting/requirements.txt

@@ -4,3 +4,4 @@ ipython
 uproot
 matplotboard
 -e git+https://github.com/cfangmeier/matplottery.git#egg=matplottery
+-e git+https://github.com/cfangmeier/matplotboard.git#egg=matplotboard