From 54382720a3139e8db41cf16b9271879fe384a1f1 Mon Sep 17 00:00:00 2001 From: renecotyfanboy Date: Sun, 9 Nov 2025 19:08:15 +0100 Subject: [PATCH 01/11] multimodal hdi --- docs/examples/plot_5_emcee_arviz_numpyro.py | 2 +- docs/examples/plot_7_multimodal_chains.py | 79 ++++++ src/chainconsumer/analysis.py | 286 ++++++++++++++++++-- src/chainconsumer/chain.py | 7 + src/chainconsumer/plotter.py | 85 ++++-- src/chainconsumer/statistics.py | 3 + tests/test_analysis.py | 155 +++++++++++ tests/test_plotter.py | 63 +++++ tests/test_translators.py | 4 +- 9 files changed, 634 insertions(+), 50 deletions(-) create mode 100644 docs/examples/plot_7_multimodal_chains.py diff --git a/docs/examples/plot_5_emcee_arviz_numpyro.py b/docs/examples/plot_5_emcee_arviz_numpyro.py index 0e70d3be..ecbd5ebd 100644 --- a/docs/examples/plot_5_emcee_arviz_numpyro.py +++ b/docs/examples/plot_5_emcee_arviz_numpyro.py @@ -1,5 +1,5 @@ """ -# Using external samples easily +# Using external samples `emcee`, `arviz`, and `numpyro` are all popular MCMC packages. ChainConsumer provides class methods to turn results from these packages into chains efficiently. diff --git a/docs/examples/plot_7_multimodal_chains.py b/docs/examples/plot_7_multimodal_chains.py new file mode 100644 index 00000000..c736d8ea --- /dev/null +++ b/docs/examples/plot_7_multimodal_chains.py @@ -0,0 +1,79 @@ +""" +# Multimodal distributions + +`ChainConsumer` can handle cases where the distributions of your chains are multimodal. +""" + +import numpy as np +import pandas as pd + +from chainconsumer import Chain, ChainConsumer +from chainconsumer.statistics import SummaryStatistic + +# %% +# First, let's build some dummy data + +rng = np.random.default_rng(42) +size = 60_000 + +eta = rng.normal(loc=0.0, scale=0.8, size=size) + +phi = np.asarray( + [rng.gamma(shape=2.5, scale=0.4, size=size // 2) - 3.0, 3.0 - rng.gamma(shape=5.0, scale=0.35, size=(size // 2))] +).flatten() + +rng.shuffle(phi) + +df = pd.DataFrame({"eta": eta, "phi": phi}) + +# %% +# To build a multimodal chain, you simply have to pass `multimodal=True` when building the chain. To work, it requires +# you to specify `SummaryStatistic.HDI` as the summary statistic. + +chain_multimodal = Chain( + samples=df.copy(), + name="posterior-multimodal", + statistics=SummaryStatistic.HDI, + multimodal=True, # <- Here +) + +# %% +# Now, if you add this `Chain` to a plotter, it will try to look for sub-intervals and display them. + +cc = ChainConsumer() +cc.add_chain(chain_multimodal) +fig = cc.plotter.plot() + +# %% +# Let's compare with what would happen if you don't use a multimodal chain. We use the same data as before but don't +# warn `ChainConsumer` that we expect the chains to be multimodal. + +chain_unimodal = Chain(samples=df.copy(), name="posterior-unimodal", statistics=SummaryStatistic.HDI, multimodal=False) + +cc.add_chain(chain_unimodal) +fig = cc.plotter.plot() + +# %% +# Let's try with even more modes. + +eta = np.asarray( + [ + rng.normal(loc=-3, scale=0.8, size=size // 3), + rng.normal(loc=0.0, scale=0.8, size=size // 3), + rng.normal(loc=+3, scale=0.8, size=size // 3), + ] +).flatten() + + +rng.shuffle(eta) + +df = pd.DataFrame({"eta": eta, "phi": phi}) + +chain_multimodal = Chain( + samples=df.copy(), name="posterior-multimodal", statistics=SummaryStatistic.HDI, multimodal=True +) + +cc = ChainConsumer() +cc.add_chain(chain_multimodal) +fig = cc.plotter.plot() +fig.tight_layout() diff --git a/src/chainconsumer/analysis.py b/src/chainconsumer/analysis.py index c078cc50..8dfda96b 100644 --- a/src/chainconsumer/analysis.py +++ b/src/chainconsumer/analysis.py @@ -1,7 +1,8 @@ from __future__ import annotations import logging -from collections.abc import Callable +import warnings +from collections.abc import Callable, Sequence from pathlib import Path import numpy as np @@ -9,6 +10,7 @@ from scipy.integrate import simpson as simps from scipy.interpolate import interp1d from scipy.ndimage import gaussian_filter +from scipy.optimize import root_scalar from .base import BetterBase from .chain import Chain, ChainName, ColumnName, MaxPosterior, Named2DMatrix @@ -17,6 +19,33 @@ from .statistics import SummaryStatistic +def _mask_to_intervals( + x: np.ndarray, + mask: np.ndarray, +) -> list[tuple[float, float]]: + """ + Turn a mask indexed on x to a list of intervals + """ + if mask.size == 0: + return [] + + change = np.diff(mask.astype(int)) + starts = np.where(change == 1)[0] + 1 # False -> True + ends = np.where(change == -1)[0] # True -> False + + # If we start inside an interval, prepend 0 + if mask[0]: + starts = np.concatenate(([0], starts)) + + # If we end inside an interval, append last index + if mask[-1]: + ends = np.concatenate((ends, len(mask) - 1)) + + intervals = [(float(x[s]), float(x[e])) for s, e in zip(starts, ends, strict=True) if x[e] > x[s]] + + return intervals + + class Bound(BetterBase): lower: float | None = Field(default=None) center: float | None = Field(default=None) @@ -53,6 +82,7 @@ def __init__(self, parent: ChainConsumer): SummaryStatistic.MEAN: self.get_parameter_summary_mean, SummaryStatistic.CUMULATIVE: self.get_parameter_summary_cumulative, SummaryStatistic.MAX_CENTRAL: self.get_parameter_summary_max_central, + SummaryStatistic.HDI: self.get_parameter_summary_hdi, } def get_latex_table( @@ -163,7 +193,7 @@ def get_summary( """Gets a summary of the marginalised parameter distributions. Args: - parameters (list[str], optional): A list of parameters which to generate summaries for. + columns (list[str], optional): A list of parameters which to generate summaries for. chains (dict[str, Chain] | list[str], optional): A list of chains to generate summaries for. Returns: @@ -183,6 +213,25 @@ def get_summary( continue summary = self.get_parameter_summary(chain, p) res[p] = summary + + if chain.multimodal: + intervals = self.get_parameter_hdi_intervals(chain, p) + + # If there is a single interval, we skip + if len(intervals) < 2: + continue + + multimodal_bounds = self.get_parameter_multimodal_bounds( + chain, + p, + intervals=intervals, + ) + + if multimodal_bounds is not None: + res[p] = multimodal_bounds + continue + + res[p] = summary results[chain.name] = res return results @@ -276,7 +325,12 @@ def get_covariance_table( return self._get_2d_latex_table(covariance, caption, label) def _get_smoothed_histogram( - self, chain: Chain, column: ColumnName, pad: bool = False + self, + chain: Chain, + column: ColumnName, + pad: bool = False, + *, + use_kde: bool | None = None, ) -> tuple[np.ndarray, np.ndarray, np.ndarray]: data = chain.get_data(column) if chain.grid: @@ -292,7 +346,10 @@ def _get_smoothed_histogram( if chain.smooth_value: hist = gaussian_filter(hist, chain.smooth_value, mode="reflect") - if chain.kde: + if use_kde is None: + use_kde = bool(chain.kde) + + if use_kde: kde_xs = np.linspace(edge_centers[0], edge_centers[-1], max(200, int(bins.max()))) factor = chain.kde if isinstance(chain.kde, int | float) else 1.0 ys = MegKDE(data.to_numpy(), chain.weights, factor=factor).evaluate(kde_xs) @@ -325,27 +382,69 @@ def _get_2d_latex_table(self, named_matrix: Named2DMatrix, caption: str, label: table += hline_text return latex_table % (column_def, table) - def get_parameter_text(self, bound: Bound, wrap: bool = False): - """Generates LaTeX appropriate text from marginalised parameter bounds. - - Parameters - ---------- - lower : float - The lower bound on the parameter - maximum : float - The value of the parameter with maximum probability - upper : float - The upper bound on the parameter - wrap : bool - Wrap output text in dollar signs for LaTeX - - Returns - ------- - str - The formatted text given the parameter bounds + def get_parameter_text( + self, + bound: Bound | Sequence[Bound], + wrap: bool = False, + *, + label: str | None = None, + ) -> str: + """Format marginal parameter bounds for display. + + Args: + bound: + The bound (or list of bounds) to format. + wrap: + Wrap each formatted expression in LaTeX dollar signs. + label: + Optional parameter label to prepend. For multimodal results the + label is placed on its own line. + + Returns: + The formatted string. Returns an empty string when the input contains + no finite limits. """ + + if bound is None: + return "" + + # Fallback to single bound behavior is there is only one mode identified + if isinstance(bound, Sequence) and len(bound) < 2: + bound = bound[0] + + if isinstance(bound, Sequence) and not isinstance(bound, Bound): + bounds = [b for b in bound if isinstance(b, Bound) and not b.all_none] + if not bounds: + return "" + + lines: list[str] = [] + if label: + lines.append(f"${label}$" if wrap else label) + + for index, sub_bound in enumerate(bounds, start=1): + entry = Analysis._format_single_bound(sub_bound, use_pm=False) + if not entry: + continue + if wrap: + entry = f"${entry}$" + lines.append(f"I{index}: {entry}") + + return "\n".join(lines) + if bound.lower is None or bound.upper is None or bound.center is None: return "" + + text = self._format_single_bound(bound, use_pm=True) + + if label: + text = f"{label} = {text}" + + if wrap: + return f"${text}$" + return text + + @staticmethod + def _format_single_bound(bound: Bound, *, use_pm: bool) -> str: upper_error = bound.upper - bound.center lower_error = bound.center - bound.lower if upper_error != 0 and lower_error != 0: @@ -389,14 +488,12 @@ def get_parameter_text(self, bound: Bound, wrap: bool = False): fmt = "%0.0f" upper_error_text = fmt % upper_error lower_error_text = fmt % lower_error - if upper_error_text == lower_error_text: + if use_pm and upper_error_text == lower_error_text: text = r"{}\pm {}".format(fmt, "%s") % (maximum, lower_error_text) else: text = r"{}^{{+{}}}_{{-{}}}".format(fmt, "%s", "%s") % (maximum, upper_error_text, lower_error_text) if factor != 0: text = r"\left( %s \right) \times 10^{%d}" % (text, -factor) - if wrap: - text = f"${text}$" return text def get_parameter_summary_mean(self, chain: Chain, column: ColumnName) -> Bound | None: @@ -412,6 +509,145 @@ def get_parameter_summary_cumulative(self, chain: Chain, column: ColumnName) -> bounds = interp1d(cs, xs)(vals) return Bound(lower=bounds[0], center=bounds[1], upper=bounds[2]) + def get_parameter_summary_hdi(self, chain: Chain, column: ColumnName) -> Bound: + data = chain.get_data(column).to_numpy() + n_samples = data.size + + if n_samples <= 512: # Arbitrary low sample warning + warnings.warn( + ( + f"Only {n_samples} samples available to compute an HDI for column '{column}' " + f"in chain '{chain.name}'. Results may be unreliable; consider enabling KDE or " + "providing more samples." + ), + UserWarning, + stacklevel=2, + ) + + xs, _, cs = self._get_smoothed_histogram(chain, column, pad=True) + + cdf_points = np.concatenate(([0.0], cs)) + x_points = np.concatenate(([xs[0]], xs)) + + eps = 1e-12 + best_width = float("inf") + best_lower = float(x_points[0]) + best_upper = float(x_points[-1]) + best_start_mass = 0.0 + best_end_mass = 1.0 + + for start_idx, start_mass in enumerate(cdf_points[:-1]): + required = start_mass + chain.summary_area + if required > 1.0 + eps: + break + + # Smallest index with cdf_points[end_idx] >= required + end_idx = np.searchsorted(cdf_points, required, side="left") + + # Ensure at least one point is in the interval + if end_idx <= start_idx: + end_idx = start_idx + 1 + if end_idx >= cdf_points.size: + break + + # If still slightly under target, move one step right if possible + if cdf_points[end_idx] - start_mass < chain.summary_area - eps and end_idx + 1 < cdf_points.size: + end_idx += 1 + + lower = float(x_points[start_idx]) + upper = float(x_points[end_idx]) + width = upper - lower + if width <= eps: + continue + + if width < best_width - eps: + best_width = width + best_lower = lower + best_upper = upper + best_start_mass = float(start_mass) + best_end_mass = float(cdf_points[end_idx]) + + interval_mass = best_end_mass - best_start_mass + + if interval_mass <= eps: + center = 0.5 * (best_lower + best_upper) + + else: + center_mass = best_start_mass + 0.5 * interval_mass + center = float(np.interp(center_mass, cdf_points, x_points, left=best_lower, right=best_upper)) + + return Bound(lower=best_lower, center=center, upper=best_upper) + + def get_parameter_hdi_intervals(self, chain: Chain, column: ColumnName) -> list[tuple[float, float]]: + """Return highest-density intervals for a marginal distribution. + + Multimodal chains yield one interval per disjoint density band, whereas unimodal chains + return a single contiguous interval. + """ + summary = self.get_parameter_summary_hdi(chain, column) + default_interval = [(summary.lower, summary.upper)] + xs, ys, _ = self._get_smoothed_histogram(chain, column, pad=True, use_kde=False) + + # We look for the threshold that is the root of this function + def mass_diff(threshold, density, xs, target): + mask = density >= threshold + mass_above_threshold = float(simps(np.where(mask, density, 0.0), x=xs)) + return mass_above_threshold - target + + area = simps(ys, x=xs) + density = ys / area + + sol = root_scalar( + mass_diff, + bracket=(0.0, float(np.max(density))), + args=(density, xs, chain.summary_area), + method="bisect", + xtol=5e-4, + ) + + threshold = sol.root + mask = density >= threshold + + intervals = _mask_to_intervals(xs, mask) + + return intervals if intervals else default_interval + + def get_parameter_multimodal_bounds( + self, + chain: Chain, + column: ColumnName, + intervals: list[tuple[float, float]], + ) -> list[Bound]: + """ + Convert multimodal HDI bands into `Bound` instances. + """ + + xs, ys, _ = self._get_smoothed_histogram( + chain, + column, + pad=True, + use_kde=False if chain.multimodal else None, + ) + + lower_limit, upper_limit = float(xs.min()), float(xs.max()) + + bounds = [] + + for lower_raw, upper_raw in intervals: + lower, upper = max(lower_raw, lower_limit), min(upper_raw, upper_limit) + mask = (xs >= lower) & (xs <= upper) + + if np.any(mask): + idx = int(np.argmax(ys[mask])) + center = float(xs[mask][idx]) + + else: + center = float(0.5 * (lower + upper)) + + bounds.append(Bound(lower=float(lower), center=center, upper=float(upper))) + + return bounds + def get_parameter_summary_max(self, chain: Chain, column: ColumnName) -> Bound | None: xs, ys, cs = self._get_smoothed_histogram(chain, column) n_pad = 1000 diff --git a/src/chainconsumer/chain.py b/src/chainconsumer/chain.py index b770aed5..7c86b5b1 100644 --- a/src/chainconsumer/chain.py +++ b/src/chainconsumer/chain.py @@ -59,6 +59,7 @@ class ChainConfig(BetterBase): shade_alpha: float = Field(default=0.5, description="The alpha of the shading") shade_gradient: float = Field(default=1.0, description="The contrast between contour levels") bar_shade: bool = Field(default=True, description="Whether to shade marginalised distributions") + multimodal: bool = Field(default=False, description="Mark the chain as multimodal to enable HDI band splitting.") bins: int | None = Field(default=None, description="The number of bins to use for histograms.") kde: int | float | bool = Field(default=False, description="The bandwidth for KDEs") smooth: int | None = Field( @@ -281,6 +282,12 @@ def _validate_model(self) -> Chain: if self.num_free_params is not None: assert np.isfinite(self.num_free_params), "num_free_params is not finite" + if self.multimodal and self.statistics is not SummaryStatistic.HDI: + raise ValueError( + f"Chain {self.name} is marked as multimodal but uses {self.statistics.value}; " + "set statistics=SummaryStatistic.HDI." + ) + return self def get_data(self, column: str) -> pd.Series[float]: diff --git a/src/chainconsumer/plotter.py b/src/chainconsumer/plotter.py index b0f0a78a..82a84908 100644 --- a/src/chainconsumer/plotter.py +++ b/src/chainconsumer/plotter.py @@ -1,5 +1,8 @@ +from __future__ import annotations + from enum import Enum from pathlib import Path +from typing import TYPE_CHECKING import matplotlib import matplotlib.pyplot as plt @@ -24,6 +27,9 @@ from .plotting import add_watermark, plot_surface from .plotting.config import PlotConfig +if TYPE_CHECKING: + from .chainconsumer import ChainConsumer + class PlottingBase(BetterBase): chains: list[Chain] @@ -42,7 +48,7 @@ class FigSize(Enum): @classmethod def get_size( - cls, input: "FigSize | float | int | tuple[float, float]", num_columns: int, has_cax: bool + cls, input: FigSize | float | int | tuple[float, float], num_columns: int, has_cax: bool ) -> tuple[float, float]: if input == FigSize.PAGE: return 10, 10 @@ -106,7 +112,7 @@ def get_artists_from_chains(chains: list[Chain]) -> list[Artist]: class Plotter: - def __init__(self, parent: "ChainConsumer") -> None: + def __init__(self, parent: ChainConsumer) -> None: self.parent: ChainConsumer = parent self._config: PlotConfig | None = None self._default_config = PlotConfig() @@ -201,7 +207,13 @@ def plot( continue do_summary = summarise and p1 not in base.blind - max_hist_val = self._plot_bars(ax, p1, chain, flip=do_flip, summary=do_summary) + max_hist_val = self._plot_bars( + ax, + p1, + chain, + flip=do_flip, + summary=do_summary, + ) if max_val is None or max_hist_val > max_val: max_val = max_hist_val @@ -905,7 +917,12 @@ def _sanitise_chains( return [c for c in final_chains if include_skip or not c.skip] def _plot_bars( - self, ax: Axes, column: str, chain: Chain, flip: bool = False, summary: bool = False + self, + ax: Axes, + column: str, + chain: Chain, + flip: bool = False, + summary: bool = False, ) -> float: # pragma: no cover # Get values from config data = chain.get_data(column) @@ -942,41 +959,63 @@ def _plot_bars( interpolator = interp1d(xs, ys, kind=interp_type) if chain.bar_shade: - fit_values = self.parent.analysis.get_parameter_summary(chain, column) - if fit_values is not None: - lower = fit_values.lower - upper = fit_values.upper - if lower is not None and upper is not None: - lower = max(lower, xs.min()) - upper = min(upper, xs.max()) - x = np.linspace(lower, upper, 1000) # type: ignore + base_bound = self.parent.analysis.get_parameter_summary(chain, column) + + if base_bound is not None and base_bound.lower is not None and base_bound.upper is not None: + if chain.multimodal: + intervals = self.parent.analysis.get_parameter_hdi_intervals(chain, column) + display_bounds = self.parent.analysis.get_parameter_multimodal_bounds( + chain, + column, + intervals, + ) + + # If we get a single interval, fallback to unimodal HDI + if len(intervals) < 2: + intervals = [(base_bound.lower, base_bound.upper)] + + else: + display_bounds = base_bound + intervals = [(display_bounds.lower, display_bounds.upper)] + intervals = np.clip(intervals, a_min=xs.min(), a_max=xs.max()) + + for lower, upper_ in intervals: + x = np.linspace(lower, upper_, 1000) + if flip: ax.fill_betweenx( x, - np.zeros(x.shape), + np.zeros_like(x), interpolator(x), color=chain.color, alpha=0.2, zorder=chain.zorder, ) + else: ax.fill_between( x, - np.zeros(x.shape), + np.zeros_like(x), interpolator(x), color=chain.color, alpha=0.2, zorder=chain.zorder, ) - if summary: - t = self.parent.analysis.get_parameter_text(fit_values) - label = self.config.get_label(column) - if isinstance(column, str): - ax.set_title( - r"${} = {}$".format(label.strip("$"), t), fontsize=self.config.summary_font_size - ) - else: - ax.set_title(rf"${t}$", fontsize=self.config.summary_font_size) + + if summary: + label = self.config.get_label(column) + label_core = label.strip("$") if isinstance(column, str) else None + label_text = label_core or None + + title = self.parent.analysis.get_parameter_text( + display_bounds, + wrap=True, + label=label_text, + ) + + if title: + ax.set_title(title, fontsize=self.config.summary_font_size) + return float(ys.max()) def _plot_walk( diff --git a/src/chainconsumer/statistics.py b/src/chainconsumer/statistics.py index 29d4afc2..b278a697 100644 --- a/src/chainconsumer/statistics.py +++ b/src/chainconsumer/statistics.py @@ -18,3 +18,6 @@ class SummaryStatistic(Enum): MEAN = "mean" """As per the cumulative method, except the central value is placed in the midpoint between the upper and lower boundary. Not recommended, but was requested.""" + + HDI = "hdi" + """Use the highest density interval. Finds the narrowest interval covering the requested mass.""" diff --git a/tests/test_analysis.py b/tests/test_analysis.py index 86051e4b..4914a066 100644 --- a/tests/test_analysis.py +++ b/tests/test_analysis.py @@ -1,8 +1,11 @@ +import arviz as az import numpy as np import pandas as pd +import pytest from scipy.stats import skewnorm from chainconsumer import Bound, Chain, ChainConfig, ChainConsumer +from chainconsumer.statistics import SummaryStatistic class TestChain: @@ -12,6 +15,9 @@ class TestChain: data2 = rng.normal(loc=3, scale=1.0, size=n) data_combined = np.vstack((data, data2)).T data_skew = skewnorm.rvs(5, loc=1, scale=1.5, size=n) + data_bimodal = np.concatenate( + [rng.normal(loc=-1.5, scale=0.3, size=n // 2), rng.normal(loc=1.5, scale=0.3, size=n // 2)] + ) chain = Chain(samples=pd.DataFrame(data, columns=["x"]), name="a") chain2 = Chain(samples=pd.DataFrame(data2, columns=["x"]), name="b") @@ -139,6 +145,107 @@ def test_output_format6(self): text = consumer.analysis.get_parameter_text(Bound.from_array(p1), wrap=True) assert text == r"$0.020^{+0.015}_{-0.010}$" + def test_output_multimodal_text(self): + intervals = [ + Bound(lower=-2.0, center=-1.5, upper=-1.0), + Bound(lower=1.0, center=1.4, upper=2.0), + ] + consumer = ChainConsumer() + text = consumer.analysis.get_parameter_text(intervals, wrap=True, label="x") + + assert text.startswith("$x$") + assert text.count("I1:") == 1 and text.count("I2:") == 1 + assert "\\pm" not in text + assert "\n" in text + + def test_summary_multimodal_returns_intervals(self): + rng = np.random.default_rng(42) + samples = np.concatenate( + [ + rng.normal(loc=-1.5, scale=0.2, size=5000), + rng.normal(loc=1.6, scale=0.25, size=5000), + ] + ) + df = pd.DataFrame({"x": samples}) + chain = Chain( + samples=df, + name="bimodal", + statistics=SummaryStatistic.HDI, + kde=True, + multimodal=True, + summary_area=0.5, + ) + consumer = ChainConsumer() + consumer.add_chain(chain) + + summary = consumer.analysis.get_summary() + result = summary["bimodal"]["x"] + + assert isinstance(result, list) + assert len(result) > 1 + assert all(isinstance(bound, Bound) for bound in result) + assert result[0].upper < 0 + assert result[-1].lower > 0 + + def test_hdi_weighted_interval(self): + samples = np.array([0.0, 1.0, 2.0, 2.5, 3.0]) + weights = np.array([0.05, 0.10, 0.50, 0.20, 0.15]) + df = pd.DataFrame({"x": samples, "weight": weights}) + chain = Chain(samples=df, name="weighted", statistics=SummaryStatistic.HDI, summary_area=0.5) + consumer = ChainConsumer() + consumer.add_chain(chain) + + bound = consumer.analysis.get_summary()["weighted"]["x"] + assert bound.lower < bound.center < bound.upper + assert np.isclose(bound.center, 2.0, atol=5e-3) + assert bound.upper - bound.lower < 0.3 + + def test_hdi_warns_when_samples_low_without_kde(self): + df = pd.DataFrame({"x": np.linspace(-1.0, 1.0, 10)}) + chain = Chain(samples=df, name="warn", statistics=SummaryStatistic.HDI, summary_area=0.5) + consumer = ChainConsumer() + consumer.add_chain(chain) + + with pytest.warns(UserWarning, match="Only 10 samples available"): + consumer.analysis.get_parameter_summary_hdi(chain, "x") + + def test_hdi_intervals_single(self): + chain = Chain( + samples=pd.DataFrame(self.data_skew[::20], columns=["x"]), + name="skew", + statistics=SummaryStatistic.HDI, + kde=True, + ) + consumer = ChainConsumer() + consumer.add_chain(chain) + + intervals = consumer.analysis.get_parameter_hdi_intervals(chain, "x") + assert len(intervals) == 1 + lower, upper = intervals[0] + assert lower < upper + + def test_hdi_intervals_multimodal(self): + df = pd.DataFrame(self.data_bimodal[::20], columns=["x"]) + chain_default = Chain(samples=df, name="bimodal", statistics=SummaryStatistic.HDI, kde=True) + consumer = ChainConsumer() + consumer.add_chain(chain_default) + + multimodal_chain = Chain( + samples=df, + name="bimodal_multi", + statistics=SummaryStatistic.HDI, + kde=True, + multimodal=True, + summary_area=chain_default.summary_area, + ) + consumer2 = ChainConsumer() + consumer2.add_chain(multimodal_chain) + + multi_intervals = consumer2.analysis.get_parameter_hdi_intervals(multimodal_chain, "x") + assert len(multi_intervals) == 2 + assert multi_intervals[0][1] < 0.0 + assert multi_intervals[1][0] > 0.0 + def test_output_format7(self): p1 = [None, 2.0e-2, 3.5e-2] consumer = ChainConsumer() @@ -250,6 +357,54 @@ def test_divide_chains_name(self): assert np.all(np.abs(array.center - means[i]) < 1e-1) assert np.abs(consumer.get_chain(name).get_data("x").mean() - means[i]) < 1e-2 + +class TestHDIParityWithArviz: + @staticmethod + def _make_chain( + samples: np.ndarray, + *, + area: float, + multimodal: bool = False, + smooth: int = 0, + kde: int | float | bool = False, + ) -> tuple[ChainConsumer, Chain]: + chain = Chain( + samples=pd.DataFrame({"x": samples}), + name="arviz", + statistics=SummaryStatistic.HDI, + summary_area=area, + smooth=smooth, + kde=kde, + multimodal=multimodal, + ) + consumer = ChainConsumer() + consumer.add_chain(chain) + return consumer, chain + + def test_hdi_matches_arviz_unimodal(self) -> None: + rng = np.random.default_rng(9876) + samples = rng.normal(loc=-0.25, scale=1.3, size=5000) + area = 0.5 + + consumer, chain = self._make_chain(samples, area=area) + bound = consumer.analysis.get_summary()[chain.name]["x"] + assert isinstance(bound, Bound) + + az_hdi = az.stats.hdi(samples, hdi_prob=area) + np.testing.assert_allclose([bound.lower, bound.upper], az_hdi, atol=5e-2) + + def test_hdi_matches_arviz_high_sample_multimodal(self) -> None: + rng = np.random.default_rng(0) + samples = np.concatenate([rng.normal(-2.0, 0.3, size=5000), rng.normal(2.0, 0.25, size=5000)]) + area = 0.5 + + consumer, chain = self._make_chain(samples, area=area, multimodal=True) + cc_intervals = np.array(consumer.analysis.get_parameter_hdi_intervals(chain, "x")) + az_intervals = np.asarray(az.stats.hdi(samples, hdi_prob=area, multimodal=True)) + + assert cc_intervals.shape == az_intervals.shape + np.testing.assert_allclose(cc_intervals, az_intervals, atol=8e-2) + # def test_stats_max_cliff(self): # tolerance = 5e-2 # n = 100000 diff --git a/tests/test_plotter.py b/tests/test_plotter.py index 787b8144..3af88f05 100644 --- a/tests/test_plotter.py +++ b/tests/test_plotter.py @@ -1,8 +1,14 @@ +import matplotlib + +matplotlib.use("Agg") + +import matplotlib.pyplot as plt import numpy as np import pandas as pd from scipy.stats import norm from chainconsumer import Chain, ChainConsumer +from chainconsumer.statistics import SummaryStatistic class TestChain: @@ -69,3 +75,60 @@ def test_plotter_extents6(self): minv, maxv = c.plotter._get_parameter_extents("x", list(c._chains.values())) assert np.isclose(minv, -1, atol=0.01) assert np.isclose(maxv, 1, atol=0.01) + + def test_plotter_multimodal_fill(self): + samples = np.concatenate( + [ + self.rng.normal(loc=-1.5, scale=0.2, size=5000), + self.rng.normal(loc=1.7, scale=0.25, size=5000), + ] + ) + df = pd.DataFrame({"x": samples}) + chain = Chain(samples=df, name="bimodal", statistics=SummaryStatistic.HDI, kde=True, multimodal=True) + consumer = ChainConsumer() + consumer.add_chain(chain) + + fig, ax = plt.subplots() + consumer.plotter._plot_bars(ax, "x", chain) + + intervals_drawn: list[tuple[float, float]] = [] + for collection in ax.collections: + if not collection.get_paths(): + continue + path = collection.get_paths()[0] + xs = path.vertices[:, 0] + xmin, xmax = xs.min(), xs.max() + if xmax - xmin <= 0: + continue + intervals_drawn.append((xmin, xmax)) + + plt.close(fig) + + intervals_drawn.sort() + assert len(intervals_drawn) == 2 + first, second = intervals_drawn + assert first[1] < 0.0 + assert second[0] > 0.0 + + def test_plotter_multimodal_title(self): + samples = np.concatenate( + [ + self.rng.normal(loc=-1.0, scale=0.15, size=4000), + self.rng.normal(loc=1.0, scale=0.15, size=4000), + ] + ) + df = pd.DataFrame({"x": samples}) + chain = Chain(samples=df, name="bimodal", statistics=SummaryStatistic.HDI, kde=True, multimodal=True) + consumer = ChainConsumer() + consumer.add_chain(chain) + + fig, ax = plt.subplots() + consumer.plotter._plot_bars(ax, "x", chain, summary=True) + title = ax.get_title() + plt.close(fig) + + assert "I1:" in title + assert "I2:" in title + assert "\n" in title + assert "\\pm" not in title + assert "^{+" in title and "}_{-" in title diff --git a/tests/test_translators.py b/tests/test_translators.py index 183d5873..b6ec627c 100644 --- a/tests/test_translators.py +++ b/tests/test_translators.py @@ -29,7 +29,9 @@ def model(data): # Running MCMC kernel = NUTS(model) - mcmc = MCMC(kernel, num_warmup=500, num_samples=n_steps, num_chains=n_chains, progress_bar=False) + mcmc = MCMC( + kernel, num_warmup=500, num_samples=n_steps, num_chains=n_chains, progress_bar=False, chain_method="sequential" + ) rng_key = random.PRNGKey(0) mcmc.run(rng_key, data=observed_data) From 7ab599b9746a216bbbbef00d42e9667224cf2060 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Dupourqu=C3=A9?= <49200287+renecotyfanboy@users.noreply.github.com> Date: Tue, 25 Nov 2025 22:27:57 +0100 Subject: [PATCH 02/11] Apply suggestion from @Copilot Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/chainconsumer/analysis.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chainconsumer/analysis.py b/src/chainconsumer/analysis.py index 8dfda96b..49698df9 100644 --- a/src/chainconsumer/analysis.py +++ b/src/chainconsumer/analysis.py @@ -39,7 +39,7 @@ def _mask_to_intervals( # If we end inside an interval, append last index if mask[-1]: - ends = np.concatenate((ends, len(mask) - 1)) + ends = np.concatenate((ends, [len(mask) - 1])) intervals = [(float(x[s]), float(x[e])) for s, e in zip(starts, ends, strict=True) if x[e] > x[s]] From cdbce0a84cef8930295a8d61e844714218cc43e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Dupourqu=C3=A9?= <49200287+renecotyfanboy@users.noreply.github.com> Date: Tue, 25 Nov 2025 22:28:28 +0100 Subject: [PATCH 03/11] Apply suggestion from @Copilot Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- docs/examples/plot_7_multimodal_chains.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/examples/plot_7_multimodal_chains.py b/docs/examples/plot_7_multimodal_chains.py index c736d8ea..c2e7971a 100644 --- a/docs/examples/plot_7_multimodal_chains.py +++ b/docs/examples/plot_7_multimodal_chains.py @@ -46,7 +46,7 @@ # %% # Let's compare with what would happen if you don't use a multimodal chain. We use the same data as before but don't -# warn `ChainConsumer` that we expect the chains to be multimodal. +# tell `ChainConsumer` that we expect the chains to be multimodal. chain_unimodal = Chain(samples=df.copy(), name="posterior-unimodal", statistics=SummaryStatistic.HDI, multimodal=False) From 0c1ed3fda9b478ea752023a8c033d94dd8383456 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Dupourqu=C3=A9?= <49200287+renecotyfanboy@users.noreply.github.com> Date: Tue, 25 Nov 2025 22:28:56 +0100 Subject: [PATCH 04/11] Apply suggestion from @Copilot Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/chainconsumer/analysis.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chainconsumer/analysis.py b/src/chainconsumer/analysis.py index 49698df9..4cc17bf4 100644 --- a/src/chainconsumer/analysis.py +++ b/src/chainconsumer/analysis.py @@ -408,7 +408,7 @@ def get_parameter_text( if bound is None: return "" - # Fallback to single bound behavior is there is only one mode identified + # Fallback to single bound behavior if there is only one mode identified if isinstance(bound, Sequence) and len(bound) < 2: bound = bound[0] From 64248dbf93a29641a81e612e76b67b6d03098545 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Dupourqu=C3=A9?= <49200287+renecotyfanboy@users.noreply.github.com> Date: Tue, 25 Nov 2025 22:29:55 +0100 Subject: [PATCH 05/11] Apply suggestion from @Copilot Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/chainconsumer/analysis.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chainconsumer/analysis.py b/src/chainconsumer/analysis.py index 4cc17bf4..1a4cd671 100644 --- a/src/chainconsumer/analysis.py +++ b/src/chainconsumer/analysis.py @@ -586,7 +586,7 @@ def get_parameter_hdi_intervals(self, chain: Chain, column: ColumnName) -> list[ """ summary = self.get_parameter_summary_hdi(chain, column) default_interval = [(summary.lower, summary.upper)] - xs, ys, _ = self._get_smoothed_histogram(chain, column, pad=True, use_kde=False) + xs, ys, _ = self._get_smoothed_histogram(chain, column, pad=True, use_kde=chain.use_kde) # We look for the threshold that is the root of this function def mass_diff(threshold, density, xs, target): From f1b0db8787377a6998a70870f37c8ac1fdf3bdc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Dupourqu=C3=A9?= <49200287+renecotyfanboy@users.noreply.github.com> Date: Tue, 25 Nov 2025 22:30:18 +0100 Subject: [PATCH 06/11] Apply suggestion from @Copilot Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/chainconsumer/analysis.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chainconsumer/analysis.py b/src/chainconsumer/analysis.py index 1a4cd671..06d8069d 100644 --- a/src/chainconsumer/analysis.py +++ b/src/chainconsumer/analysis.py @@ -626,7 +626,7 @@ def get_parameter_multimodal_bounds( chain, column, pad=True, - use_kde=False if chain.multimodal else None, + use_kde=None, # Use default KDE setting for both unimodal and multimodal chains for consistency ) lower_limit, upper_limit = float(xs.min()), float(xs.max()) From 31594c95eab8d16851071703780208f82754d03b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Dupourqu=C3=A9?= <49200287+renecotyfanboy@users.noreply.github.com> Date: Tue, 25 Nov 2025 22:31:26 +0100 Subject: [PATCH 07/11] Update src/chainconsumer/plotter.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/chainconsumer/plotter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chainconsumer/plotter.py b/src/chainconsumer/plotter.py index 82a84908..bc4b723d 100644 --- a/src/chainconsumer/plotter.py +++ b/src/chainconsumer/plotter.py @@ -977,7 +977,7 @@ def _plot_bars( else: display_bounds = base_bound intervals = [(display_bounds.lower, display_bounds.upper)] - intervals = np.clip(intervals, a_min=xs.min(), a_max=xs.max()) + intervals = [(max(lower, xs.min()), min(upper, xs.max())) for lower, upper in intervals] for lower, upper_ in intervals: x = np.linspace(lower, upper_, 1000) From 4827d2b4d539449ac846b2bcc6c1d46501edadf0 Mon Sep 17 00:00:00 2001 From: renecotyfanboy Date: Tue, 25 Nov 2025 22:34:34 +0100 Subject: [PATCH 08/11] fix bugs introduced by copilot --- src/chainconsumer/analysis.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/chainconsumer/analysis.py b/src/chainconsumer/analysis.py index 06d8069d..4b1c4b24 100644 --- a/src/chainconsumer/analysis.py +++ b/src/chainconsumer/analysis.py @@ -586,7 +586,7 @@ def get_parameter_hdi_intervals(self, chain: Chain, column: ColumnName) -> list[ """ summary = self.get_parameter_summary_hdi(chain, column) default_interval = [(summary.lower, summary.upper)] - xs, ys, _ = self._get_smoothed_histogram(chain, column, pad=True, use_kde=chain.use_kde) + xs, ys, _ = self._get_smoothed_histogram(chain, column, pad=True) # We look for the threshold that is the root of this function def mass_diff(threshold, density, xs, target): @@ -626,7 +626,6 @@ def get_parameter_multimodal_bounds( chain, column, pad=True, - use_kde=None, # Use default KDE setting for both unimodal and multimodal chains for consistency ) lower_limit, upper_limit = float(xs.min()), float(xs.max()) From a37909f96446dcd2aa2a2ea7f043a8bd334cfe9f Mon Sep 17 00:00:00 2001 From: renecotyfanboy Date: Thu, 27 Nov 2025 10:29:57 +0100 Subject: [PATCH 09/11] implement suggestions --- src/chainconsumer/analysis.py | 25 +++++++++++-------------- src/chainconsumer/plotter.py | 3 +-- 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/src/chainconsumer/analysis.py b/src/chainconsumer/analysis.py index 4b1c4b24..464e0672 100644 --- a/src/chainconsumer/analysis.py +++ b/src/chainconsumer/analysis.py @@ -197,7 +197,7 @@ def get_summary( chains (dict[str, Chain] | list[str], optional): A list of chains to generate summaries for. Returns: - dict[ChainName, dict[ColumnName, Bound]]: A map from chain name to column name to bound. + dict[ChainName, dict[ColumnName, Bound | list[Bound]]]: A map from chain name to column name to bound. """ results = {} if chains is None: @@ -216,22 +216,19 @@ def get_summary( if chain.multimodal: intervals = self.get_parameter_hdi_intervals(chain, p) - # If there is a single interval, we skip - if len(intervals) < 2: - continue - - multimodal_bounds = self.get_parameter_multimodal_bounds( - chain, - p, - intervals=intervals, - ) - - if multimodal_bounds is not None: - res[p] = multimodal_bounds - continue + if len(intervals) >= 2: + multimodal_bounds = self.get_parameter_multimodal_bounds( + chain, + p, + intervals=intervals, + ) + if multimodal_bounds is not None: + res[p] = multimodal_bounds + continue res[p] = summary + results[chain.name] = res return results diff --git a/src/chainconsumer/plotter.py b/src/chainconsumer/plotter.py index bc4b723d..f4718651 100644 --- a/src/chainconsumer/plotter.py +++ b/src/chainconsumer/plotter.py @@ -1004,8 +1004,7 @@ def _plot_bars( if summary: label = self.config.get_label(column) - label_core = label.strip("$") if isinstance(column, str) else None - label_text = label_core or None + label_text = label.strip("$") if isinstance(column, str) else None title = self.parent.analysis.get_parameter_text( display_bounds, From c593c9157e01a0cb313f26257d87e1a1e791f8e6 Mon Sep 17 00:00:00 2001 From: renecotyfanboy Date: Thu, 11 Dec 2025 10:42:32 +0100 Subject: [PATCH 10/11] Modify the chain defaults --- src/chainconsumer/chain.py | 8 +++++++- tests/test_chain.py | 11 +++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/chainconsumer/chain.py b/src/chainconsumer/chain.py index 7c86b5b1..6f560c49 100644 --- a/src/chainconsumer/chain.py +++ b/src/chainconsumer/chain.py @@ -48,7 +48,7 @@ class ChainConfig(BetterBase): if you have two chains, you probably want them to be different colors. """ - statistics: SummaryStatistic = Field(default=SummaryStatistic.MAX, description="The summary statistic to use") + statistics: SummaryStatistic | None = Field(default=None, description="The summary statistic to use") summary_area: float = Field(default=0.6827, ge=0, le=1.0, description="The area to use for summary statistics") sigmas: list[float] = Field(default=[0, 1, 2], description="The sigmas to use for summary statistics") color: ColorInput | None = Field(default=None, description="The color of the chain") # type: ignore @@ -282,6 +282,12 @@ def _validate_model(self) -> Chain: if self.num_free_params is not None: assert np.isfinite(self.num_free_params), "num_free_params is not finite" + if self.statistics is None: + if self.multimodal: + self.statistics = SummaryStatistic.HDI + else: + self.statistics = SummaryStatistic.MAX + if self.multimodal and self.statistics is not SummaryStatistic.HDI: raise ValueError( f"Chain {self.name} is marked as multimodal but uses {self.statistics.value}; " diff --git a/tests/test_chain.py b/tests/test_chain.py index 6bf81be5..5d2f2187 100644 --- a/tests/test_chain.py +++ b/tests/test_chain.py @@ -4,6 +4,7 @@ from pydantic import ValidationError from chainconsumer.chain import Chain +from chainconsumer.statistics import SummaryStatistic class TestChain: @@ -105,3 +106,13 @@ def test_divide(self): for chain in result: assert chain.walkers == 1 + + def test_default_stat(self): + chain = Chain(samples=self.df, name=self.n) + assert chain.statistics is SummaryStatistic.MAX + + chain = Chain(samples=self.df, name=self.n, multimodal=True) + assert chain.statistics is SummaryStatistic.HDI + + with pytest.raises(ValueError): + Chain(samples=self.df, name=self.n, multimodal=True, statistics=SummaryStatistic.MAX) From 8da1218805d9f38ebba27b7555dec40f2dd3c89a Mon Sep 17 00:00:00 2001 From: renecotyfanboy Date: Thu, 11 Dec 2025 15:10:52 +0100 Subject: [PATCH 11/11] Update usage.mdf --- docs/resources/generate_stats.py | 81 +++++++++++++++++++++++++++++++ docs/resources/stats.png | Bin 52390 -> 30042 bytes docs/usage.md | 2 +- 3 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 docs/resources/generate_stats.py diff --git a/docs/resources/generate_stats.py b/docs/resources/generate_stats.py new file mode 100644 index 00000000..b3ceb941 --- /dev/null +++ b/docs/resources/generate_stats.py @@ -0,0 +1,81 @@ +import matplotlib +import matplotlib.pyplot as plt +import numpy as np +import pandas as pd +from matplotlib import rc +from scipy.stats import gamma + +from chainconsumer import Chain, ChainConsumer +from chainconsumer.statistics import SummaryStatistic + +# Activate latex text rendering +rc("font", family="serif", serif=["Computer Modern Roman"], size=13) +rc("text", usetex=True) +matplotlib.rcParams["text.latex.preamble"] = r"\usepackage{amsmath}" + +x = np.linspace(0, 5, 100) + +loc = 4 +scale = 0.45 + +fig, axs = plt.subplots(nrows=2, ncols=1, sharex=True, height_ratios=[0.5, 0.5], figsize=(5, 5)) +axs[0].plot(x, gamma.pdf(x, a=loc, scale=scale), color="black") +axs[1].plot(x, gamma.cdf(x, a=loc, scale=scale), color="black") + + +axs[1].set_xlabel("$x$") +axs[0].set_ylabel("$P(x)$") +axs[1].set_ylabel("$C(x)$") +axs[0].set_xlim(0, 5.0) +axs[0].set_ylim(0, 0.6) +axs[1].set_ylim(0, 1) + +samples = pd.DataFrame.from_dict({"gamma": gamma.rvs(size=10_000_000, a=loc, scale=scale)}) + +summary_list = [ + (SummaryStatistic.MAX, "MAX"), + (SummaryStatistic.CUMULATIVE, "CUMULATIVE"), + (SummaryStatistic.MEAN, "MEAN"), + (SummaryStatistic.HDI, "HDI"), +] + +chains = [] + +for summary, name in summary_list: + chains.append(Chain(samples=samples, statistics=summary, name=name)) + +cc = ChainConsumer() + +summary_result = cc.analysis.get_summary(chains=chains, columns=["gamma"]) + +for (_summary, name), color, linestyle, marker_style in zip( + summary_list, + ["r", "g", "b", "y"], + [":", "--", "-", "-."], + ["o", "^", "s", "*"], + strict=False, +): + bound = summary_result[name]["gamma"] + + x_min, x_mid, x_max = bound.lower, bound.center, bound.upper + + axs[0].scatter(x_mid, gamma.pdf(x_mid, a=loc, scale=scale), label=name, zorder=10, color=color, marker=marker_style) + axs[1].scatter(x_mid, gamma.cdf(x_mid, a=loc, scale=scale), zorder=10, color=color, marker=marker_style) + + axs[0].vlines( + x=x_min, ymin=0, ymax=gamma.pdf(x_min, a=loc, scale=scale), color=color, linestyle=linestyle, alpha=0.5 + ) + axs[0].vlines( + x=x_max, ymin=0, ymax=gamma.pdf(x_max, a=loc, scale=scale), color=color, linestyle=linestyle, alpha=0.5 + ) + + axs[1].hlines( + xmin=0, xmax=x_min, y=gamma.cdf(x_min, a=loc, scale=scale), color=color, linestyle=linestyle, alpha=0.5 + ) + axs[1].hlines( + xmin=0, xmax=x_max, y=gamma.cdf(x_max, a=loc, scale=scale), color=color, linestyle=linestyle, alpha=0.5 + ) + +axs[0].legend(fontsize=8) +plt.tight_layout() +plt.savefig("stats.png", bbox_inches="tight") diff --git a/docs/resources/stats.png b/docs/resources/stats.png index b7e501c992f88a6f552066a4a42ffaeeb9559437..6c2cb9388c3dd20a19b4b877432e6c7e1992b6d8 100644 GIT binary patch literal 30042 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℞||!msx|Uhyeuu7g!s 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