kdiagram.plot.evaluation.plot_pinball_loss

kdiagram.plot.evaluation.plot_pinball_loss(y_true, y_preds_quantiles, quantiles, names=None, title='Pinball Loss per Quantile', figsize=(8, 8), cmap='tab10', colors=None, show_grid=True, grid_props=None, mask_radius=False, acov='default', zero_at='E', clockwise=True, savefig=None, dpi=300, kind='polar', ax=None)[source]

Plots the Pinball Loss for each quantile of a forecast.

This function creates a polar plot to visualize the performance of a probabilistic forecast at each individual quantile level. The radius of the plot at a given angle (quantile) represents the average Pinball Loss, providing a granular view of the model’s accuracy across its entire predictive distribution.

Parameters:
y_truenp.ndarray

1D array of the true observed values.

y_preds_quantilesnp.ndarray

2D array of quantile forecasts, with shape (n_samples, n_quantiles).

quantilesnp.ndarray

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

nameslist of str, optional

Display names for each of the models. Note: This function currently supports plotting one model at a time.

titlestr, default=”Pinball Loss per Quantile”

The title for the plot.

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

The figure size in inches.

cmapstr, default=’viridis’

The colormap used for the plot’s fill and line.

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.

axAxes, optional

The Matplotlib Axes object to use for plotting. If None, a new figure and axes will be created.

kind{‘polar’, ‘cartesian’}, default=’polar’

Rendering mode selector. When set to 'polar' (default), the plot uses a Matplotlib polar projection and applies polar-specific options (acov, zero_at, clockwise) via internal helpers. When set to 'cartesian', the function delegates to a Cartesian renderer (through maybe_delegate_cartesian), keeping names/colors/figsize/grid behavior consistent while ignoring polar- only arguments (e.g., acov, zero_at, clockwise). The return value is always the Axes actually used. The value is validated with validate_kind (case-insensitive); invalid values raise ValueError("kind must be 'polar' or 'cartesian'.").

Returns:
axmatplotlib.axes.Axes

The Matplotlib Axes object containing the plot.

Parameters:

See also

compute_pinball_loss

The underlying mathematical utility.

compute_crps

A score calculated by averaging the pinball loss.

Evaluating Probabilistic Forecasts

The user guide for probabilistic plots.

Notes

The Pinball Loss, \(\mathcal{L}_{\tau}\), is a proper scoring rule for evaluating a single quantile forecast \(q\) at level \(\tau\) against an observation \(y\). It asymmetrically penalizes errors, giving a different weight to over- and under- predictions [1].

(1)\[\begin{split}\mathcal{L}_{\tau}(q, y) = \begin{cases} (y - q) \tau & \text{if } y \ge q \\ (q - y) (1 - \tau) & \text{if } y < q \end{cases}\end{split}\]

This plot calculates the average Pinball Loss for each provided quantile and visualizes these scores on a polar axis, where the angle represents the quantile level and the radius represents the loss. A good forecast will have a small, symmetrical shape close to the center.

References

Examples

>>> import numpy as np
>>> from scipy.stats import norm
>>> from kdiagram.plot.evaluation import plot_pinball_loss
>>>
>>> # Generate synthetic data
>>> np.random.seed(0)
>>> n_samples = 1000
>>> y_true = np.random.normal(loc=50, scale=10, size=n_samples)
>>> quantiles = np.array([0.1, 0.25, 0.5, 0.75, 0.9])
>>>
>>> # Simulate a model that is good at the median, worse at the tails
>>> scales = np.array([12, 10, 8, 10, 12]) # Different scales per quantile
>>> y_preds = norm.ppf(
...     quantiles, loc=y_true[:, np.newaxis], scale=scales
... )
>>>
>>> # Generate the plot
>>> ax = plot_pinball_loss(
...     y_true,
...     y_preds,
...     quantiles,
...     title="Pinball Loss per Quantile"
... )