kdiagram.plot.anomaly.plot_anomaly_severity

kdiagram.plot.anomaly.plot_anomaly_severity(df, actual_col, q_low_col, q_up_col, *, window_size=21, title=None, figsize=(9.0, 9.0), cmap='plasma', s=40, alpha=0.8, acov='default', mask_angle=True, mask_radius=False, show_grid=True, grid_props=None, ax=None, savefig=None, **kwargs)[source]

Visualizes clustered anomaly severity using a polar scatter plot.

This function creates a diagnostic plot to analyze forecast failures. It identifies anomalies where the true value falls outside the predicted interval and visualizes their location, magnitude, type, and clustering density in a single, compact polar view.

Parameters:
dfpd.DataFrame

The input DataFrame containing the actual and predicted quantile values.

actual_colstr

The name of the column containing the true observed values.

q_low_colstr

The name of the column for the lower bound of the prediction interval.

q_up_colstr

The name of the column for the upper bound of the prediction interval.

window_sizeint, default=21

The size of the moving window used to calculate the local density of anomalies, which defines a “cluster”.

titlestr, optional

A custom title for the plot. If None, a default title including the CAS score is generated.

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

The figure size in inches.

cmapstr, default=’plasma’

The colormap for coloring points based on local density.

sint, default=40

The marker size for the scatter points.

alphafloat, default=0.8

The transparency of the scatter points.

acov{‘default’, ‘half_circle’, ‘quarter_circle’, ‘eighth_circle’},

default=’default’

Specifies the angular coverage of the polar plot.

mask_anglebool, default=True

If True, hides the angular tick labels (e.g., degrees).

mask_radiusbool, default=False

If True, hides the radial tick labels.

axmatplotlib.axes.Axes, optional

An existing polar axes to draw the plot on. If None, a new figure and axes are created.

savefigstr, optional

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

Returns:
axmatplotlib.axes.Axes or None

The Matplotlib Axes object containing the plot, or None if no anomalies are detected in the data.

Parameters:
Return type:

Axes | None

See also

plot_anomaly_profile

A stylized “fiery ring” version of this plot.

plot_anomaly_glyphs

A version using informative glyphs instead of dots.

clustered_anomaly_severity_score

The underlying metric function.

Notes

This plot visualizes the four key dimensions of forecast failures as described in Kouadio and Liu[1].

Visual Mapping:

  • Angle (:math:`varepsilon`): The sample index, showing where in the dataset the failure occurred.

  • Radius (`r`): The Anomaly Magnitude—the distance from the true value to the nearest violated interval bound. Larger radii indicate more severe failures.

  • Color: The Local Anomaly Density. Hotter colors indicate the anomaly is part of a dense cluster of other failures.

  • Marker Shape: The Type of anomaly.

    • ‘o’ (circle): Over-prediction (risk was underestimated).

    • ‘X’: Under-prediction (risk was overestimated).

The title of the plot automatically includes the overall Clustered Anomaly Severity (CAS) score for a quantitative summary.

References

Examples

>>> import numpy as np
>>> import pandas as pd
>>> from kdiagram.plot.anomaly import plot_anomaly_severity
>>>
>>> # Simulate data with a cluster of severe failures
>>> np.random.seed(0)
>>> n_samples = 400
>>> y_true = 100 + 20 * np.sin(np.linspace(0, 4*np.pi, n_samples))
>>> y_qlow = y_true - 10
>>> y_qup = y_true + 10
>>> y_true[100:140] = y_qup[100:140] + np.random.uniform(10, 25, 40)
>>>
>>> df = pd.DataFrame({
...     "actual": y_true, "q10": y_qlow, "q90": y_qup
... })
>>>
>>> ax = plot_anomaly_severity(
...     df,
...     actual_col="actual",
...     q_low_col="q10",
...     q_up_col="q90",
...     window_size=31,
...     title="Severity of Clustered Anomalies"
... )