From 975f20d44a790fed79596302f31308755afbc327 Mon Sep 17 00:00:00 2001
From: Frank Sauerburger <f.sauerburger@cern.ch>
Date: Thu, 28 Nov 2019 14:38:24 +0100
Subject: [PATCH] Add density argument to hist()

---
 examples/Histogram.ipynb | 17 +++++++++++++++++
 nnfwtbn/plot.py          | 19 ++++++++++++++++---
 2 files changed, 33 insertions(+), 3 deletions(-)

diff --git a/examples/Histogram.ipynb b/examples/Histogram.ipynb
index 215bd2f..2a2718f 100644
--- a/examples/Histogram.ipynb
+++ b/examples/Histogram.ipynb
@@ -167,6 +167,23 @@
     "None"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "colors = [\"windows blue\", \"amber\", \"greyish\", \"faded green\", \"dusty purple\"]\n",
+    "colors = sns.xkcd_palette(colors)\n",
+    "\n",
+    "s_sig = McStack(p_sig, color=colors[0], histtype='step')\n",
+    "s_ztt = McStack(p_ztt, color=colors[1], histtype='step')\n",
+    "\n",
+    "hist(df, v_higgs_m, 20, [s_sig, s_ztt], range=(0, 200), selection=None,\n",
+    "     weight=\"weight\",  numerator=None, density=True)\n",
+    "None"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
diff --git a/nnfwtbn/plot.py b/nnfwtbn/plot.py
index 1814a6d..01a8b90 100644
--- a/nnfwtbn/plot.py
+++ b/nnfwtbn/plot.py
@@ -60,7 +60,7 @@ def hist(dataframe, variable, bins, stacks, selection=None,
          weight=None, y_log=False, y_min=None, vlines=[],
          denominator=0, numerator=-1, ratio_label=None, diff=False,
          ratio_range=None, atlas=None, info=None, enlarge=1.3,
-         **kwds):
+         density=False, **kwds):
     """
     Creates a histogram of stacked processes. The first argument is the
     dataframe to operate on. The 'variable' argument defines the x-axis. The
@@ -124,6 +124,9 @@ def hist(dataframe, variable, bins, stacks, selection=None,
 
     The module constants ATLAS and INFO are passed to atlasify. Overwrite them
     to change the badges.
+
+    If the density argument is True, the area of each stack is normalized to
+    unity.
     """
     # Wrap column string by variable
     if isinstance(variable, str):
@@ -219,17 +222,26 @@ def hist(dataframe, variable, bins, stacks, selection=None,
             c_blind = variable.blinding(variable, bins)
         else:
             c_blind = lambda d: d
+
+        density_norm = 1.0
+        if density:
+            density_norm = stack.get_total(dataframe,
+                                           [float('-inf'), float('inf')],
+                                           variable, weight).sum()
              
         for i_process in range_(len(stack)):
             process = stack.processes[i_process]
             histogram = stack.get_hist(c_blind(dataframe), i_process, bins,
                                        variable, weight)
 
+            histogram = histogram / density_norm
+
             # Draw uncertainty iff this is the last processes of the stack
             if i_process == len(stack) - 1:
                 uncertainty = stack.get_total_uncertainty(c_blind(dataframe),
                                                           bins, variable,
                                                           weight)
+                uncertainty = uncertainty / density_norm
 
             # Draw process
             histtype = stack.get_histtype(i_process)
@@ -317,11 +329,12 @@ def hist(dataframe, variable, bins, stacks, selection=None,
                                 horizontalalignment='right', x=0.95)
 
     if equidistant_bins:
+        subject = "Fraction" if density else "Events"
         if variable.unit is not None:
-            axes.set_ylabel("Events / %g %s" % (bins[1] - bins[0], variable.unit),
+            axes.set_ylabel(f"{subject} / %g %s" % (bins[1] - bins[0], variable.unit),
                             horizontalalignment='right', y=0.95)
         else:
-            axes.set_ylabel("Events / %g" % (bins[1] - bins[0]),
+            axes.set_ylabel(f"{subject} / %g" % (bins[1] - bins[0]),
                             horizontalalignment='right', y=0.95)
     else:
         axes.set_ylabel("Events / Bin", horizontalalignment='right', y=0.95)
-- 
GitLab