rootfig 0.4.0__tar.gz → 0.5.0__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.4.0 → rootfig-0.5.0}/PKG-INFO +1 -1
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/composable.md +1 -1
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/plotting.md +2 -1
- {rootfig-0.4.0 → rootfig-0.5.0}/examples/gallery/__init__.py +27 -18
- {rootfig-0.4.0 → rootfig-0.5.0}/src/rootfig/__init__.py +1 -1
- {rootfig-0.4.0 → rootfig-0.5.0}/src/rootfig/api/_common.py +2 -2
- {rootfig-0.4.0 → rootfig-0.5.0}/src/rootfig/api/data.py +1 -1
- {rootfig-0.4.0 → rootfig-0.5.0}/src/rootfig/api/measures.py +5 -5
- {rootfig-0.4.0 → rootfig-0.5.0}/src/rootfig/api/plots1d.py +3 -3
- {rootfig-0.4.0 → rootfig-0.5.0}/src/rootfig/histograms/build.py +3 -3
- {rootfig-0.4.0 → rootfig-0.5.0}/src/rootfig/histograms/normalize.py +2 -2
- {rootfig-0.4.0 → rootfig-0.5.0}/src/rootfig/histograms/pipeline.py +2 -2
- {rootfig-0.4.0 → rootfig-0.5.0}/src/rootfig/model/samples.py +7 -7
- {rootfig-0.4.0 → rootfig-0.5.0}/src/rootfig/model/style.py +2 -2
- {rootfig-0.4.0 → rootfig-0.5.0}/src/rootfig/model/variables.py +2 -2
- {rootfig-0.4.0 → rootfig-0.5.0}/tests/test_api.py +3 -1
- {rootfig-0.4.0 → rootfig-0.5.0}/tests/test_histograms.py +8 -8
- {rootfig-0.4.0 → rootfig-0.5.0}/tests/test_model.py +23 -21
- {rootfig-0.4.0 → rootfig-0.5.0}/tests/test_plotting.py +2 -2
- {rootfig-0.4.0 → rootfig-0.5.0}/.gitignore +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/CONTRIBUTING.md +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/LICENSE +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/README.md +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/api.md +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/ecosystem.md +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/expressions.md +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/gallery/index.md +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/hooks/gallery.py +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/arrays-alice-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/arrays-alice.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/arrays-atlas-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/arrays-atlas.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/arrays-cms-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/arrays-cms.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/arrays-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/arrays-dune-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/arrays-dune.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/arrays-lhcb-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/arrays-lhcb.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/arrays.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/correlation-alice-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/correlation-alice.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/correlation-atlas-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/correlation-atlas.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/correlation-cms-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/correlation-cms.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/correlation-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/correlation-dune-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/correlation-dune.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/correlation-lhcb-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/correlation-lhcb.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/correlation.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/density_flow-alice-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/density_flow-alice.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/density_flow-atlas-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/density_flow-atlas.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/density_flow-cms-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/density_flow-cms.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/density_flow-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/density_flow-dune-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/density_flow-dune.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/density_flow-lhcb-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/density_flow-lhcb.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/density_flow.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/efficiency-alice-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/efficiency-alice.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/efficiency-atlas-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/efficiency-atlas.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/efficiency-cms-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/efficiency-cms.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/efficiency-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/efficiency-dune-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/efficiency-dune.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/efficiency-lhcb-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/efficiency-lhcb.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/efficiency.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/expressions-alice-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/expressions-alice.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/expressions-atlas-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/expressions-atlas.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/expressions-cms-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/expressions-cms.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/expressions-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/expressions-dune-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/expressions-dune.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/expressions-lhcb-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/expressions-lhcb.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/expressions.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/fill_stats-alice-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/fill_stats-alice.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/fill_stats-atlas-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/fill_stats-atlas.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/fill_stats-cms-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/fill_stats-cms.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/fill_stats-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/fill_stats-dune-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/fill_stats-dune.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/fill_stats-lhcb-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/fill_stats-lhcb.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/fill_stats.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/hist2d-alice-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/hist2d-alice.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/hist2d-atlas-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/hist2d-atlas.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/hist2d-cms-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/hist2d-cms.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/hist2d-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/hist2d-dune-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/hist2d-dune.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/hist2d-lhcb-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/hist2d-lhcb.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/hist2d.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/log_axes-alice-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/log_axes-alice.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/log_axes-atlas-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/log_axes-atlas.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/log_axes-cms-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/log_axes-cms.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/log_axes-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/log_axes-dune-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/log_axes-dune.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/log_axes-lhcb-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/log_axes-lhcb.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/log_axes.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/luminosity-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/luminosity.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/many_plots-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/many_plots.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/object_vs_event-alice-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/object_vs_event-alice.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/object_vs_event-atlas-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/object_vs_event-atlas.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/object_vs_event-cms-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/object_vs_event-cms.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/object_vs_event-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/object_vs_event-dune-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/object_vs_event-dune.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/object_vs_event-lhcb-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/object_vs_event-lhcb.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/object_vs_event.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/overlay_ratio-alice-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/overlay_ratio-alice.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/overlay_ratio-atlas-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/overlay_ratio-atlas.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/overlay_ratio-cms-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/overlay_ratio-cms.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/overlay_ratio-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/overlay_ratio-dune-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/overlay_ratio-dune.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/overlay_ratio-lhcb-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/overlay_ratio-lhcb.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/overlay_ratio.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/profile-alice-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/profile-alice.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/profile-atlas-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/profile-atlas.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/profile-cms-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/profile-cms.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/profile-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/profile-dune-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/profile-dune.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/profile-lhcb-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/profile-lhcb.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/profile.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/quick-alice-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/quick-alice.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/quick-atlas-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/quick-atlas.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/quick-cms-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/quick-cms.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/quick-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/quick-dune-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/quick-dune.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/quick-lhcb-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/quick-lhcb.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/quick.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/ratio_reference-alice-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/ratio_reference-alice.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/ratio_reference-atlas-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/ratio_reference-atlas.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/ratio_reference-cms-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/ratio_reference-cms.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/ratio_reference-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/ratio_reference-dune-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/ratio_reference-dune.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/ratio_reference-lhcb-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/ratio_reference-lhcb.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/ratio_reference.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/robust_range-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/robust_range.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/stack_data-alice-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/stack_data-alice.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/stack_data-atlas-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/stack_data-atlas.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/stack_data-cms-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/stack_data-cms.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/stack_data-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/stack_data-dune-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/stack_data-dune.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/stack_data-lhcb-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/stack_data-lhcb.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/stack_data.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/style_colors-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/style_colors.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/systematics-alice-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/systematics-alice.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/systematics-atlas-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/systematics-atlas.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/systematics-cms-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/systematics-cms.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/systematics-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/systematics-dune-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/systematics-dune.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/systematics-lhcb-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/systematics-lhcb.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/systematics.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/variable_bins-alice-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/variable_bins-alice.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/variable_bins-atlas-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/variable_bins-atlas.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/variable_bins-cms-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/variable_bins-cms.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/variable_bins-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/variable_bins-dune-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/variable_bins-dune.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/variable_bins-lhcb-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/variable_bins-lhcb.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/variable_bins.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/xbreak_ratio-alice-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/xbreak_ratio-alice.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/xbreak_ratio-atlas-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/xbreak_ratio-atlas.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/xbreak_ratio-cms-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/xbreak_ratio-cms.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/xbreak_ratio-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/xbreak_ratio-dune-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/xbreak_ratio-dune.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/xbreak_ratio-lhcb-dark.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/xbreak_ratio-lhcb.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/images/gallery/xbreak_ratio.png +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/index.md +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/quickstart.md +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/docs/stylesheets/gallery.css +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/examples/gallery/__main__.py +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/examples/gallery/data.py +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/examples/gallery/registry.py +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/mkdocs.yml +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/pyproject.toml +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/src/rootfig/_mapping.py +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/src/rootfig/_typing.py +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/src/rootfig/api/__init__.py +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/src/rootfig/api/plots2d.py +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/src/rootfig/api/tables.py +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/src/rootfig/errors.py +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/src/rootfig/expressions/__init__.py +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/src/rootfig/expressions/functions.py +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/src/rootfig/expressions/parser.py +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/src/rootfig/histograms/__init__.py +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/src/rootfig/histograms/cutflow.py +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/src/rootfig/histograms/efficiency.py +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/src/rootfig/histograms/ratio.py +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/src/rootfig/histograms/stats.py +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/src/rootfig/histograms/systematics.py +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/src/rootfig/io/__init__.py +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/src/rootfig/io/sources.py +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/src/rootfig/model/__init__.py +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/src/rootfig/model/binning.py +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/src/rootfig/model/cuts.py +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/src/rootfig/model/systematics.py +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/src/rootfig/model/units.py +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/src/rootfig/plotting/__init__.py +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/src/rootfig/plotting/annotations.py +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/src/rootfig/plotting/correlation.py +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/src/rootfig/plotting/figure.py +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/src/rootfig/plotting/hist1d.py +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/src/rootfig/plotting/hist2d.py +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/src/rootfig/plotting/points.py +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/src/rootfig/plotting/ratio.py +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/src/rootfig/plotting/result.py +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/src/rootfig/plotting/style.py +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/src/rootfig/py.typed +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/src/rootfig/selection/__init__.py +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/src/rootfig/selection/columns.py +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/tests/conftest.py +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/tests/data/split_collection.root +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/tests/test_expressions.py +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/tests/test_gallery.py +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/tests/test_io.py +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/tests/test_selection.py +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/tests/test_tutorials.py +0 -0
- {rootfig-0.4.0 → rootfig-0.5.0}/tests/type_checks/systematics.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: rootfig
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.0
|
|
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
6
|
Project-URL: Documentation, https://jbeirer.github.io/rootfig/
|
|
@@ -56,7 +56,7 @@ mem = rf.Sample({"x": awkward_array, "w": weights}, label="in memory")
|
|
|
56
56
|
([`Systematic.samples`][rootfig.Systematic]). Sources with
|
|
57
57
|
the same name are correlated across samples; see
|
|
58
58
|
[Systematic uncertainties](plotting.md#systematic-uncertainties).
|
|
59
|
-
- `sample.
|
|
59
|
+
- `sample.replace(label="...")` returns a copy with the given fields changed; new values are
|
|
60
60
|
validated like constructor arguments.
|
|
61
61
|
|
|
62
62
|
Passing a list of files to `plot()` creates one sample per file. To merge
|
|
@@ -113,7 +113,8 @@ Pre-filled histograms take variations directly and are drawn the same way:
|
|
|
113
113
|
[`sum_histograms`][rootfig.histograms.sum_histograms] work on them too.
|
|
114
114
|
|
|
115
115
|
Use `(h_up, None)` for a mirrored variation. `Sample.systematics` and
|
|
116
|
-
`Histogram.variations` are read-only;
|
|
116
|
+
`Histogram.variations` are read-only; `sample.replace(systematics=...)` and
|
|
117
|
+
`histogram.replace(variations=...)` return copies with other ones.
|
|
117
118
|
|
|
118
119
|
## Luminosity
|
|
119
120
|
|
|
@@ -231,7 +231,7 @@ def stack_data(mc: list[rf.Sample], data: rf.Sample, pt: rf.Variable, style: rf.
|
|
|
231
231
|
"Systematic uncertainties in a stack and its ratio panel",
|
|
232
232
|
section=SIMULATION_AND_DATA,
|
|
233
233
|
)
|
|
234
|
-
def systematics(
|
|
234
|
+
def systematics(signal: rf.Sample, data: rf.Sample, met: rf.Variable, style: rf.Style) -> rf.Plot:
|
|
235
235
|
"""A sample lists its sources of systematic uncertainty by name: a pair of weight
|
|
236
236
|
expressions, a relative normalisation uncertainty, or a mapping of shifted branches,
|
|
237
237
|
which also move the selection. ``systematics=`` on the plot adds a
|
|
@@ -239,15 +239,24 @@ def systematics(mc: list[rf.Sample], data: rf.Sample, met: rf.Variable, style: r
|
|
|
239
239
|
statistical and systematic uncertainties; a source with the same name in several
|
|
240
240
|
samples is correlated, different sources add in quadrature. ``p.uncertainty()``
|
|
241
241
|
returns every component."""
|
|
242
|
-
zjets, diboson, signal = mc
|
|
243
242
|
jes = {"MET": ("MET_jesUp", "MET_jesDown")}
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
243
|
+
zjets = rf.Sample(
|
|
244
|
+
"background.root",
|
|
245
|
+
tree="events",
|
|
246
|
+
label="Z + jets",
|
|
247
|
+
weight="weight",
|
|
248
|
+
systematics={"pileup": ("weight_pu_up", "weight_pu_down"), "jes": jes},
|
|
249
|
+
)
|
|
250
|
+
diboson = rf.Sample(
|
|
251
|
+
"diboson.root",
|
|
252
|
+
tree="events",
|
|
253
|
+
label="Diboson",
|
|
254
|
+
weight="weight",
|
|
255
|
+
scale=0.15,
|
|
256
|
+
systematics={"jes": jes, "xsec": 0.10},
|
|
257
|
+
)
|
|
249
258
|
return rf.plot(
|
|
250
|
-
|
|
259
|
+
[zjets, diboson, signal],
|
|
251
260
|
met,
|
|
252
261
|
observed=data,
|
|
253
262
|
stack=True,
|
|
@@ -272,9 +281,9 @@ def ratio_reference(
|
|
|
272
281
|
stays visible on light and dark pages."""
|
|
273
282
|
return rf.plot(
|
|
274
283
|
[
|
|
275
|
-
zjets.
|
|
276
|
-
diboson.
|
|
277
|
-
signal.
|
|
284
|
+
zjets.replace(color=plt.rcParams["text.color"], histtype="errorbar"),
|
|
285
|
+
diboson.replace(color="#d95f02"),
|
|
286
|
+
signal.replace(color="#1b9e77", histtype="fill"),
|
|
278
287
|
],
|
|
279
288
|
rf.Variable("nJet", bins=(9, -0.5, 8.5), label="Jet multiplicity"),
|
|
280
289
|
normalize=True,
|
|
@@ -413,12 +422,12 @@ def density_flow(
|
|
|
413
422
|
def object_vs_event(signal: rf.Sample, pt: rf.Variable, style: rf.Style) -> rf.Plot:
|
|
414
423
|
"""``Muon_pt`` is a list per event. A per-object cut such as ``Muon_pt > 100`` masks
|
|
415
424
|
individual muons, while ``any(Muon_pt > 100)`` is per event: it keeps whole events, with all
|
|
416
|
-
their muons, soft ones included. ``Sample.
|
|
425
|
+
their muons, soft ones included. ``Sample.replace`` derives variants of a sample."""
|
|
417
426
|
return rf.plot(
|
|
418
427
|
[
|
|
419
|
-
signal.
|
|
420
|
-
signal.
|
|
421
|
-
signal.
|
|
428
|
+
signal.replace(label="All muons"),
|
|
429
|
+
signal.replace(label="Muon_pt > 100", selection="Muon_pt > 100"),
|
|
430
|
+
signal.replace(label="any(Muon_pt > 100)", selection="any(Muon_pt > 100)"),
|
|
422
431
|
],
|
|
423
432
|
pt,
|
|
424
433
|
logy=True,
|
|
@@ -433,12 +442,12 @@ def expressions(signal: rf.Sample, pt: rf.Variable, style: rf.Style) -> rf.Plot:
|
|
|
433
442
|
``rf.histogram`` returns a plain ``hist.Hist``; ``rf.plot_histograms`` draws any collection
|
|
434
443
|
of them with the usual options."""
|
|
435
444
|
all_muons = rf.histogram(signal, pt)
|
|
436
|
-
leading = rf.histogram(signal, pt.
|
|
437
|
-
momentum = rf.histogram(signal, pt.
|
|
445
|
+
leading = rf.histogram(signal, pt.replace(expression="first(Muon_pt)"))
|
|
446
|
+
momentum = rf.histogram(signal, pt.replace(expression="Muon_pt * cosh(Muon_eta)"))
|
|
438
447
|
return rf.plot_histograms(
|
|
439
448
|
[all_muons, leading, momentum],
|
|
440
449
|
labels=["All muons", "Leading muon", r"Muon $|\vec{p}|$"],
|
|
441
|
-
variable=pt.
|
|
450
|
+
variable=pt.replace(label=r"$p_T^{\mu}$ or $|\vec{p}^{\,\mu}|$"),
|
|
442
451
|
logy=True,
|
|
443
452
|
style=style,
|
|
444
453
|
)
|
|
@@ -54,7 +54,7 @@ from rootfig.histograms import (
|
|
|
54
54
|
from rootfig.model import Cut, Sample, Style, Systematic, Variable, log_bins
|
|
55
55
|
from rootfig.plotting import Plot, dark_theme, use_style
|
|
56
56
|
|
|
57
|
-
__version__ = "0.
|
|
57
|
+
__version__ = "0.5.0"
|
|
58
58
|
|
|
59
59
|
__all__ = [
|
|
60
60
|
"BinningError",
|
|
@@ -40,12 +40,12 @@ def style_for(
|
|
|
40
40
|
"""Resolve ``style`` and add free text lines and the luminosity used for scaling."""
|
|
41
41
|
resolved = as_style(style)
|
|
42
42
|
if lumi is not None and resolved.lumi is None:
|
|
43
|
-
resolved = resolved.
|
|
43
|
+
resolved = resolved.replace(lumi=lumi)
|
|
44
44
|
if text is None:
|
|
45
45
|
return resolved
|
|
46
46
|
existing = list(resolved.text_lines)
|
|
47
47
|
extra = [text] if isinstance(text, str) else list(text)
|
|
48
|
-
return resolved.
|
|
48
|
+
return resolved.replace(text=[*existing, *extra])
|
|
49
49
|
|
|
50
50
|
|
|
51
51
|
def normalize_for_plot(histogram_: Histogram, spec: NormalizeSpec) -> Histogram:
|
|
@@ -167,7 +167,7 @@ def histogram(
|
|
|
167
167
|
... ) # doctest: +SKIP
|
|
168
168
|
>>> h.values().sum() # doctest: +SKIP
|
|
169
169
|
"""
|
|
170
|
-
samples = [sample.
|
|
170
|
+
samples = [sample.replace(systematics={}) for sample in as_samples(data, tree=tree)]
|
|
171
171
|
results = histograms(
|
|
172
172
|
samples,
|
|
173
173
|
variable,
|
|
@@ -95,13 +95,13 @@ def efficiency(
|
|
|
95
95
|
... ) # doctest: +SKIP
|
|
96
96
|
"""
|
|
97
97
|
# efficiencies are statistical only: systematics are neither evaluated nor needed
|
|
98
|
-
samples = [s.
|
|
98
|
+
samples = [s.replace(systematics={}) for s in as_samples(data, tree=tree, labels=label)]
|
|
99
99
|
var = as_variable(variable, bins=bins, range=range, label=xlabel, unit=unit)
|
|
100
100
|
logx = var.log if logx is None else logx
|
|
101
101
|
totals = build_histograms(
|
|
102
102
|
samples, var, selection=selection, weight=weight, lumi=lumi, nonfinite=nonfinite
|
|
103
103
|
)
|
|
104
|
-
fixed = var.
|
|
104
|
+
fixed = var.replace(bins=totals[0].axis) # same binning for the numerators
|
|
105
105
|
pass_cut = as_cut(passed)
|
|
106
106
|
if pass_cut is None:
|
|
107
107
|
msg = "efficiency() needs a 'passed' selection"
|
|
@@ -117,7 +117,7 @@ def efficiency(
|
|
|
117
117
|
]
|
|
118
118
|
resolved_style = style_for(style, text, lumi)
|
|
119
119
|
if legend is not None:
|
|
120
|
-
resolved_style = resolved_style.
|
|
120
|
+
resolved_style = resolved_style.replace(legend=legend)
|
|
121
121
|
with style_context(resolved_style) as st:
|
|
122
122
|
layout = make_figure(st, ratio=False, ax=ax, figsize=figsize)
|
|
123
123
|
cycle = iter(color_cycle(len(samples), st))
|
|
@@ -249,7 +249,7 @@ def profile(
|
|
|
249
249
|
]
|
|
250
250
|
resolved_style = style_for(style, text, lumi)
|
|
251
251
|
if legend is not None:
|
|
252
|
-
resolved_style = resolved_style.
|
|
252
|
+
resolved_style = resolved_style.replace(legend=legend)
|
|
253
253
|
if ylabel is None:
|
|
254
254
|
ylabel = var_y.axis_label if statistic == "mean" else f"Std. dev. of {var_y.axis_label}"
|
|
255
255
|
with style_context(resolved_style) as st:
|
|
@@ -260,7 +260,7 @@ def profile(
|
|
|
260
260
|
finish_axes(
|
|
261
261
|
layout.main,
|
|
262
262
|
data_range=(low, high),
|
|
263
|
-
xlabel=var_x.
|
|
263
|
+
xlabel=var_x.replace(bins=axis).axis_label,
|
|
264
264
|
ylabel=ylabel,
|
|
265
265
|
xlim=xlim or (float(edges[0]), float(edges[-1])),
|
|
266
266
|
ylim=ylim,
|
|
@@ -231,7 +231,7 @@ def plot(
|
|
|
231
231
|
samples = as_samples(data, tree=tree, labels=label)
|
|
232
232
|
if observed is not None:
|
|
233
233
|
observed_samples = [
|
|
234
|
-
s if s.is_data else s.
|
|
234
|
+
s if s.is_data else s.replace(is_data=True) for s in as_samples(observed, tree=tree)
|
|
235
235
|
]
|
|
236
236
|
samples = [*samples, *observed_samples]
|
|
237
237
|
var = as_variable(variable, bins=bins, range=range, label=xlabel, unit=unit)
|
|
@@ -335,7 +335,7 @@ def plot_histograms(
|
|
|
335
335
|
histograms_ = [normalize_for_plot(h, normalize) for h in histograms_]
|
|
336
336
|
resolved_style = as_style(style)
|
|
337
337
|
if legend is not None:
|
|
338
|
-
resolved_style = resolved_style.
|
|
338
|
+
resolved_style = resolved_style.replace(legend=legend)
|
|
339
339
|
|
|
340
340
|
# The y label quotes the bin width of the histogram as filled, before flow bins are added.
|
|
341
341
|
label_widths = histograms_[0].widths
|
|
@@ -559,7 +559,7 @@ def _wrap_hists(
|
|
|
559
559
|
wrapped: list[Histogram] = []
|
|
560
560
|
for index, item in enumerate(hists):
|
|
561
561
|
if isinstance(item, Histogram):
|
|
562
|
-
wrapped.append(item if labels is None else item.
|
|
562
|
+
wrapped.append(item if labels is None else item.replace(label=labels[index]))
|
|
563
563
|
continue
|
|
564
564
|
if labels is not None:
|
|
565
565
|
label = labels[index]
|
|
@@ -147,7 +147,7 @@ class Histogram:
|
|
|
147
147
|
up shift around the nominal contents. Summarised by
|
|
148
148
|
:func:`~rootfig.histograms.uncertainty`. The mapping is copied and made
|
|
149
149
|
read-only; every stored pair contains two histograms. Use
|
|
150
|
-
``histogram.
|
|
150
|
+
``histogram.replace(variations=...)`` to replace it. The underlying
|
|
151
151
|
``hist.Hist`` objects remain mutable. Observed data (``is_data``) cannot
|
|
152
152
|
carry variations, as for :class:`~rootfig.model.Sample`.
|
|
153
153
|
"""
|
|
@@ -307,8 +307,8 @@ class Histogram:
|
|
|
307
307
|
"""
|
|
308
308
|
return None if self.stats is None else self.stats.entries
|
|
309
309
|
|
|
310
|
-
def
|
|
311
|
-
"""Return a copy with the given fields
|
|
310
|
+
def replace(self, **changes: Any) -> Histogram:
|
|
311
|
+
"""Return a copy with the given fields changed, e.g. ``h.replace(label="B")``."""
|
|
312
312
|
return replace(self, **changes)
|
|
313
313
|
|
|
314
314
|
def map_hists(self, transform: Callable[[Hist], Hist]) -> Histogram:
|
|
@@ -154,7 +154,7 @@ def normalize(histogram: Histogram, spec: NormalizeSpec) -> Histogram:
|
|
|
154
154
|
return histogram
|
|
155
155
|
result, applied = _normalize_hist(histogram.hist, spec)
|
|
156
156
|
if not applied:
|
|
157
|
-
return histogram.
|
|
157
|
+
return histogram.replace(hist=result, normalization=None)
|
|
158
158
|
label = normalization_label(spec)
|
|
159
159
|
variations = {}
|
|
160
160
|
for name, pair in histogram.variations.items():
|
|
@@ -169,7 +169,7 @@ def normalize(histogram: Histogram, spec: NormalizeSpec) -> Histogram:
|
|
|
169
169
|
raise SystematicError(msg)
|
|
170
170
|
normalized.append(shifted)
|
|
171
171
|
variations[name] = (normalized[0], normalized[1])
|
|
172
|
-
return histogram.
|
|
172
|
+
return histogram.replace(hist=result, normalization=label, variations=variations)
|
|
173
173
|
|
|
174
174
|
|
|
175
175
|
def normalization_label(spec: NormalizeSpec) -> str | None:
|
|
@@ -384,7 +384,7 @@ def _variant_sample(sample: Sample, spec: Any, context: str) -> Sample:
|
|
|
384
384
|
nominal sample's resolved number of generated events; files read their own.
|
|
385
385
|
"""
|
|
386
386
|
if isinstance(spec, Sample):
|
|
387
|
-
return spec.
|
|
387
|
+
return spec.replace(label=context)
|
|
388
388
|
nominal = sample.source
|
|
389
389
|
try:
|
|
390
390
|
if isinstance(nominal, FileSource | ArraySource) and (
|
|
@@ -413,7 +413,7 @@ def _variant_sample(sample: Sample, spec: Any, context: str) -> Sample:
|
|
|
413
413
|
and not callable(getattr(source, "read_scalar", None))
|
|
414
414
|
):
|
|
415
415
|
changes["ngen"] = sample.generated_events()
|
|
416
|
-
return sample.
|
|
416
|
+
return sample.replace(**changes)
|
|
417
417
|
|
|
418
418
|
|
|
419
419
|
def _is_file_spec(spec: Any) -> bool:
|
|
@@ -77,7 +77,7 @@ class Sample:
|
|
|
77
77
|
``Systematic.samples(...)`` for varied files. Sources
|
|
78
78
|
with the same name in several samples are fully correlated; different
|
|
79
79
|
names are independent. Not allowed together with ``is_data=True``. The mapping is copied and
|
|
80
|
-
made read-only; use ``sample.
|
|
80
|
+
made read-only; use ``sample.replace(systematics=...)`` to change it.
|
|
81
81
|
|
|
82
82
|
Examples
|
|
83
83
|
--------
|
|
@@ -198,10 +198,10 @@ class Sample:
|
|
|
198
198
|
"""The resolved input files, or an empty tuple for in-memory sources."""
|
|
199
199
|
return self.source.files if isinstance(self.source, FileSource) else ()
|
|
200
200
|
|
|
201
|
-
def
|
|
202
|
-
"""Return a copy with the given fields
|
|
201
|
+
def replace(self, **changes: Any) -> Sample:
|
|
202
|
+
"""Return a copy with the given fields changed, e.g. ``sample.replace(label="B")``.
|
|
203
203
|
|
|
204
|
-
|
|
204
|
+
New values are validated and normalised exactly as by the
|
|
205
205
|
constructor (``selection`` accepts a string, ``source`` anything
|
|
206
206
|
:func:`~rootfig.io.as_source` accepts, ``scale`` must be finite, ...).
|
|
207
207
|
"""
|
|
@@ -222,7 +222,7 @@ class Sample:
|
|
|
222
222
|
return clone
|
|
223
223
|
|
|
224
224
|
|
|
225
|
-
# -- field validation shared by the constructor and
|
|
225
|
+
# -- field validation shared by the constructor and replace() ---------------------------------
|
|
226
226
|
|
|
227
227
|
|
|
228
228
|
def _normalise_weight(weight: str | None, label: str) -> str | None:
|
|
@@ -319,7 +319,7 @@ def as_samples(
|
|
|
319
319
|
samples = [data]
|
|
320
320
|
elif isinstance(data, Mapping) and _looks_like_label_map(data):
|
|
321
321
|
samples = [
|
|
322
|
-
value.
|
|
322
|
+
value.replace(label=key)
|
|
323
323
|
if isinstance(value, Sample)
|
|
324
324
|
else Sample(value, tree=tree, label=key, entry_start=entry_start, entry_stop=entry_stop)
|
|
325
325
|
for key, value in data.items()
|
|
@@ -342,7 +342,7 @@ def as_samples(
|
|
|
342
342
|
if len(label_list) != len(samples):
|
|
343
343
|
msg = f"got {len(label_list)} labels for {len(samples)} samples"
|
|
344
344
|
raise SourceError(msg)
|
|
345
|
-
samples = [s.
|
|
345
|
+
samples = [s.replace(label=lab) for s, lab in zip(samples, label_list, strict=True)]
|
|
346
346
|
return samples
|
|
347
347
|
|
|
348
348
|
|
|
@@ -115,8 +115,8 @@ class Style:
|
|
|
115
115
|
return tuple(self.text.split("\n"))
|
|
116
116
|
return tuple(self.text)
|
|
117
117
|
|
|
118
|
-
def
|
|
119
|
-
"""Return a copy with the given fields
|
|
118
|
+
def replace(self, **changes: Any) -> Style:
|
|
119
|
+
"""Return a copy with the given fields changed, e.g. ``style.replace(lumi=140)``."""
|
|
120
120
|
return replace(self, **changes)
|
|
121
121
|
|
|
122
122
|
|
|
@@ -91,8 +91,8 @@ class Variable:
|
|
|
91
91
|
base = self.label if self.label is not None else self.expression
|
|
92
92
|
return f"{base} [{self.unit}]" if self.unit else base
|
|
93
93
|
|
|
94
|
-
def
|
|
95
|
-
"""Return a copy with the given fields
|
|
94
|
+
def replace(self, **changes: Any) -> Variable:
|
|
95
|
+
"""Return a copy with the given fields changed, e.g. ``var.replace(bins=20)``."""
|
|
96
96
|
return replace(self, **changes)
|
|
97
97
|
|
|
98
98
|
|
|
@@ -975,7 +975,9 @@ class TestFigureShape:
|
|
|
975
975
|
[narrow_name] = [t for t in narrow.ax.texts if isinstance(t, hep.label.ExpLabel)]
|
|
976
976
|
assert narrow_name.get_fontsize() < wide_name.get_fontsize()
|
|
977
977
|
# an explicit position inside the frame is kept for 2D plots too
|
|
978
|
-
inside = rf.plot2d(
|
|
978
|
+
inside = rf.plot2d(
|
|
979
|
+
signal_file, "MET", "nMuon", tree="events", style=cms.replace(label_loc=1)
|
|
980
|
+
)
|
|
979
981
|
inside.fig.canvas.draw()
|
|
980
982
|
renderer = inside.fig.canvas.get_renderer() # type: ignore[attr-defined]
|
|
981
983
|
[name] = [t for t in inside.ax.texts if isinstance(t, hep.label.ExpLabel)]
|
|
@@ -98,7 +98,7 @@ class TestHistogram:
|
|
|
98
98
|
scaled = histogram.scaled(2.0)
|
|
99
99
|
assert scaled.values().tolist() == [4.0, 4.0, 2.0]
|
|
100
100
|
assert scaled.variances().tolist() == [8.0, 16.0, 4.0]
|
|
101
|
-
assert histogram.
|
|
101
|
+
assert histogram.replace(label="x").label == "x"
|
|
102
102
|
|
|
103
103
|
def test_scaled_keeps_statistics_consistent(self, histogram: Histogram) -> None:
|
|
104
104
|
assert histogram.stats is not None
|
|
@@ -1026,13 +1026,13 @@ class TestVariations:
|
|
|
1026
1026
|
del histogram.variations["shape"] # type: ignore[attr-defined]
|
|
1027
1027
|
with pytest.raises(TypeError):
|
|
1028
1028
|
Histogram(nominal, "MC").variations["new"] = (up, up) # type: ignore[index]
|
|
1029
|
-
changed = histogram.
|
|
1029
|
+
changed = histogram.replace(variations={"norm": (nominal * 1.1, None)})
|
|
1030
1030
|
assert list(changed.variations) == ["norm"]
|
|
1031
1031
|
assert list(histogram.variations) == ["shape"]
|
|
1032
1032
|
with pytest.raises(TypeError):
|
|
1033
1033
|
changed.variations["new"] = (up, up) # type: ignore[index]
|
|
1034
1034
|
with pytest.raises(SystematicError, match="binning"):
|
|
1035
|
-
histogram.
|
|
1035
|
+
histogram.replace(variations={"bad": (contents([1.0]), None)})
|
|
1036
1036
|
|
|
1037
1037
|
@pytest.mark.parametrize("operation", ["copy", "deepcopy", "pickle"])
|
|
1038
1038
|
def test_variations_support_copy_and_pickle(self, operation: str) -> None:
|
|
@@ -1057,7 +1057,7 @@ class TestVariations:
|
|
|
1057
1057
|
histogram = Histogram(
|
|
1058
1058
|
nominal, "MC", sample, stats, False, "red", "step", "unity", {"s": (nominal, None)}
|
|
1059
1059
|
)
|
|
1060
|
-
changed = histogram.
|
|
1060
|
+
changed = histogram.replace(label="renamed")
|
|
1061
1061
|
assert changed.label == "renamed"
|
|
1062
1062
|
assert changed.sample is sample
|
|
1063
1063
|
assert changed.stats is stats
|
|
@@ -1095,8 +1095,8 @@ class TestVariations:
|
|
|
1095
1095
|
Histogram(nominal, "Data", is_data=True, variations={"s": (nominal, None)})
|
|
1096
1096
|
simulated = Histogram(nominal, "MC", variations={"s": (nominal, None)})
|
|
1097
1097
|
with pytest.raises(SystematicError, match="observed data"):
|
|
1098
|
-
simulated.
|
|
1099
|
-
assert simulated.
|
|
1098
|
+
simulated.replace(is_data=True)
|
|
1099
|
+
assert simulated.replace(is_data=True, variations={}).is_data
|
|
1100
1100
|
|
|
1101
1101
|
def test_down_is_mirrored_and_binning_checked(self) -> None:
|
|
1102
1102
|
nominal = contents([10.0, 20.0])
|
|
@@ -1264,7 +1264,7 @@ class TestSystematicsPipeline:
|
|
|
1264
1264
|
np.testing.assert_allclose(hists[0].variations["lumi"][0].values(), 1.5 * hists[0].values())
|
|
1265
1265
|
assert hists[1].variations == {}
|
|
1266
1266
|
with pytest.raises(SystematicError, match="observed data"):
|
|
1267
|
-
build_histograms([data.
|
|
1267
|
+
build_histograms([data.replace(systematics={"s": 0.1})], "x")
|
|
1268
1268
|
|
|
1269
1269
|
def test_binning_from_nominal_and_single_read(self, arrays: dict[str, Any]) -> None:
|
|
1270
1270
|
sample = Sample(
|
|
@@ -1471,7 +1471,7 @@ class TestSystematicsRegressions:
|
|
|
1471
1471
|
with pytest.raises(MissingBranchError, match="pi"):
|
|
1472
1472
|
build_histograms([sample], Variable("x", bins=(2, 0, 2)))
|
|
1473
1473
|
# A name resolving to a mathematical constant is not a branch to replace.
|
|
1474
|
-
sample = sample.
|
|
1474
|
+
sample = sample.replace(systematics={"s": {"pi": "missing"}})
|
|
1475
1475
|
(h,) = build_histograms([sample], Variable("pi", bins=(4, 0, 4)))
|
|
1476
1476
|
np.testing.assert_allclose(h.variations["s"][0].values(), h.values())
|
|
1477
1477
|
|
|
@@ -82,7 +82,7 @@ class TestVariable:
|
|
|
82
82
|
var = Variable("Muon_pt / 1000", label=r"$p_T$", unit="GeV")
|
|
83
83
|
assert var.axis_label == r"$p_T$ [GeV]"
|
|
84
84
|
assert var.safe_name == "Muon_pt_1000"
|
|
85
|
-
assert var.
|
|
85
|
+
assert var.replace(name="pt").safe_name == "pt"
|
|
86
86
|
|
|
87
87
|
def test_invalid_expression(self) -> None:
|
|
88
88
|
with pytest.raises(ExpressionError):
|
|
@@ -117,7 +117,7 @@ class TestVariable:
|
|
|
117
117
|
with pytest.raises(ValueError, match="path separators"):
|
|
118
118
|
Variable("x", name=name)
|
|
119
119
|
with pytest.raises(ValueError, match="path separators"):
|
|
120
|
-
Variable("x").
|
|
120
|
+
Variable("x").replace(name=name)
|
|
121
121
|
|
|
122
122
|
def test_name_keeps_plain_stems(self) -> None:
|
|
123
123
|
assert Variable("x", name="pt-lead.window").safe_name == "pt-lead.window"
|
|
@@ -442,7 +442,7 @@ class TestSample:
|
|
|
442
442
|
|
|
443
443
|
def test_with(self, signal_file: Path) -> None:
|
|
444
444
|
sample = Sample(signal_file, tree="events")
|
|
445
|
-
other = sample.
|
|
445
|
+
other = sample.replace(label="new", selection="MET > 1")
|
|
446
446
|
assert other.label == "new"
|
|
447
447
|
assert other.selection == Cut("MET > 1")
|
|
448
448
|
assert other.source is sample.source
|
|
@@ -450,21 +450,21 @@ class TestSample:
|
|
|
450
450
|
def test_with_validates_like_init(self) -> None:
|
|
451
451
|
sample = Sample({"x": np.arange(2.0)})
|
|
452
452
|
with pytest.raises(ValueError, match="scale must be"):
|
|
453
|
-
sample.
|
|
453
|
+
sample.replace(scale=np.nan)
|
|
454
454
|
with pytest.raises(LuminosityError, match="finite"):
|
|
455
|
-
sample.
|
|
455
|
+
sample.replace(ngen=np.inf)
|
|
456
456
|
with pytest.raises(LuminosityError):
|
|
457
|
-
sample.
|
|
457
|
+
sample.replace(xsec="bad")
|
|
458
458
|
with pytest.raises(SourceError, match="cannot interpret"):
|
|
459
|
-
sample.
|
|
459
|
+
sample.replace(source=42)
|
|
460
460
|
with pytest.raises(TypeError, match="weight must be"):
|
|
461
|
-
sample.
|
|
461
|
+
sample.replace(weight=42)
|
|
462
462
|
with pytest.raises(TypeError, match="label must be"):
|
|
463
|
-
sample.
|
|
464
|
-
assert sample.
|
|
465
|
-
assert sample.
|
|
466
|
-
assert sample.
|
|
467
|
-
assert sample.
|
|
463
|
+
sample.replace(label=3)
|
|
464
|
+
assert sample.replace(weight=" ").weight is None
|
|
465
|
+
assert sample.replace(scale=2).scale == 2.0
|
|
466
|
+
assert sample.replace(source=sample.source).source is sample.source
|
|
467
|
+
assert sample.replace(xsec="1.2 fb").xsec == "1.2 fb"
|
|
468
468
|
|
|
469
469
|
def test_existing_source_rejects_entry_range(self, signal_file: Path) -> None:
|
|
470
470
|
source = FileSource(signal_file, tree="events")
|
|
@@ -531,7 +531,7 @@ class TestStyle:
|
|
|
531
531
|
assert as_style("ggplot") == Style(base="ggplot")
|
|
532
532
|
style = Style(lumi=140)
|
|
533
533
|
assert as_style(style) is style
|
|
534
|
-
assert style.
|
|
534
|
+
assert style.replace(com=13.6).com == 13.6
|
|
535
535
|
with pytest.raises(TypeError):
|
|
536
536
|
as_style(3) # type: ignore[arg-type]
|
|
537
537
|
|
|
@@ -742,10 +742,12 @@ class TestSystematic:
|
|
|
742
742
|
sample = Sample({"x": [1.0, 2.0]}, label="S", systematics={"n": 0.1})
|
|
743
743
|
assert sample.systematics == {"n": Systematic("norm", 1.1, 0.9)}
|
|
744
744
|
assert "systematics=['n']" in repr(sample)
|
|
745
|
-
assert sample.
|
|
745
|
+
assert sample.replace(systematics={"w": "x"}).systematics == {
|
|
746
|
+
"w": Systematic("weight", "x")
|
|
747
|
+
}
|
|
746
748
|
assert Sample({"x": [1.0]}).systematics == {}
|
|
747
749
|
with pytest.raises(SystematicError, match="sample 'S': systematic 'bad'"):
|
|
748
|
-
sample.
|
|
750
|
+
sample.replace(systematics={"bad": object()})
|
|
749
751
|
|
|
750
752
|
@pytest.mark.parametrize(
|
|
751
753
|
("kind", "up", "down"),
|
|
@@ -787,12 +789,12 @@ class TestSystematic:
|
|
|
787
789
|
Sample(columns, is_data=True, systematics={"s": 0.1})
|
|
788
790
|
data = Sample(columns, is_data=True, systematics={}) # an empty mapping is fine
|
|
789
791
|
with pytest.raises(SystematicError, match="observed data"):
|
|
790
|
-
data.
|
|
792
|
+
data.replace(systematics={"s": 0.1})
|
|
791
793
|
mc = Sample(columns, systematics={"s": 0.1})
|
|
792
794
|
with pytest.raises(SystematicError, match="observed data"):
|
|
793
|
-
mc.
|
|
794
|
-
assert mc.
|
|
795
|
-
assert data.
|
|
795
|
+
mc.replace(is_data=True)
|
|
796
|
+
assert mc.replace(is_data=True, systematics={}).is_data
|
|
797
|
+
assert data.replace(is_data=False, systematics={"s": 0.1}).systematics
|
|
796
798
|
|
|
797
799
|
def test_systematic_mappings_are_read_only_snapshots(self) -> None:
|
|
798
800
|
branches = {"x": ("x_up", "x_down")}
|
|
@@ -812,7 +814,7 @@ class TestSystematic:
|
|
|
812
814
|
with pytest.raises(TypeError):
|
|
813
815
|
Sample({"x": [1.0]}).systematics["extra"] = systematic # type: ignore[index]
|
|
814
816
|
|
|
815
|
-
updated = sample.
|
|
817
|
+
updated = sample.replace(systematics={"norm": 0.1})
|
|
816
818
|
assert list(updated.systematics) == ["norm"]
|
|
817
819
|
assert list(sample.systematics) == ["shape"]
|
|
818
820
|
with pytest.raises(TypeError):
|
|
@@ -1220,7 +1220,7 @@ class TestHist2DMask:
|
|
|
1220
1220
|
|
|
1221
1221
|
|
|
1222
1222
|
def with_variation(histogram: Histogram, factor: float) -> Histogram:
|
|
1223
|
-
return histogram.
|
|
1223
|
+
return histogram.replace(variations={"s": (histogram.hist * factor, None)})
|
|
1224
1224
|
|
|
1225
1225
|
|
|
1226
1226
|
class TestSystematicDrawing:
|
|
@@ -1251,7 +1251,7 @@ class TestSystematicDrawing:
|
|
|
1251
1251
|
def test_flow_bins_carry_variations(self) -> None:
|
|
1252
1252
|
nominal = make_hist([1.5, 5.0], label="A") # 5.0 is overflow
|
|
1253
1253
|
up = make_hist([-1.0, 1.5], label="up") # underflow only in the variation
|
|
1254
|
-
varied = nominal.
|
|
1254
|
+
varied = nominal.replace(variations={"s": (up.hist, None)})
|
|
1255
1255
|
(shown,), (under, over) = show_flow_bins([varied])
|
|
1256
1256
|
assert (under, over) == (True, True)
|
|
1257
1257
|
np.testing.assert_allclose(shown.variations["s"][0].values(), [1, 0, 1, 0, 0, 0])
|
|
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
|