rootfig 0.2.1__tar.gz → 0.2.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {rootfig-0.2.1 → rootfig-0.2.2}/PKG-INFO +58 -62
- rootfig-0.2.2/README.md +164 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/pyproject.toml +1 -1
- {rootfig-0.2.1 → rootfig-0.2.2}/src/rootfig/__init__.py +1 -1
- rootfig-0.2.1/README.md +0 -168
- {rootfig-0.2.1 → rootfig-0.2.2}/.gitignore +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/CONTRIBUTING.md +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/LICENSE +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/docs/api.md +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/docs/composable.md +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/docs/ecosystem.md +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/docs/expressions.md +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/docs/gallery.md +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/docs/hooks/gallery.py +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/docs/images/gallery/arrays.png +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/docs/images/gallery/cms_density.png +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/docs/images/gallery/correlation.png +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/docs/images/gallery/efficiency.png +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/docs/images/gallery/expressions.png +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/docs/images/gallery/fill_stats.png +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/docs/images/gallery/hist2d.png +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/docs/images/gallery/log_axes.png +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/docs/images/gallery/luminosity.png +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/docs/images/gallery/many_plots.png +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/docs/images/gallery/object_vs_event.png +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/docs/images/gallery/overlay_ratio.png +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/docs/images/gallery/profile.png +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/docs/images/gallery/quick.png +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/docs/images/gallery/ratio_reference.png +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/docs/images/gallery/robust_range.png +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/docs/images/gallery/stack_data.png +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/docs/images/gallery/style_colors.png +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/docs/images/gallery/variable_bins.png +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/docs/images/gallery/xbreak_ratio.png +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/docs/index.md +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/docs/plotting.md +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/docs/quickstart.md +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/examples/gallery/__init__.py +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/examples/gallery/__main__.py +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/examples/gallery/data.py +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/examples/gallery/registry.py +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/mkdocs.yml +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/src/rootfig/_typing.py +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/src/rootfig/api.py +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/src/rootfig/errors.py +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/src/rootfig/expressions/__init__.py +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/src/rootfig/expressions/functions.py +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/src/rootfig/expressions/parser.py +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/src/rootfig/histograms/__init__.py +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/src/rootfig/histograms/build.py +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/src/rootfig/histograms/cutflow.py +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/src/rootfig/histograms/efficiency.py +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/src/rootfig/histograms/normalize.py +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/src/rootfig/histograms/pipeline.py +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/src/rootfig/histograms/ratio.py +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/src/rootfig/histograms/stats.py +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/src/rootfig/io/__init__.py +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/src/rootfig/io/sources.py +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/src/rootfig/model/__init__.py +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/src/rootfig/model/binning.py +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/src/rootfig/model/cuts.py +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/src/rootfig/model/samples.py +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/src/rootfig/model/style.py +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/src/rootfig/model/units.py +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/src/rootfig/model/variables.py +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/src/rootfig/plotting/__init__.py +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/src/rootfig/plotting/annotations.py +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/src/rootfig/plotting/correlation.py +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/src/rootfig/plotting/figure.py +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/src/rootfig/plotting/hist1d.py +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/src/rootfig/plotting/hist2d.py +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/src/rootfig/plotting/points.py +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/src/rootfig/plotting/ratio.py +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/src/rootfig/plotting/result.py +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/src/rootfig/plotting/style.py +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/src/rootfig/py.typed +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/src/rootfig/selection/__init__.py +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/src/rootfig/selection/columns.py +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/tests/conftest.py +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/tests/data/split_collection.root +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/tests/test_api.py +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/tests/test_expressions.py +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/tests/test_gallery.py +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/tests/test_histograms.py +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/tests/test_io.py +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/tests/test_model.py +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/tests/test_plotting.py +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/tests/test_selection.py +0 -0
- {rootfig-0.2.1 → rootfig-0.2.2}/tests/test_tutorials.py +0 -0
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: rootfig
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.2
|
|
4
4
|
Summary: Publication-quality figures straight from ROOT trees, without ROOT: uproot + Awkward + hist + mplhep with a TTree::Draw-like API.
|
|
5
5
|
Project-URL: Homepage, https://github.com/jbeirer/rootfig
|
|
6
|
-
Project-URL: Documentation, https://github.
|
|
6
|
+
Project-URL: Documentation, https://jbeirer.github.io/rootfig/
|
|
7
7
|
Project-URL: Repository, https://github.com/jbeirer/rootfig
|
|
8
8
|
Project-URL: Issues, https://github.com/jbeirer/rootfig/issues
|
|
9
9
|
Author-email: Joshua Falco Beirer <jbeirer@cern.ch>
|
|
@@ -35,41 +35,42 @@ Description-Content-Type: text/markdown
|
|
|
35
35
|
|
|
36
36
|
**Publication-quality figures straight from ROOT trees, without ROOT.**
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
give it ROOT files, a tree, an expression, a selection and a weight, and get a
|
|
40
|
-
styled matplotlib figure back in one call. It reads with
|
|
41
|
-
[uproot](https://github.com/scikit-hep/uproot5), computes with
|
|
42
|
-
[Awkward Array](https://github.com/scikit-hep/awkward), fills
|
|
43
|
-
[hist](https://github.com/scikit-hep/hist) histograms and draws with
|
|
44
|
-
[mplhep](https://github.com/scikit-hep/mplhep). It adds the missing glue:
|
|
45
|
-
predictable per-event/per-object selection semantics, weights, shared
|
|
46
|
-
binning across samples, normalisation, ratio panels and good defaults.
|
|
47
|
-
|
|
38
|
+
[](https://jbeirer.github.io/rootfig/)
|
|
48
39
|
[](https://github.com/jbeirer/rootfig/actions/workflows/ci.yml)
|
|
49
40
|
[](https://codecov.io/gh/jbeirer/rootfig)
|
|
50
41
|
[](https://pypi.org/project/rootfig/)
|
|
51
42
|
[](https://pypi.org/project/rootfig/)
|
|
52
43
|
[](LICENSE)
|
|
53
44
|
|
|
45
|
+
**[Documentation](https://jbeirer.github.io/rootfig/) ·
|
|
46
|
+
[Gallery](https://jbeirer.github.io/rootfig/gallery/) ·
|
|
47
|
+
[Quick start](https://jbeirer.github.io/rootfig/quickstart/)**
|
|
48
|
+
|
|
49
|
+
Go from ROOT files to a styled figure in one call. Choose a variable, add a
|
|
50
|
+
selection, and plot:
|
|
51
|
+
|
|
54
52
|
```python
|
|
55
53
|
import rootfig as rf
|
|
56
54
|
|
|
57
55
|
rf.plot("events.root", "Muon_pt", tree="events", selection="Muon_pt > 20", bins=50)
|
|
58
56
|
```
|
|
59
57
|
|
|
58
|
+
Start with a single distribution; add samples, weights, stacks and ratio
|
|
59
|
+
panels as your analysis grows. Every plot gives you a matplotlib figure to
|
|
60
|
+
customise and save. No ROOT installation required.
|
|
61
|
+
|
|
60
62
|
<p align="center">
|
|
61
|
-
<img src="docs/images/gallery/stack_data.png" alt="Stacked simulation with data and a ratio panel" width="48%">
|
|
62
|
-
<img src="docs/images/gallery/xbreak_ratio.png" alt="Broken x axis with a ratio panel" width="48%">
|
|
63
|
+
<a href="https://jbeirer.github.io/rootfig/gallery/"><img src="docs/images/gallery/stack_data.png" alt="Stacked simulation with data and a ratio panel" width="48%"></a>
|
|
64
|
+
<a href="https://jbeirer.github.io/rootfig/gallery/"><img src="docs/images/gallery/xbreak_ratio.png" alt="Broken x axis with a ratio panel" width="48%"></a>
|
|
63
65
|
</p>
|
|
64
66
|
<p align="center">
|
|
65
|
-
<img src="docs/images/gallery/object_vs_event.png" alt="Per-object versus per-event selections" width="48%">
|
|
66
|
-
<img src="docs/images/gallery/hist2d.png" alt="Two-dimensional histogram" width="48%">
|
|
67
|
+
<a href="https://jbeirer.github.io/rootfig/gallery/"><img src="docs/images/gallery/object_vs_event.png" alt="Per-object versus per-event selections" width="48%"></a>
|
|
68
|
+
<a href="https://jbeirer.github.io/rootfig/gallery/"><img src="docs/images/gallery/hist2d.png" alt="Two-dimensional histogram" width="48%"></a>
|
|
67
69
|
</p>
|
|
68
70
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
draws every example in a few seconds; the same figures are pixel-compared in CI.
|
|
71
|
+
**[Explore the gallery →](https://jbeirer.github.io/rootfig/gallery/)**
|
|
72
|
+
See each figure alongside the code that makes it, from simple overlays to
|
|
73
|
+
stacked data/MC comparisons, broken axes and 2D histograms.
|
|
73
74
|
|
|
74
75
|
## Installation
|
|
75
76
|
|
|
@@ -82,7 +83,7 @@ uv add rootfig
|
|
|
82
83
|
Python 3.12 or newer. No ROOT installation is needed; `TTree` and `RNTuple`
|
|
83
84
|
files are both supported.
|
|
84
85
|
|
|
85
|
-
##
|
|
86
|
+
## Compare samples in one call
|
|
86
87
|
|
|
87
88
|
```python
|
|
88
89
|
import rootfig as rf
|
|
@@ -100,8 +101,9 @@ rf.plot(
|
|
|
100
101
|
)
|
|
101
102
|
```
|
|
102
103
|
|
|
103
|
-
|
|
104
|
-
|
|
104
|
+
## Build up to a full analysis
|
|
105
|
+
|
|
106
|
+
Define samples, variables, cuts and styles once, then reuse them across plots:
|
|
105
107
|
|
|
106
108
|
```python
|
|
107
109
|
import rootfig as rf
|
|
@@ -132,56 +134,50 @@ Everything you get back is a standard object: `p.fig` and `p.ax` are
|
|
|
132
134
|
matplotlib `Figure`/`Axes`, `p.hists` are `hist.Hist` objects, and
|
|
133
135
|
`rf.load(...)` returns Awkward arrays.
|
|
134
136
|
|
|
135
|
-
##
|
|
136
|
-
|
|
137
|
-
- **
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
- **
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
- **
|
|
144
|
-
|
|
145
|
-
- **
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
(`Sample(xsec="0.2 pb", ngen="eventsProcessed")`, `lumi="10.8 ab^-1"`).
|
|
152
|
-
- **Analysis tables and panels**: cut flows with yields and efficiencies,
|
|
153
|
-
significance panels (S/√B), efficiency-versus-variable plots with binomial
|
|
154
|
-
intervals, profiles and resolutions.
|
|
155
|
-
- **Experiment-neutral defaults**, with mplhep styles and labels for ATLAS,
|
|
156
|
-
CMS, LHCb, ALICE and DUNE one keyword away; any other experiment name, GeV
|
|
157
|
-
and ab⁻¹ work too.
|
|
158
|
-
- **EDM4hep-friendly**: sub-branches of split collections are addressed as
|
|
159
|
-
`ReconstructedParticles.momentum.x`, with `pt`, `p`, `theta`, `costheta`,
|
|
160
|
-
`eta`, `phi` and `mass` helpers.
|
|
161
|
-
- **Also**: 2D histograms, summary statistics tables, statistics boxes,
|
|
162
|
-
correlation matrices, multi-file globs, entry ranges for quick looks.
|
|
137
|
+
## What you can do
|
|
138
|
+
|
|
139
|
+
- **Select events and objects with readable expressions.** Write cuts such as
|
|
140
|
+
`count(Jet_pt) >= 2` or `Muon_pt > 20`; event and object selections have
|
|
141
|
+
explicit rules, and event weights carry through to each selected object.
|
|
142
|
+
- **Compare samples with a few keywords.** Overlays, stacks, data points and
|
|
143
|
+
ratio panels share binning and propagate histogram uncertainties.
|
|
144
|
+
Normalise to unity, density, bin width or luminosity.
|
|
145
|
+
- **Style figures for your analysis.** Add experiment labels, units, log axes
|
|
146
|
+
and broken axes, then refine the result with matplotlib.
|
|
147
|
+
- **Go beyond 1D plots.** Draw 2D histograms, correlations, efficiencies,
|
|
148
|
+
profiles, resolutions and significance panels; produce cut flows and
|
|
149
|
+
summary statistics from the same inputs.
|
|
150
|
+
- **Work directly with your files.** Read `TTree` and `RNTuple` data, combine
|
|
151
|
+
files with globs, limit entry ranges for quick checks, and use EDM4hep
|
|
152
|
+
split collections. Only the branches your expressions need are read.
|
|
163
153
|
|
|
164
154
|
## Documentation
|
|
165
155
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
- [
|
|
156
|
+
**[Read the docs](https://jbeirer.github.io/rootfig/)** or
|
|
157
|
+
**[browse the gallery](https://jbeirer.github.io/rootfig/gallery/)** for examples
|
|
158
|
+
with figures and code.
|
|
159
|
+
|
|
160
|
+
- [Quick start](https://jbeirer.github.io/rootfig/quickstart/): your first plot, selections and weights.
|
|
161
|
+
- [Expressions and selections](https://jbeirer.github.io/rootfig/expressions/): syntax and event/object rules.
|
|
162
|
+
- [Samples, variables, cuts and styles](https://jbeirer.github.io/rootfig/composable/): reusable analysis definitions.
|
|
163
|
+
- [Plotting options](https://jbeirer.github.io/rootfig/plotting/): binning, normalisation, panels and styling.
|
|
164
|
+
- [API reference](https://jbeirer.github.io/rootfig/api/): full signatures and options.
|
|
171
165
|
|
|
172
166
|
## Relation to the ecosystem
|
|
173
167
|
|
|
174
|
-
`rootfig`
|
|
168
|
+
`rootfig` brings a `TTree::Draw`-like workflow to the Scientific Python HEP
|
|
169
|
+
stack, building on familiar libraries:
|
|
175
170
|
|
|
176
171
|
| Task | Library | What rootfig adds |
|
|
177
172
|
| --- | --- | --- |
|
|
178
|
-
| Reading ROOT files | uproot | file globs, tree auto-detection, reading only the required branches |
|
|
179
|
-
| Jagged arrays | Awkward Array | the per-event/per-object rules for cuts and weights |
|
|
180
|
-
| Histograms | hist / boost-histogram | shared binning, automatic ranges, normalisation, ratios |
|
|
181
|
-
| Drawing | mplhep + matplotlib | overlays, stacks, ratio panels, labels and legends with good defaults |
|
|
173
|
+
| Reading ROOT files | [uproot](https://github.com/scikit-hep/uproot5) | file globs, tree auto-detection, reading only the required branches |
|
|
174
|
+
| Jagged arrays | [Awkward Array](https://github.com/scikit-hep/awkward) | the per-event/per-object rules for cuts and weights |
|
|
175
|
+
| Histograms | [hist](https://github.com/scikit-hep/hist) / boost-histogram | shared binning, automatic ranges, normalisation, ratios |
|
|
176
|
+
| Drawing | [mplhep](https://github.com/scikit-hep/mplhep) + matplotlib | overlays, stacks, ratio panels, labels and legends with good defaults |
|
|
182
177
|
|
|
183
178
|
If you already have `hist.Hist` objects, `rf.plot_histograms` draws them with
|
|
184
|
-
the same options. If you want the arrays, `rf.load` returns them.
|
|
179
|
+
the same options. If you want the arrays, `rf.load` returns them. See
|
|
180
|
+
[the ecosystem guide](https://jbeirer.github.io/rootfig/ecosystem/) for details.
|
|
185
181
|
|
|
186
182
|
## Development
|
|
187
183
|
|
rootfig-0.2.2/README.md
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
# rootfig
|
|
2
|
+
|
|
3
|
+
**Publication-quality figures straight from ROOT trees, without ROOT.**
|
|
4
|
+
|
|
5
|
+
[](https://jbeirer.github.io/rootfig/)
|
|
6
|
+
[](https://github.com/jbeirer/rootfig/actions/workflows/ci.yml)
|
|
7
|
+
[](https://codecov.io/gh/jbeirer/rootfig)
|
|
8
|
+
[](https://pypi.org/project/rootfig/)
|
|
9
|
+
[](https://pypi.org/project/rootfig/)
|
|
10
|
+
[](LICENSE)
|
|
11
|
+
|
|
12
|
+
**[Documentation](https://jbeirer.github.io/rootfig/) ·
|
|
13
|
+
[Gallery](https://jbeirer.github.io/rootfig/gallery/) ·
|
|
14
|
+
[Quick start](https://jbeirer.github.io/rootfig/quickstart/)**
|
|
15
|
+
|
|
16
|
+
Go from ROOT files to a styled figure in one call. Choose a variable, add a
|
|
17
|
+
selection, and plot:
|
|
18
|
+
|
|
19
|
+
```python
|
|
20
|
+
import rootfig as rf
|
|
21
|
+
|
|
22
|
+
rf.plot("events.root", "Muon_pt", tree="events", selection="Muon_pt > 20", bins=50)
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Start with a single distribution; add samples, weights, stacks and ratio
|
|
26
|
+
panels as your analysis grows. Every plot gives you a matplotlib figure to
|
|
27
|
+
customise and save. No ROOT installation required.
|
|
28
|
+
|
|
29
|
+
<p align="center">
|
|
30
|
+
<a href="https://jbeirer.github.io/rootfig/gallery/"><img src="docs/images/gallery/stack_data.png" alt="Stacked simulation with data and a ratio panel" width="48%"></a>
|
|
31
|
+
<a href="https://jbeirer.github.io/rootfig/gallery/"><img src="docs/images/gallery/xbreak_ratio.png" alt="Broken x axis with a ratio panel" width="48%"></a>
|
|
32
|
+
</p>
|
|
33
|
+
<p align="center">
|
|
34
|
+
<a href="https://jbeirer.github.io/rootfig/gallery/"><img src="docs/images/gallery/object_vs_event.png" alt="Per-object versus per-event selections" width="48%"></a>
|
|
35
|
+
<a href="https://jbeirer.github.io/rootfig/gallery/"><img src="docs/images/gallery/hist2d.png" alt="Two-dimensional histogram" width="48%"></a>
|
|
36
|
+
</p>
|
|
37
|
+
|
|
38
|
+
**[Explore the gallery →](https://jbeirer.github.io/rootfig/gallery/)**
|
|
39
|
+
See each figure alongside the code that makes it, from simple overlays to
|
|
40
|
+
stacked data/MC comparisons, broken axes and 2D histograms.
|
|
41
|
+
|
|
42
|
+
## Installation
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
pip install rootfig
|
|
46
|
+
# or
|
|
47
|
+
uv add rootfig
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Python 3.12 or newer. No ROOT installation is needed; `TTree` and `RNTuple`
|
|
51
|
+
files are both supported.
|
|
52
|
+
|
|
53
|
+
## Compare samples in one call
|
|
54
|
+
|
|
55
|
+
```python
|
|
56
|
+
import rootfig as rf
|
|
57
|
+
|
|
58
|
+
# Overlay two samples, normalised to unity, with a ratio panel.
|
|
59
|
+
rf.plot(
|
|
60
|
+
["signal.root", "background.root"],
|
|
61
|
+
"Muon_pt",
|
|
62
|
+
tree="events",
|
|
63
|
+
selection="abs(Muon_eta) < 2.5",
|
|
64
|
+
weight="event_weight",
|
|
65
|
+
bins=(50, 0, 200),
|
|
66
|
+
normalize=True,
|
|
67
|
+
ratio=True,
|
|
68
|
+
)
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Build up to a full analysis
|
|
72
|
+
|
|
73
|
+
Define samples, variables, cuts and styles once, then reuse them across plots:
|
|
74
|
+
|
|
75
|
+
```python
|
|
76
|
+
import rootfig as rf
|
|
77
|
+
|
|
78
|
+
signal = rf.Sample("sig_*.root", tree="events", label="Signal", weight="mc_weight")
|
|
79
|
+
background = rf.Sample("bkg.root", tree="events", label="Background", weight="mc_weight")
|
|
80
|
+
data = rf.Sample("data.root", tree="events", label="Data", is_data=True)
|
|
81
|
+
|
|
82
|
+
pt = rf.Variable("Muon_pt", bins=(50, 0, 200), label=r"$p_T^{\mu}$", unit="GeV")
|
|
83
|
+
baseline = rf.Cut("nMuon >= 1") & "abs(Muon_eta) < 2.5"
|
|
84
|
+
style = rf.Style(experiment="ATLAS", status="Internal", lumi=140, com=13.6)
|
|
85
|
+
|
|
86
|
+
p = rf.plot(
|
|
87
|
+
[background, signal],
|
|
88
|
+
pt,
|
|
89
|
+
observed=data,
|
|
90
|
+
selection=baseline,
|
|
91
|
+
stack=True,
|
|
92
|
+
ratio=True,
|
|
93
|
+
logy=True,
|
|
94
|
+
style=style,
|
|
95
|
+
)
|
|
96
|
+
p.ax.set_ylim(top=1e5) # it is a normal matplotlib Axes
|
|
97
|
+
p.save("muon_pt.pdf")
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Everything you get back is a standard object: `p.fig` and `p.ax` are
|
|
101
|
+
matplotlib `Figure`/`Axes`, `p.hists` are `hist.Hist` objects, and
|
|
102
|
+
`rf.load(...)` returns Awkward arrays.
|
|
103
|
+
|
|
104
|
+
## What you can do
|
|
105
|
+
|
|
106
|
+
- **Select events and objects with readable expressions.** Write cuts such as
|
|
107
|
+
`count(Jet_pt) >= 2` or `Muon_pt > 20`; event and object selections have
|
|
108
|
+
explicit rules, and event weights carry through to each selected object.
|
|
109
|
+
- **Compare samples with a few keywords.** Overlays, stacks, data points and
|
|
110
|
+
ratio panels share binning and propagate histogram uncertainties.
|
|
111
|
+
Normalise to unity, density, bin width or luminosity.
|
|
112
|
+
- **Style figures for your analysis.** Add experiment labels, units, log axes
|
|
113
|
+
and broken axes, then refine the result with matplotlib.
|
|
114
|
+
- **Go beyond 1D plots.** Draw 2D histograms, correlations, efficiencies,
|
|
115
|
+
profiles, resolutions and significance panels; produce cut flows and
|
|
116
|
+
summary statistics from the same inputs.
|
|
117
|
+
- **Work directly with your files.** Read `TTree` and `RNTuple` data, combine
|
|
118
|
+
files with globs, limit entry ranges for quick checks, and use EDM4hep
|
|
119
|
+
split collections. Only the branches your expressions need are read.
|
|
120
|
+
|
|
121
|
+
## Documentation
|
|
122
|
+
|
|
123
|
+
**[Read the docs](https://jbeirer.github.io/rootfig/)** or
|
|
124
|
+
**[browse the gallery](https://jbeirer.github.io/rootfig/gallery/)** for examples
|
|
125
|
+
with figures and code.
|
|
126
|
+
|
|
127
|
+
- [Quick start](https://jbeirer.github.io/rootfig/quickstart/): your first plot, selections and weights.
|
|
128
|
+
- [Expressions and selections](https://jbeirer.github.io/rootfig/expressions/): syntax and event/object rules.
|
|
129
|
+
- [Samples, variables, cuts and styles](https://jbeirer.github.io/rootfig/composable/): reusable analysis definitions.
|
|
130
|
+
- [Plotting options](https://jbeirer.github.io/rootfig/plotting/): binning, normalisation, panels and styling.
|
|
131
|
+
- [API reference](https://jbeirer.github.io/rootfig/api/): full signatures and options.
|
|
132
|
+
|
|
133
|
+
## Relation to the ecosystem
|
|
134
|
+
|
|
135
|
+
`rootfig` brings a `TTree::Draw`-like workflow to the Scientific Python HEP
|
|
136
|
+
stack, building on familiar libraries:
|
|
137
|
+
|
|
138
|
+
| Task | Library | What rootfig adds |
|
|
139
|
+
| --- | --- | --- |
|
|
140
|
+
| Reading ROOT files | [uproot](https://github.com/scikit-hep/uproot5) | file globs, tree auto-detection, reading only the required branches |
|
|
141
|
+
| Jagged arrays | [Awkward Array](https://github.com/scikit-hep/awkward) | the per-event/per-object rules for cuts and weights |
|
|
142
|
+
| Histograms | [hist](https://github.com/scikit-hep/hist) / boost-histogram | shared binning, automatic ranges, normalisation, ratios |
|
|
143
|
+
| Drawing | [mplhep](https://github.com/scikit-hep/mplhep) + matplotlib | overlays, stacks, ratio panels, labels and legends with good defaults |
|
|
144
|
+
|
|
145
|
+
If you already have `hist.Hist` objects, `rf.plot_histograms` draws them with
|
|
146
|
+
the same options. If you want the arrays, `rf.load` returns them. See
|
|
147
|
+
[the ecosystem guide](https://jbeirer.github.io/rootfig/ecosystem/) for details.
|
|
148
|
+
|
|
149
|
+
## Development
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
git clone https://github.com/jbeirer/rootfig
|
|
153
|
+
cd rootfig
|
|
154
|
+
uv sync --all-groups
|
|
155
|
+
uv run pytest
|
|
156
|
+
uv run ruff check . && uv run ruff format --check .
|
|
157
|
+
uv run mypy
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for details.
|
|
161
|
+
|
|
162
|
+
## License
|
|
163
|
+
|
|
164
|
+
MIT. See [LICENSE](LICENSE).
|
|
@@ -40,7 +40,7 @@ dependencies = [
|
|
|
40
40
|
|
|
41
41
|
[project.urls]
|
|
42
42
|
Homepage = "https://github.com/jbeirer/rootfig"
|
|
43
|
-
Documentation = "https://github.
|
|
43
|
+
Documentation = "https://jbeirer.github.io/rootfig/"
|
|
44
44
|
Repository = "https://github.com/jbeirer/rootfig"
|
|
45
45
|
Issues = "https://github.com/jbeirer/rootfig/issues"
|
|
46
46
|
|
rootfig-0.2.1/README.md
DELETED
|
@@ -1,168 +0,0 @@
|
|
|
1
|
-
# rootfig
|
|
2
|
-
|
|
3
|
-
**Publication-quality figures straight from ROOT trees, without ROOT.**
|
|
4
|
-
|
|
5
|
-
`rootfig` is the `TTree::Draw` workflow for the Scientific Python HEP stack:
|
|
6
|
-
give it ROOT files, a tree, an expression, a selection and a weight, and get a
|
|
7
|
-
styled matplotlib figure back in one call. It reads with
|
|
8
|
-
[uproot](https://github.com/scikit-hep/uproot5), computes with
|
|
9
|
-
[Awkward Array](https://github.com/scikit-hep/awkward), fills
|
|
10
|
-
[hist](https://github.com/scikit-hep/hist) histograms and draws with
|
|
11
|
-
[mplhep](https://github.com/scikit-hep/mplhep). It adds the missing glue:
|
|
12
|
-
predictable per-event/per-object selection semantics, weights, shared
|
|
13
|
-
binning across samples, normalisation, ratio panels and good defaults.
|
|
14
|
-
|
|
15
|
-
[](https://github.com/jbeirer/rootfig/actions/workflows/ci.yml)
|
|
16
|
-
[](https://codecov.io/gh/jbeirer/rootfig)
|
|
17
|
-
[](https://pypi.org/project/rootfig/)
|
|
18
|
-
[](https://pypi.org/project/rootfig/)
|
|
19
|
-
[](LICENSE)
|
|
20
|
-
|
|
21
|
-
```python
|
|
22
|
-
import rootfig as rf
|
|
23
|
-
|
|
24
|
-
rf.plot("events.root", "Muon_pt", tree="events", selection="Muon_pt > 20", bins=50)
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
<p align="center">
|
|
28
|
-
<img src="docs/images/gallery/stack_data.png" alt="Stacked simulation with data and a ratio panel" width="48%">
|
|
29
|
-
<img src="docs/images/gallery/xbreak_ratio.png" alt="Broken x axis with a ratio panel" width="48%">
|
|
30
|
-
</p>
|
|
31
|
-
<p align="center">
|
|
32
|
-
<img src="docs/images/gallery/object_vs_event.png" alt="Per-object versus per-event selections" width="48%">
|
|
33
|
-
<img src="docs/images/gallery/hist2d.png" alt="Two-dimensional histogram" width="48%">
|
|
34
|
-
</p>
|
|
35
|
-
|
|
36
|
-
These and a dozen more figures, each next to the code that made it, are in the
|
|
37
|
-
[gallery](https://jbeirer.github.io/rootfig/gallery/). All of them come from
|
|
38
|
-
[`examples/gallery`](examples/gallery/__init__.py), which writes toy ROOT files and
|
|
39
|
-
draws every example in a few seconds; the same figures are pixel-compared in CI.
|
|
40
|
-
|
|
41
|
-
## Installation
|
|
42
|
-
|
|
43
|
-
```bash
|
|
44
|
-
pip install rootfig
|
|
45
|
-
# or
|
|
46
|
-
uv add rootfig
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
Python 3.12 or newer. No ROOT installation is needed; `TTree` and `RNTuple`
|
|
50
|
-
files are both supported.
|
|
51
|
-
|
|
52
|
-
## Quick start
|
|
53
|
-
|
|
54
|
-
```python
|
|
55
|
-
import rootfig as rf
|
|
56
|
-
|
|
57
|
-
# Overlay two samples, normalised to unity, with a ratio panel.
|
|
58
|
-
rf.plot(
|
|
59
|
-
["signal.root", "background.root"],
|
|
60
|
-
"Muon_pt",
|
|
61
|
-
tree="events",
|
|
62
|
-
selection="abs(Muon_eta) < 2.5",
|
|
63
|
-
weight="event_weight",
|
|
64
|
-
bins=(50, 0, 200),
|
|
65
|
-
normalize=True,
|
|
66
|
-
ratio=True,
|
|
67
|
-
)
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
For analysis scripts with many samples, variables and plots, describe things
|
|
71
|
-
once and reuse them:
|
|
72
|
-
|
|
73
|
-
```python
|
|
74
|
-
import rootfig as rf
|
|
75
|
-
|
|
76
|
-
signal = rf.Sample("sig_*.root", tree="events", label="Signal", weight="mc_weight")
|
|
77
|
-
background = rf.Sample("bkg.root", tree="events", label="Background", weight="mc_weight")
|
|
78
|
-
data = rf.Sample("data.root", tree="events", label="Data", is_data=True)
|
|
79
|
-
|
|
80
|
-
pt = rf.Variable("Muon_pt", bins=(50, 0, 200), label=r"$p_T^{\mu}$", unit="GeV")
|
|
81
|
-
baseline = rf.Cut("nMuon >= 1") & "abs(Muon_eta) < 2.5"
|
|
82
|
-
style = rf.Style(experiment="ATLAS", status="Internal", lumi=140, com=13.6)
|
|
83
|
-
|
|
84
|
-
p = rf.plot(
|
|
85
|
-
[background, signal],
|
|
86
|
-
pt,
|
|
87
|
-
observed=data,
|
|
88
|
-
selection=baseline,
|
|
89
|
-
stack=True,
|
|
90
|
-
ratio=True,
|
|
91
|
-
logy=True,
|
|
92
|
-
style=style,
|
|
93
|
-
)
|
|
94
|
-
p.ax.set_ylim(top=1e5) # it is a normal matplotlib Axes
|
|
95
|
-
p.save("muon_pt.pdf")
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
Everything you get back is a standard object: `p.fig` and `p.ax` are
|
|
99
|
-
matplotlib `Figure`/`Axes`, `p.hists` are `hist.Hist` objects, and
|
|
100
|
-
`rf.load(...)` returns Awkward arrays.
|
|
101
|
-
|
|
102
|
-
## Features
|
|
103
|
-
|
|
104
|
-
- **One call from files to figure**, reading only the branches the expressions need.
|
|
105
|
-
- **Expressions in Python syntax**: `sqrt(px**2 + py**2)`, `count(Jet_pt) >= 2`,
|
|
106
|
-
`` `jet1_b-tag` > 0.5 ``, `and`/`or`/`not`, chained comparisons.
|
|
107
|
-
- **Jagged branches done right**: per-object cuts mask objects, per-event
|
|
108
|
-
cuts drop events, ambiguous combinations raise a clear error instead of
|
|
109
|
-
silently broadcasting.
|
|
110
|
-
- **Weights**: per-event weights broadcast onto objects, per-object weights,
|
|
111
|
-
constant scale factors, multiplicative combination of sample and plot weights.
|
|
112
|
-
- **Histograms with uncertainties** (`hist` with `Weight` storage), shared
|
|
113
|
-
binning across samples, automatic or robust ranges, log bins, flow bins.
|
|
114
|
-
- **Overlays, stacks, data points, ratio panels** with correct error
|
|
115
|
-
propagation for weighted histograms and a reference-uncertainty band.
|
|
116
|
-
- **Normalisation**: to unity, density, per bin width, or to a number; or to
|
|
117
|
-
a **luminosity** from cross sections and generated-event counts
|
|
118
|
-
(`Sample(xsec="0.2 pb", ngen="eventsProcessed")`, `lumi="10.8 ab^-1"`).
|
|
119
|
-
- **Analysis tables and panels**: cut flows with yields and efficiencies,
|
|
120
|
-
significance panels (S/√B), efficiency-versus-variable plots with binomial
|
|
121
|
-
intervals, profiles and resolutions.
|
|
122
|
-
- **Experiment-neutral defaults**, with mplhep styles and labels for ATLAS,
|
|
123
|
-
CMS, LHCb, ALICE and DUNE one keyword away; any other experiment name, GeV
|
|
124
|
-
and ab⁻¹ work too.
|
|
125
|
-
- **EDM4hep-friendly**: sub-branches of split collections are addressed as
|
|
126
|
-
`ReconstructedParticles.momentum.x`, with `pt`, `p`, `theta`, `costheta`,
|
|
127
|
-
`eta`, `phi` and `mass` helpers.
|
|
128
|
-
- **Also**: 2D histograms, summary statistics tables, statistics boxes,
|
|
129
|
-
correlation matrices, multi-file globs, entry ranges for quick looks.
|
|
130
|
-
|
|
131
|
-
## Documentation
|
|
132
|
-
|
|
133
|
-
- [Quick start](docs/quickstart.md)
|
|
134
|
-
- [Expressions and selections](docs/expressions.md)
|
|
135
|
-
- [Samples, variables, cuts and styles](docs/composable.md)
|
|
136
|
-
- [Plotting options](docs/plotting.md)
|
|
137
|
-
- [Relation to uproot, Awkward, hist, mplhep and matplotlib](docs/ecosystem.md)
|
|
138
|
-
|
|
139
|
-
## Relation to the ecosystem
|
|
140
|
-
|
|
141
|
-
`rootfig` does not replace any of the libraries it builds on:
|
|
142
|
-
|
|
143
|
-
| Task | Library | What rootfig adds |
|
|
144
|
-
| --- | --- | --- |
|
|
145
|
-
| Reading ROOT files | uproot | file globs, tree auto-detection, reading only the required branches |
|
|
146
|
-
| Jagged arrays | Awkward Array | the per-event/per-object rules for cuts and weights |
|
|
147
|
-
| Histograms | hist / boost-histogram | shared binning, automatic ranges, normalisation, ratios |
|
|
148
|
-
| Drawing | mplhep + matplotlib | overlays, stacks, ratio panels, labels and legends with good defaults |
|
|
149
|
-
|
|
150
|
-
If you already have `hist.Hist` objects, `rf.plot_histograms` draws them with
|
|
151
|
-
the same options. If you want the arrays, `rf.load` returns them.
|
|
152
|
-
|
|
153
|
-
## Development
|
|
154
|
-
|
|
155
|
-
```bash
|
|
156
|
-
git clone https://github.com/jbeirer/rootfig
|
|
157
|
-
cd rootfig
|
|
158
|
-
uv sync --all-groups
|
|
159
|
-
uv run pytest
|
|
160
|
-
uv run ruff check . && uv run ruff format --check .
|
|
161
|
-
uv run mypy
|
|
162
|
-
```
|
|
163
|
-
|
|
164
|
-
See [CONTRIBUTING.md](CONTRIBUTING.md) for details.
|
|
165
|
-
|
|
166
|
-
## License
|
|
167
|
-
|
|
168
|
-
MIT. See [LICENSE](LICENSE).
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|