Stack
Contents
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()

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()

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.52e+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()

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]:
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]:
Double() Σ=20.0
You can scale a stack:
[8]:
(s * 5).plot()
plt.legend()
plt.show()

Or an item in the stack inplace:
[9]:
s["good"] *= 3
s.plot()
plt.legend()
plt.show()

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")
.