Source code for pyhs3.distributions.histfactory.data

"""
HistFactory data classes.

Provides data structures for HistFactory distributions including sample data
with bin contents and errors.
"""

from __future__ import annotations

from pydantic import BaseModel, ConfigDict, Field, PrivateAttr, model_validator


[docs] class SampleData(BaseModel): """Sample data containing bin contents and optional per-bin uncertainties. This class represents the binned values for a single sample in a HistFactory- style model, along with optional statistical uncertainties ("errors") per bin. .. note:: - The ``errors`` field is optional in serialized form. If omitted, it is interpreted as an array of zeros with the same length as ``contents``. This follows the convention used in ROOT HistFactory/HS3 workflows, where some samples may not carry explicit bin-by-bin uncertainties (e.g. when BBlight is not applied). - Internally, errors are always materialized and accessible via the ``errors`` property. - If provided, ``errors`` must have the same length as ``contents``. Parameters: contents : list[float] The bin contents (yields) for the sample. errors : list[float] | None Optional serialized representation of per-bin uncertainties. This is aliased to ``"errors"`` when exporting. If ``None``, errors are implicitly treated as zeros and omitted from serialization. Raises: ValueError: If ``contents`` and ``errors`` are both provided and have different lengths. """ model_config = ConfigDict(serialize_by_alias=True) contents: list[float] v_errors: list[float] | None = Field( default=None, alias="errors", repr=False, exclude_if=lambda v: v is None ) _errors: list[float] = PrivateAttr() @model_validator(mode="after") def set_default_and_validate(self) -> SampleData: """Ensure contents and errors have same length.""" if self.v_errors is None: self._errors = [0.0] * len(self.contents) else: self._errors = self.v_errors if len(self.contents) != len(self.v_errors): msg = f"Sample data contents ({len(self.contents)}) and errors ({len(self.v_errors)}) must have same length" raise ValueError(msg) return self @property def errors(self) -> list[float]: """Return the per-bin uncertainties for the sample. This property always returns a list of the same length as ``contents``. - If uncertainties were explicitly provided, they are returned as-is. - If the ``errors`` field was omitted during initialization (e.g. in HS3 JSON where missing errors imply zeros), this returns a zero-filled list. Returns: list[float]: The per-bin uncertainties corresponding to ``contents``. """ return self._errors
__all__ = ["SampleData"]