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]:
import matplotlib.pyplot as plt
import numpy as np

import hist
from hist import Hist

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.000 _                                                                                                      142/row ╷
 -4.600 _
 -4.200 _
 -3.800 _
 -3.400 _
 -3.000 _
 -2.600 _
 -2.200 _
 -1.800 _
 -1.400 _
 -1.000 _
 -0.600 _
 -0.200 _
  0.200 _
  0.600 _
  1.000 _
  1.400 _
  1.800 _
  2.200 _
  2.600 _
  3.000 _
  3.400 _
  3.800 _
  4.200 _
  4.600 _
  5.000 _
                                              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')

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

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