Source code for zfit.models.histogram

#  Copyright (c) 2025 zfit
from __future__ import annotations

import typing

import numpy as np
from uhi.typing.plottable import PlottableHistogram

import zfit.z.numpy as znp

if typing.TYPE_CHECKING:
    import zfit  # noqa: F401

from ..core.binnedpdf import BaseBinnedPDF
from ..core.interfaces import ZfitBinnedData
from ..core.space import supports
from ..util import ztyping
from ..util.exception import SpecificFunctionNotImplemented


[docs] class HistogramPDF(BaseBinnedPDF): def __init__( self, data: ztyping.BinnedDataInputType, extended: ztyping.ExtendedInputType | None = None, norm: ztyping.NormInputType | None = None, name: str = "HistogramPDF", label: str | None = None, ) -> None: """Binned PDF resembling a histogram. Simple histogram PDF that can be used to model a histogram as a PDF. Args: data: Histogram to be used as PDF. extended: |@doc:pdf.init.extended| The overall yield of the PDF. If this is parameter-like, it will be used as the yield, the expected number of events, and the PDF will be extended. An extended PDF has additional functionality, such as the ``ext_*`` methods and the ``counts`` (for binned PDFs). |@docend:pdf.init.extended| |@doc:pdf.init.extended.auto| If ``True``, the PDF will be extended automatically if the PDF is extended using the total number of events in the histogram. This is the default. |@docend:pdf.init.extended.auto| norm: |@doc:pdf.init.norm| Normalization of the PDF. By default, this is the same as the default space of the PDF. |@docend:pdf.init.norm| name: |@doc:pdf.init.name| Name of the PDF. Maybe has implications on the serialization and deserialization of the PDF. For a human-readable name, use the label. |@docend:pdf.init.name| label: |@doc:pdf.init.label| Human-readable name or label of the PDF for a better description, to be used with plots etc. Has no programmatical functional purpose as identification. |@docend:pdf.init.label| """ if extended is None: extended = True if not isinstance(data, ZfitBinnedData): if isinstance(data, PlottableHistogram): from zfit._data.binneddatav1 import BinnedData data = BinnedData.from_hist(data) else: msg = "data must be of type PlottableHistogram (UHI) or ZfitBinnedData" raise TypeError(msg) params = {} if extended is True: self._automatically_extended = True extended = znp.sum(data.values()) else: self._automatically_extended = False super().__init__(obs=data.space, extended=extended, norm=norm, params=params, name=name, label=label) self._data = data @supports(norm="space") def _ext_pdf(self, x, norm): if not self._automatically_extended: raise SpecificFunctionNotImplemented counts = self._counts(x, norm) areas = np.prod(self._data.axes.widths, axis=0) return counts / areas @supports(norm="space") def _pdf(self, x, norm): counts = self._rel_counts(x, norm) areas = np.prod(self._data.axes.widths, axis=0) return counts / areas @supports(norm="space") def _counts(self, x, norm=None): # noqa: ARG002 if not self._automatically_extended: raise SpecificFunctionNotImplemented return self._data.values() @supports(norm="space") def _rel_counts(self, x, norm=None): # noqa: ARG002 values = self._data.values() return values / znp.sum(values)