Stack

Build via Axes

A histogram stack holds multiple 1-D histograms into a stack, whose axes are required to match. The most common way to create one is with a categorical axes:

[1]:
from hist import Hist
import hist
import numpy as np
import matplotlib.pyplot as plt

ax = hist.axis.Regular(25, -5, 5, flow=False, name="x")
cax = hist.axis.StrCategory(["signal", "upper", "lower"], name="c")
full_hist = Hist(ax, cax)

full_hist.fill(x=np.random.normal(size=600), c="signal")
full_hist.fill(x=2 * np.random.normal(size=500) + 2, c="upper")
full_hist.fill(x=2 * np.random.normal(size=500) - 2, c="lower")


s = full_hist.stack("c")

You can build this directly with hist.Stack(h1, h2, h3), hist.Stack.from_iter([h1, h2, h3]), or hist.Stack.from_dict({"signal": h1, "lower": h2, "upper": h3}) as well.

HistStack has .plot() method which calls mplhep and plots the histograms in the stack:

[2]:
s.plot()
plt.legend()
plt.show()
../../_images/user-guide_notebooks_Stack_4_0.png

For the “stacked” style of plot, you can pass arguments through to mplhep. For some reason, this reverses the graphical order, but we can easily undo that by applying a slicing operation to the stack:

[3]:
s[::-1].plot(stack=True, histtype="fill")
plt.legend()
plt.show()
../../_images/user-guide_notebooks_Stack_6_0.png

We can use .show() to access histoprint and print the stacked histograms to the console.

Note: Histoprint currently supports only non-discrete axes. Hence, it supports only regular and variable axes at the moment.

[4]:
s.show(columns=120)
-5.00e+00 _                                                                                                   1.45e+02 ╷
-4.60e+00 _
-4.20e+00 _
-3.80e+00 _
-3.40e+00 _
-3.00e+00 _
-2.60e+00 _
-2.20e+00 _
-1.80e+00 _
-1.40e+00 _
-1.00e+00 _
-6.00e-01 _
-2.00e-01 _
 2.00e-01 _
 6.00e-01 _
 1.00e+00 _
 1.40e+00 _
 1.80e+00 _
 2.20e+00 _
 2.60e+00 _
 3.00e+00 _
 3.40e+00 _
 3.80e+00 _
 4.20e+00 _
 4.60e+00 _
 5.00e+00 _
                                              signal     upper      lower

Manipulations on a Stack

[5]:
h = Hist.new.Reg(50, -5, 5, name="x").StrCat(["good", "bad"], name="quality").Double()

h.fill(x=np.random.randn(100), quality=["good", "good", "good", "good", "bad"] * 20)

# Turn an existing axis into a stack
s = h.stack("quality")
s[::-1].plot(stack=True, histtype="fill")
plt.legend()
plt.show()
../../_images/user-guide_notebooks_Stack_10_0.png

Histograms in a stack can have names. The names of histograms are the categories, which are corresponding profiled histograms:

[6]:
print(s[0].name)
s[0]
good
[6]:
-5 5 x
Regular(50, -5, 5, name='x', label='x')

Double() Σ=80.0

You can use those names in indexing, just like for axes (only when using string names):

[7]:
print(s["bad"].name)
s["bad"]
bad
[7]:
-5 5 x
Regular(50, -5, 5, name='x', label='x')

Double() Σ=20.0

You can scale a stack:

[8]:
(s * 5).plot()
plt.legend()
plt.show()
../../_images/user-guide_notebooks_Stack_16_0.png

Or an item in the stack inplace:

[9]:
s["good"] *= 3
s.plot()
plt.legend()
plt.show()
../../_images/user-guide_notebooks_Stack_18_0.png

You can project on a stack, as well, if the histograms are at least two dimensional. h.stack("x").project("y") is identical to h.project("y").stack("x").