Source code for wolfhece.assets.pie.distribution

from __future__ import annotations

from dataclasses import dataclass
from typing import Sequence

import numpy as np


@dataclass(frozen=True)
[docs] class PieSlice: """One normalized pie slice definition."""
[docs] value: float
[docs] fraction: float
[docs] start_angle_deg: float
[docs] end_angle_deg: float
[docs] label: str
[docs] class PieDistributionModel: """Compute and store normalized pie fractions from values.""" def __init__(self, values: Sequence[float], labels: Sequence[str] | None = None) -> None:
[docs] self._values = np.array([], dtype=np.float64)
[docs] self._fractions = np.array([], dtype=np.float64)
[docs] self._labels: list[str] = []
self.set_values(values, labels=labels) @property
[docs] def values(self) -> np.ndarray: return self._values.copy()
@property
[docs] def fractions(self) -> np.ndarray: return self._fractions.copy()
@property
[docs] def labels(self) -> list[str]: return self._labels.copy()
[docs] def set_values(self, values: Sequence[float], labels: Sequence[str] | None = None) -> None: arr = np.asarray(values, dtype=np.float64).ravel() if arr.size == 0: raise ValueError("Pie distribution needs at least one value") if not np.isfinite(arr).all(): raise ValueError("All pie values must be finite") if np.any(arr < 0.0): raise ValueError("Pie values must be >= 0") total = float(arr.sum()) if total <= 0.0: raise ValueError("The sum of pie values must be > 0") self._values = arr self._fractions = arr / total if labels is None: self._labels = [f"Slice {i + 1}" for i in range(arr.size)] else: if len(labels) != arr.size: raise ValueError("labels length must match values length") self._labels = [str(lbl) for lbl in labels]
[docs] def slices(self, start_angle_deg: float = 90.0, clockwise: bool = False) -> list[PieSlice]: sign = -1.0 if clockwise else 1.0 cur = float(start_angle_deg) out: list[PieSlice] = [] for value, frac, label in zip(self._values, self._fractions, self._labels): delta = sign * 360.0 * float(frac) nxt = cur + delta out.append(PieSlice(float(value), float(frac), cur, nxt, label)) cur = nxt return out