kdiagram.plot.probabilistic.plot_calibration_sharpness

kdiagram.plot.probabilistic.plot_calibration_sharpness(y_true, *y_preds_quantiles, quantiles, names=None, title='Calibration vs. Sharpness Trade-off', figsize=(8.0, 8.0), cmap='viridis', marker='o', s=150, acov='default', show_grid=True, grid_props=None, mask_radius=False, savefig=None, dpi=300, ax=None)[source]

Plots a Polar Calibration-Sharpness Diagram.

This function creates a polar plot to visualize the fundamental trade-off between forecast calibration (reliability) and sharpness (precision) for one or more models. Each model is represented by a single point, allowing for a direct and intuitive comparison of their overall probabilistic performance.

The ideal forecast is located at the center of the plot, representing perfect calibration and perfect sharpness.

Parameters:
y_truenp.ndarray

1D array of observed (true) values.

*y_preds_quantilesnp.ndarray

One or more 2D arrays of quantile forecasts. Each array corresponds to a different model, with shape (n_samples, n_quantiles).

quantilesnp.ndarray

1D array of the quantile levels corresponding to the columns of the prediction arrays.

nameslist of str, optional

Display names for each of the models. If not provided, generic names like 'Model 1' will be generated.

titlestr, default=”Calibration vs. Sharpness Trade-off”

The title for the plot.

figsizetuple of (float, float), default=(8, 8)

The figure size in inches.

cmapstr, default=’viridis’

The colormap used to assign a unique color to each model’s marker.

markerstr, default=’o’

The marker style for the points representing each model.

sint, default=150

The size of the markers.

show_gridbool, default=True

Toggle the visibility of the polar grid lines.

grid_propsdict, optional

Custom keyword arguments passed to the grid for styling.

mask_radiusbool, default=False

If True, hide the radial tick labels.

savefigstr, optional

The file path to save the plot. If None, the plot is displayed interactively.

dpiint, default=300

The resolution (dots per inch) for the saved figure.

Returns:
axmatplotlib.axes.Axes

The Matplotlib Axes object containing the plot.

Parameters:
Return type:

Axes

Notes

This plot synthesizes two key aspects of a probabilistic forecast into a single point for each model. It is a novel visualization developed as part of the analytics framework in Kouadio[1].

  1. Sharpness (Radius): The radial coordinate represents the forecast’s sharpness, calculated as the average width of the prediction interval between the lowest and highest provided quantiles. A smaller radius is better (sharper).

    (1)\[S = \frac{1}{N} \sum_{i=1}^{N} (y_{i, q_{max}} - y_{i, q_{min}})\]
  2. Calibration Error (Angle): The angular coordinate represents the forecast’s calibration error. This is quantified by first calculating the Probability Integral Transform (PIT) values for each observation. The Kolmogorov-Smirnov (KS) statistic is then used to measure the maximum distance between the empirical CDF of these PIT values and the CDF of a perfect uniform distribution.

    (2)\[E_{calib} = \sup_{x} | F_{PIT}(x) - U(x) |\]

    An error of 0 indicates perfect calibration. The angle is mapped such that \(\theta = E_{calib} \cdot \frac{\pi}{2}\), so 0° is perfect and 90° is the worst possible calibration.

References

Examples

>>> import numpy as np
>>> from scipy.stats import norm
>>> from kdiagram.plot.probabilistic import plot_calibration_sharpness
>>>
>>> # Generate synthetic data
>>> np.random.seed(42)
>>> n_samples = 1000
>>> y_true = np.random.normal(loc=10, scale=5, size=n_samples)
>>> quantiles = np.linspace(0.05, 0.95, 19)
>>>
>>> # Create forecasts for three models with different trade-offs
>>> model_A = norm.ppf(
...     quantiles, loc=y_true[:, np.newaxis], scale=5
... ) # Balanced
>>> model_B = norm.ppf(
...     quantiles, loc=y_true[:, np.newaxis] - 2, scale=3
... ) # Sharp but biased
>>> model_C = norm.ppf(
...     quantiles, loc=y_true[:, np.newaxis], scale=8
... ) # Calibrated but wide
>>>
>>> # Generate the plot
>>> ax = plot_calibration_sharpness(
...     y_true,
...     model_A, model_B, model_C,
...     quantiles=quantiles,
...     names=["Balanced", "Sharp/Biased", "Calibrated/Wide"]
... )