Conversation
There was a problem hiding this comment.
Pull request overview
This PR introduces a redesigned, pure-Python PlotKit package that preserves the legacy FLAF Plotter API and YAML configuration vocabulary while adding a standalone workflow. It provides a default matplotlib/mplhep renderer with an optional ROOT/cmsstyle backend, plus new signal scaling behavior (including “norm to bkg”) and accompanying tests/examples.
Changes:
- Added engine-neutral plotting spec + layered architecture (config/hist/spec/plotters/backends) with a legacy-compatible
Plotterfacade. - Implemented standalone CLI that can render directly from ROOT files via uproot, including auto-discovery of processes.
- Added pytest coverage for ROOT-compat translation, config merging, CLI discovery/rendering, and signal→background normalization.
Reviewed changes
Copilot reviewed 21 out of 23 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
tests/test_smoke.py |
Smoke tests for PDF/PNG rendering, signal scaling-to-bkg behavior, and optional cmsstyle backend. |
tests/test_rootcompat.py |
Unit tests for ROOT color/TLatex/font/bin parsing and mathtext-parse safety. |
tests/test_config.py |
Tests for legacy config merge behavior and backend selection via env var. |
tests/test_cli.py |
Tests CLI auto-discovery classification/selection and end-to-end rendering from nested files. |
tests/conftest.py |
Adjusts sys.path so PlotKit imports work from a checkout during tests. |
spec.py |
Defines engine-neutral plot specification dataclasses (StackSpec, entries, uncertainty band). |
rootcompat.py |
Translates ROOT-flavored config vocabulary (colors, TLatex, styles, bins) to matplotlib equivalents. |
requirements.txt |
Declares core runtime dependencies for the default (mplhep) backend. |
README.md |
Documents installation, CLI usage (explicit map + auto-discovery), API usage, and architecture. |
pyproject.toml |
Defines package metadata, dependencies, optional extras, console script, and packaging layout. |
plotters/stacked.py |
Implements the backward-compatible stacked plot style and signal scaling options (incl. bkg). |
plotters/base.py |
Base plotter class wiring config + backend selection. |
plotters/__init__.py |
Plot-style registry and style lookup helper. |
Plotter.py |
Legacy-compatible Plotter facade matching FLAF’s import/usage patterns. |
histogram.py |
Introduces Hist1D and adapters from ROOT TH1, uproot histograms, and numpy. |
examples/demo_standalone.py |
Minimal runnable example rendering synthetic histograms without FLAF/ROOT. |
examples/config/era_Run3_2022.yaml |
Example era override config (lumi/channel/region labels). |
examples/config/cms_stacked.yaml |
Example legacy-style stacked plotting configuration. |
config.py |
Loads/merges legacy YAML configs and provides accessors + backend selection. |
cli.py |
Standalone CLI entry point and histogram discovery/loading logic. |
backends.py |
Implements mplhep backend and optional cmsstyle backend with fallback behavior. |
.gitignore |
Adds common Python/build artifacts and plot outputs to ignore list. |
__init__.py |
Package metadata and curated exports while preserving legacy Plotter submodule semantics. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+20
to
+22
| def __init__(self, config: PlotConfig, backend: Optional[StyleBackend] = None): | ||
| self.config = config | ||
| self.backend = backend or get_backend(config.backend_name()) |
Comment on lines
+73
to
+87
| with open(inputs_cfg, "r") as f: | ||
| inputs = yaml.safe_load(f) | ||
|
|
||
| prefix = f"{path.strip('/')}/" if path else "" | ||
| histograms = {} | ||
| with uproot.open(input_file) as f: | ||
| for entry in inputs: | ||
| name = entry["name"] | ||
| # Accept a nested "<path>/<name>", a "<name>/<hist_name>" layout, or a flat object. | ||
| for candidate in ( | ||
| f"{prefix}{name}", | ||
| f"{name}/{hist_name}", | ||
| name, | ||
| hist_name, | ||
| ): |
Comment on lines
+17
to
+40
|
|
||
| @dataclasses.dataclass | ||
| class HistEntry: | ||
| """One histogram to draw, with its already-resolved (engine-neutral) style.""" | ||
|
|
||
| hist: Hist1D | ||
| label: str | ||
| color: Tuple[float, float, float] = (0.5, 0.5, 0.5) | ||
| filled: bool = True | ||
| line_style: str = "-" | ||
| line_width: float = 1.0 | ||
| line_color: Optional[Tuple[float, float, float]] = None | ||
| marker: Optional[str] = None | ||
| marker_size: float = 6.0 | ||
| legend: bool = True | ||
|
|
||
|
|
||
| @dataclasses.dataclass | ||
| class UncBand: | ||
| """Style for the background-uncertainty band (drawn from the stack total).""" | ||
|
|
||
| hatch: Optional[str] = "///" | ||
| color: Tuple[float, float, float] = (0.4, 0.6, 0.6) | ||
| label: str = "Bkg. uncertainty" |
…cess hist_name fallback; widen color type hints
This was referenced Jun 29, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
From-scratch redesign of the FLAF plotting code (for cms-flaf/FLAF#171)
into a small, layered, pure-Python package. It renders CMS plots with matplotlib + mplhep by
default and optionally through ROOT + cmsstyle, replacing the legacy ROOT-C++ renderer
(
StackedPlotDescriptor.h/PdfPrinter.h/ … driven viagInterpreter).It is a transparent drop-in for FLAF — the legacy
PlotterAPI and the analysisconfig/plot/*.yamlfiles are unchanged, so only the FLAF submodule pointer moves — and it alsoruns standalone outside FLAF.
What's included
FLAF.PlotKitand standalonePlotKit):histogram.py(Hist1D+ TH1/uproot/numpy adapters),rootcompat.py(ROOT colours / TLatex /fonts /
"n|lo:hi"binning → matplotlib),config.py(loads the legacy YAML),spec.py(engine-neutral
StackSpec),backends.py(MplhepBackenddefault +CmsstyleBackend, lazy ROOTimport with fallback),
plotters/(StackedPlotter+STYLESregistry + abstractBasePlotterextension points),
Plotter.py(legacy-compatible facade),cli.py(standalone).include/headers are not carried over.inputs.yamlprocess map, or auto-discovery of a real FLAF merged file(
--path channel/region/category+--data-name/--signal-regex/--signal-select).--signal-scale bkg/signal_plot_scale: bkgnormalises each signal's integral to the summed background (shape comparison), alongside the
existing fixed-factor scaling; the legend then reads
… (norm. to bkg).Testing
pytest15/15: ROOT-compat parsing (colours / TLatex incl. a mathtext parse check / binning),config merge, smoke renders to PDF/PNG for both backends, CLI nested-file navigation +
auto-discovery, and signal→background normalisation.
all_plotshistograms (Run3_2023) through both the FLAFlaw-task plotting path (
HistPlotter.py+Run3_Model) and the standalone CLI — faithful stackedplots (CMS/lumi/channel/category/region labels,
divide_by_bin_width, stacked backgrounds +bkg-uncertainty band + scaled signals + data + Obs/Bkg ratio).
Companion PRs
issue-171-plotkit-redesign:.gitmodulesURL →cms-flaf/PlotKit, submodule pointer,mk_flaf_env.sh(+cmsstyle), docs.HistPlotter.pyunchanged.plotkit-signal-scale-to-bkg:signal_plot_scale: bkg.