Worked example: plot_roc_curve — annotated ROC with threshold marker#
What this shows. ROC curve rendering for a binary classifier, with an optional decision-threshold marker + baseline overlay. Sibling primitive to
plot_pr_curve. Shipped in v0.33.0 (closes upstream issue #14).Runtime: <1 s. Requires
[plotting]extra.
Setup#
import numpy as np
import matplotlib
matplotlib.use("Agg") # headless backend for docs build
import matplotlib.pyplot as plt
from eval_toolkit import plot_roc_curve, set_global_seeds
set_global_seeds(42)
Synthetic data: discriminative scorer#
rng = np.random.default_rng(42)
n = 200
y = np.concatenate([np.zeros(100, dtype=int), np.ones(100, dtype=int)])
rng.shuffle(y)
# Signal-with-noise: positives have a 0.5-shift over negatives.
score = y * 0.5 + rng.uniform(0, 0.5, size=n)
Basic ROC#
fig = plot_roc_curve(y, score, title="Synthetic discriminative scorer")
# fig is a matplotlib.figure.Figure — caller owns lifecycle.
assert fig is not None
plt.close(fig)
The diagonal chance line is drawn automatically (per plot_pr_curve’s
prevalence-line convention).
With threshold marker#
The threshold= kwarg marks the (FPR, TPR) pair closest to the requested
score-threshold — useful for showing where a deployed decision boundary
sits on the ROC.
fig = plot_roc_curve(
y, score,
threshold=0.5, # deployment threshold
title="ROC with decision threshold @ 0.5",
)
plt.close(fig)
With baseline overlay#
For comparing against a baseline scorer’s ROC (e.g., last release vs
current), pass baseline_curve=(fpr, tpr):
from sklearn.metrics import roc_curve as sklearn_roc
# A weaker baseline scorer for comparison.
baseline_score = y * 0.2 + rng.uniform(0, 0.5, size=n)
fpr_base, tpr_base, _ = sklearn_roc(y, baseline_score)
fig = plot_roc_curve(
y, score,
label="current",
baseline_curve=(fpr_base, tpr_base),
baseline_label="prior_release",
title="Current vs prior-release ROC",
)
plt.close(fig)
The baseline is drawn in a muted color (the PALETTE["baseline"] slot);
the current scorer in the accent color.
With caller-managed ax#
For composite figures (e.g., side-by-side ROC + PR), pass an existing
Axes:
fig, (ax_roc, ax_pr) = plt.subplots(1, 2, figsize=(10, 4))
plot_roc_curve(y, score, ax=ax_roc, title="ROC")
# (plot_pr_curve(y, score, ax=ax_pr) — analogous)
plt.close(fig)
plot_roc_curve returns the parent Figure regardless of the ax path
(consistent with plot_pr_curve and the other v0.33.0+ plotting fns —
all 6 accept ax= except plot_confusion_matrix_grid which is
intrinsically grid-shaped).
Common pitfalls#
Single-class
y_true: ROC is undefined wheny_trueis all 0s or all 1s. The fn raisesValueError— guard upstream for slices that might collapse to a single class.Score scale:
y_scoremust be monotone-equivalent to “higher = more positive”. If your scores are inverted (lower = more positive), negate them before plotting.
See also#
plot_pr_curve()(API) — sibling primitive for precision-recall curvesplot_reliability_diagram()for the calibration story