Skip to content

Commit 1b9471f

Browse files
committed
[skip-ci][doc] Add UHI docs
1 parent 31a0503 commit 1b9471f

File tree

3 files changed

+167
-0
lines changed

3 files changed

+167
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
\defgroup uhi_docs Unified Histogram Interface (UHI)
2+
\ingroup Pythonizations
3+
4+
ROOT histograms implement the [Unified Histogram Interface (UHI)](https://uhi.readthedocs.io/en/latest/index.html), enhancing interoperability with other UHI-compatible libraries. This compliance standardizes histogram operations, making tasks like plotting, indexing, and slicing more intuitive and consistent.
5+
6+
# Table of contents
7+
- [Plotting](\ref plotting)
8+
- [Plotting with mplhep](\ref plotting-with-mplhep)
9+
- [Additional Notes](\ref additional-notes-1)
10+
- [Indexing](\ref indexing)
11+
- [Setup](\ref setup)
12+
- [Slicing](\ref slicing)
13+
- [Setting](\ref setting)
14+
- [Access](\ref access)
15+
- [Additional Notes](\ref additional-notes-2)
16+
17+
18+
\anchor plotting
19+
# Plotting
20+
21+
ROOT histograms implement the `PlottableHistogram` protocol. Any plotting library that accepts an object that follows the protocol can plot ROOT histogram objects.
22+
23+
You can read more about the protocol on the [UHI plotting](https://uhi.readthedocs.io/en/latest/plotting.html) page.
24+
25+
\anchor plotting-with-mplhep
26+
## Plotting with [mplhep](https://github.com/scikit-hep/mplhep)
27+
```python
28+
import ROOT
29+
import matplotlib.pyplot as plt
30+
import mplhep as hep
31+
32+
# Create and fill a 1D histogram
33+
h1 = ROOT.TH1D("h1", "MyHist", 10, -1, 1)
34+
h1.FillRandom("gaus", 1000)
35+
36+
# Load a style sheet and plot the histogram
37+
hep.style.use("LHCb2")
38+
hep.histplot(h1)
39+
plt.title("MyHist")
40+
plt.show()
41+
```
42+
43+
\image html uhi_th1_plot.png width=600px
44+
45+
\anchor additional-notes-1
46+
## Additional Notes
47+
48+
- UHI plotting related pythonizations are added to all [`TH1`](https://root.cern.ch/doc/master/classTH1.html)-derived classes (that includes [`TH2`](https://root.cern.ch/doc/master/classTH2.html) and [`TH3`](https://root.cern.ch/doc/master/classTH3.html)).
49+
- While some libraries such as [mplhep](https://github.com/scikit-hep/mplhep) may not yet support multidimensional `PlottableHistogram` objects, you can call `.values()` on your histogram to retrieve a [`numpy.ndarray`](https://numpy.org/doc/2.2/reference/generated/numpy.ndarray.html) and pass it to appropriate plotting functions.
50+
- Example plotting a 2D ROOT histogram with [`matplotlib.pyplot.imshow`](https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.imshow.html#matplotlib-pyplot-imshow) and [`seaborn.heatmap`](https://seaborn.pydata.org/generated/seaborn.heatmap.html#seaborn-heatmap):
51+
```python
52+
import ROOT
53+
import matplotlib.pyplot as plt
54+
import seaborn as sns
55+
import numpy as np
56+
57+
h2 = ROOT.TH2D("h2", "h2", 10, -1, 1, 10, -1, 1)
58+
h2[...] = np.random.rand(10, 10)
59+
60+
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 6))
61+
62+
# First subplot with imshow
63+
ax1.imshow(h2.values(), cmap='hot', interpolation='nearest')
64+
ax1.set_title("imshow")
65+
66+
# Second subplot with seaborn heatmap
67+
sns.heatmap(h2.values(), linewidth=0.5, ax=ax2)
68+
ax2.set_title("heatmap")
69+
70+
plt.tight_layout()
71+
plt.show()
72+
```
73+
74+
\image html uhi_th2_plot.png width=800px
75+
76+
\anchor indexing
77+
# Indexing
78+
79+
ROOT histograms implement the UHI indexing specification. This introduces a unified syntax for accessing and setting bin values, as well as slicing histogram axes.
80+
81+
You can read more about the syntax on the [UHI Indexing](https://uhi.readthedocs.io/en/latest/indexing.html) page.
82+
83+
\anchor setup
84+
## Setup
85+
The `loc`, `undeflow`, `overflow`, `rebin` and `sum` tags are imported from the `ROOT.uhi` module.
86+
```python
87+
import ROOT
88+
from ROOT.uhi import loc, underflow, overflow, rebin, sum
89+
import numpy as np
90+
91+
92+
h = ROOT.TH2D("h2", "h2", 10, 0, 1, 10, 0, 1)
93+
```
94+
95+
\anchor slicing
96+
## Slicing
97+
```python
98+
# Slicing over everything
99+
h == h[:, :]
100+
h == h[...]
101+
102+
# Slicing a range, picking the bins 1 to 5 along the x axis and 2 to 6 along the y axis
103+
h1 = h[1:5, 2:6]
104+
105+
# Slicing leaving out endpoints
106+
h2 = h[:5, 6:]
107+
108+
# Slicing using data coordinates, picking the bins from the one containing the value 0.5 onwards along both axes
109+
h3 = h[loc(0.5):, loc(0.5):]
110+
111+
# Combining slicing with rebinning, rebinning the x axis by a factor of 2
112+
h4 = h[1:9:rebin(2), :]
113+
```
114+
115+
\anchor setting
116+
### Setting
117+
```python
118+
# Setting the bin contents
119+
h[1, 2] = 5
120+
121+
# Setting the bin contents using data coordinates
122+
h[loc(3), loc(1)] = 5
123+
124+
# Setting the flow bins
125+
h[overflow, overflow] = 5
126+
127+
# Setting the bin contents using a numpy array
128+
h[...] = np.ones((10, 10))
129+
130+
# Setting the bin contents using a scalar
131+
h[...] = 5
132+
```
133+
134+
\anchor access
135+
## Access
136+
```python
137+
# Accessing the bin contents using the bin number
138+
v = h[1, 2]
139+
140+
# Accessing the bin contents using data coordinates
141+
v = h[loc(0.5), loc(0.5)]
142+
v = h[loc(0.5) + 1, loc(0.5) + 1] # Returns the bin above the one containing the value 2 along both axes
143+
144+
# Accessing the flow bins
145+
v = h[underflow, underflow]
146+
```
147+
148+
\anchor additional-notes-2
149+
## Additional Notes
150+
151+
- **Indexing system**
152+
- ROOT histograms use a bin indexing system that ranges from 0 to `nbins+1` where 0 is the underflow bin and `nbins+1` is the overflow (see [conventions for numbering bins](https://root.cern.ch/doc/master/classTH1.html#convention)). In contrast, UHI inherits 0-based indexing from numpy array conventions where 0 is the first valid element and n-1 is the last valid element. Our implementation complies with the UHI conventions by implementing the following syntax:
153+
- `h[underflow]` returns the underflow bin (equivalent to `h.GetBinContent(0)`).
154+
- `h[0]` returns the first valid bin (equivalent to `h.GetBinContent(1)`).
155+
- `h[-1]` returns the last valid bin (equivalent to `h.GetBinContent(nbins)`).
156+
- `h[overflow]` returns the overflow bin (equivalent to `h.GetBinContent(nbins+1)`).
157+
- **Slicing operations**
158+
- Slicing always returns a new histogram with the appropriate values copied from the original one according to the input slice.
159+
- Values outside of the slice range fall into the flow bins.
160+
- **Summing operations with `sum`**
161+
- For a 1D histogram, the integral of the selected slice is returned.
162+
- ex. `ans = h[a:b:sum]` --> `ans` is the integral value.
163+
- For a 2D or 3D histogram, a new histogram with reduced dimensionality is returned
164+
- ex. `h_projected = h[:, ::sum, ::sum]` --> `h_projected` is a 1D histogram representing the y and z projections along the x axis.
165+
- **Setting operations**
166+
- Setting with a scalar does not set the flow bins.
167+
- Setting with an array checks whether the array matches the shape of the histogram with flow bins or the size without flow bins.
37.3 KB
Loading
20.5 KB
Loading

0 commit comments

Comments
 (0)