cabinetry: Design and Steer Profile Likelihood Fits
cabinetry is a Python library designed for building and steering profile likelihood fits, particularly used in high-energy physics for statistical analysis. It currently stands at version 0.6.0 and maintains an active development cycle with regular patch and minor releases, often coinciding with updates to its core dependency, `pyhf`.
Common errors
-
TypeError: <function_name> missing 1 required keyword-only argument: '<arg_name>'
cause Attempting to call a cabinetry function with positional arguments after v0.4.0, where all arguments became keyword-only.fixUpdate the function call to explicitly use keyword arguments. For example, change `cabinetry.fit.fit(model, data)` to `cabinetry.fit.fit(model=model, data=data)`. -
RuntimeError: This version of cabinetry requires Python 3.8 or higher.
cause Running cabinetry v0.6.0 or newer on an unsupported Python version (e.g., Python 3.7).fixUpgrade your Python environment to version 3.8 or newer to meet the library's requirements. -
pyhf.exceptions.InvalidSpecification: model specification not valid
cause Incompatibility between the `cabinetry` version and the installed `pyhf` version, particularly if `cabinetry` v0.5.0+ is used with an older `pyhf` (<0.7.0).fixEnsure `pyhf` is updated to a compatible version, specifically `pyhf>=0.7.0` for cabinetry v0.5.0 and later (`pip install 'pyhf>=0.7.0'`). -
AttributeError: 'Figure' object has no attribute 'tight_layout' (or other plotting errors)
cause An outdated `matplotlib` version being used, which lacks features or has breaking API changes that cabinetry's visualization functions rely on.fixUpgrade `matplotlib` to at least version 3.5.0 (`pip install 'matplotlib>=3.5.0'`).
Warnings
- breaking As of cabinetry v0.6.0, support for Python 3.7 has been dropped. Previous versions may still run on Python 3.7, but v0.6.0+ explicitly requires Python 3.8 or newer.
- breaking cabinetry v0.5.0 adopted the `pyhf` 0.7 API. Code written for older `pyhf` versions or cabinetry versions prior to 0.5.0 may experience compatibility issues if the `pyhf` model definitions or API calls are used directly.
- breaking From cabinetry v0.4.0 onwards, all API arguments are keyword-only. This means you must explicitly use the keyword when calling functions, e.g., `func(arg=value)` instead of `func(value)`.
- gotcha Since cabinetry v0.2.2, cabinetry no longer overrides the `pyhf` backend. If you need a specific `pyhf` backend (e.g., 'jax', 'torch'), you must set it explicitly using `pyhf.set_backend()` before any `pyhf` operations are performed.
- gotcha cabinetry v0.5.1 introduced a minimum required `matplotlib` version of 3.5.0 to address plotting issues and enable new features.
Install
-
pip install cabinetry
Imports
- cabinetry
import cabinetry
- templates
from cabinetry import templates
- fit
from cabinetry import fit
- model_utils
from cabinetry import model_utils
- workspace
from cabinetry import workspace
- visualize
from cabinetry import visualize
Quickstart
import cabinetry
import numpy as np
import pyhf
import os
# 1. Define configuration (simplified for quickstart)
# In a real scenario, this would likely be loaded from a YAML/JSON file
config = {
"General": {
"Measurement": "my_measurement",
"POI": "Signal_norm",
"Luminosity": 1.0
},
"Regions": [
{
"Name": "SR",
"HistogramFolders": ["data/", "signal/", "background/"],
"Variable": "m_yy",
"Binning": [40, 50, 60, 70, 80, 90, 100]
}
],
"Samples": [
{"Name": "Signal", "Observable": "m_yy", "Normalization": "Signal_norm"},
{"Name": "Background", "Observable": "m_yy"}
],
"Systematics": [
{
"Name": "lumi",
"Type": "lumi",
"Expression": "1.02"
}
]
}
# 2. Create dummy data/histograms in memory
bins = config["Regions"][0]["Binning"]
data_hists = {
"SR": np.array([5, 8, 12, 10, 7, 4])
}
sample_hists = [
{
"name": "Signal",
"region": "SR",
"nominal": np.array([2, 3, 4, 3, 2, 1]),
"staterr": np.sqrt(np.array([2, 3, 4, 3, 2, 1])) # Placeholder for stat error
},
{
"name": "Background",
"region": "SR",
"nominal": np.array([3, 5, 8, 7, 5, 3]),
"staterr": np.sqrt(np.array([3, 5, 8, 7, 5, 3]))
}
]
# Add systematic variation for "lumi"
for h in sample_hists:
h["lumi_up"] = h["nominal"] * 1.02
h["lumi_down"] = h["nominal"] * 0.98
h["bins"] = bins # Add binning for plotting
# 3. Build workspace
ws = cabinetry.workspace.build(config, sample_hists, data_hists)
model, data = cabinetry.model_utils.model_and_data(ws)
# 4. Perform fit
fit_results = cabinetry.fit.fit(model, data)
# 5. Visualize results (optional)
plot_dir = "cabinetry_quickstart_plots"
os.makedirs(plot_dir, exist_ok=True)
cabinetry.visualize.data_mc(
model, data, fit_results=fit_results, config=config, save_path=os.path.join(plot_dir, "data_mc_plot.pdf")
)
cabinetry.visualize.ranking(
fit_results, save_path=os.path.join(plot_dir, "ranking_plot.pdf")
)
print("cabinetry quickstart complete. Plots saved to:", os.path.abspath(plot_dir))