kdiagram.plot.anomaly.plot_anomaly_profile¶
- kdiagram.plot.anomaly.plot_anomaly_profile(df, actual_col, q_low_col, q_up_col, *, window_size=21, theta_bins=72, title=None, figsize=(9.0, 9.0), cmap='plasma', colors=None, alpha=0.8, acov='default', show_grid=True, grid_props=None, ax=None, savefig=None, jitter=0.85, max_flares_per_bin=None, flare_scale='sqrt', flare_clip=None, flare_linewidth=1.4, ring_height=0.06, ring_alpha=0.95, legend_anchor=(1.35, 1.04), **kwargs)[source]¶
Visualize anomaly severity as a polar profile or “fiery ring”.
This figure emphasizes readability for papers. It encodes clustered anomaly density as a colored ring, and shows each failed sample as a short “flare” growing inward or outward. The design avoids overlap by angular binning and in–bin dodging.
- Parameters:
- df
pandas.DataFrame Input table that holds the observed series and the two prediction bounds. Missing rows are dropped.
- actual_col
str Column name of the observed values.
- q_low_col
str Column name of the lower prediction bound.
- q_up_col
str Column name of the upper prediction bound.
- window_size
int, default=21 Window length used to compute the local anomaly density. Odd values are recommended for symmetric windows.
- theta_bins
int, default=72 Number of angular bins used for the density ring and to group flares for anti-overlap dodging.
- title
str,optional Figure title. If not given, a title including the CAS score is used.
- figsize
tupleoffloat, default=(9.0, 9.0) Figure size in inches.
- cmap
str, default=’plasma’ Colormap used for the density ring.
- colors
listofstr,optional Two colors for the flares (over, under). If not given, defaults are chosen.
- alpha
float, default=0.8 Global alpha for flare lines.
- acov{‘default’,’half_circle’,’quarter_circle’,
‘eighth_circle’}, default=’default’
Angular coverage preset. This controls the polar span.
- show_gridbool, default=True
If True, show a light polar grid.
- grid_props
dict,optional Keyword arguments forwarded to the grid styling helper.
- ax
matplotlib.axes.Axes,optional Existing polar axes. If None, a new figure is created.
- savefig
str,optional Path to save the figure. If None, the figure is shown.
- jitter
float, default=0.85 Fraction of bin width used to spread flares within each bin to reduce overlap. Clipped to [0, 1].
- max_flares_per_bin
int,optional If given, at most this many flares are drawn per bin. The largest magnitudes are kept.
- flare_scale{‘linear’,’sqrt’,’log’}, default=’sqrt’
Transform applied to anomaly magnitude before mapping to flare length. Use ‘sqrt’ or ‘log’ to tame outliers.
- flare_clip
float,optional Maximum flare length after scaling. If None, no clipping is applied.
- flare_linewidth
float, default=1.4 Line width of the flares.
- ring_height
float, default=0.06 Radial thickness of the density ring.
- ring_alpha
float, default=0.95 Alpha value for the density ring.
- legend_anchor
tupleoffloat, default=(1.35, 1.04) Anchor for the legend box (axes coordinates).
- df
- Returns:
- ax
matplotlib.axes.AxesorNone The polar axes with the plot. Returns None if no anomaly is detected after preprocessing.
- ax
- Parameters:
df (DataFrame)
actual_col (str)
q_low_col (str)
q_up_col (str)
window_size (int)
theta_bins (int)
title (str | None)
cmap (str)
alpha (float)
acov (str)
show_grid (bool)
grid_props (dict)
ax (Axes | None)
savefig (str | None)
jitter (float)
max_flares_per_bin (int | None)
flare_scale (str)
flare_clip (float | None)
flare_linewidth (float)
ring_height (float)
ring_alpha (float)
kwargs (Any)
- Return type:
Axes | None
See also
plot_anomaly_severityPolar scatter of anomaly points.
plot_anomaly_glyphsGlyph-based variant with richer marks.
clustered_anomaly_severityMetric used by this plot.
Notes
Visual mapping.
Angle \(\varepsilon\): encodes sample position (index order).
Ring color: mean local anomaly density within each angular bin. Hot colors indicate clustered failures.
Flares: one per failed sample.
Length: anomaly magnitude (scaled and optionally clipped).
Direction: type. Outward = over-prediction. Inward = under-prediction.
Anomalies.
A point is an anomaly when the observed value lies outside the prediction interval. Density is computed with a moving window of length
window_sizeand then averaged within bins.Styling and overlap control. Angular binning plus in-bin jitter reduce overlap. Use
theta_binsto raise angular resolution,jitterto control spread,max_flares_per_binto cap clutter, andflare_scaleorflare_clipto keep lengths balanced.References
[1]Kouadio, K. L., et al. 2025. CAS: Cluster-Aware Scoring for Probabilistic Forecasts. in review.
[2]Gneiting, T., and Raftery, A. E. 2007. Strictly proper scoring rules, prediction, and estimation. JASA, 102(477), 359–378.
Examples
>>> import numpy as np >>> import pandas as pd >>> from kdiagram.plot.anomaly import plot_anomaly_profile >>> rng = np.random.default_rng(30) >>> n = 500 >>> base = np.sin(np.linspace(0, 6*np.pi, n)) * 10 + 20 >>> qlow = base - 5 >>> qup = base + 5 >>> y = base.copy() >>> y[100:130] += rng.uniform(6, 12, 30) # over >>> y[300:330] -= rng.uniform(6, 12, 30) # under >>> df = pd.DataFrame({'actual': y, 'q10': qlow, 'q90': qup}) >>> ax = plot_anomaly_profile( ... df, ... actual_col='actual', ... q_low_col='q10', ... q_up_col='q90', ... window_size=31, ... theta_bins=96, ... jitter=0.9, ... ) >>> _ = ax.figure # keep handle for saving outside