plots

Plotting utilities to surface metric-to-metric relationships.

These plots make the sample-vs-alarm gap (Andrade 2024), threshold sensitivity, cadence sensitivity, and IoC vs surrogate transparent. All return (fig, ax); none save to disk — that’s the caller’s job.

scitex_seizure_metrics.plots.cadence_ablation(sweep_df, *, ax=None, x='cadence_s', y='fp_per_hour', logx=True)[source]

How does FP/hr (or any metric) move as we change the cadence? Input: forecasting.sweep_policies output sorted by cadence.

Parameters:
scitex_seizure_metrics.plots.ioc_vs_surrogate(sweep_df, *, ax=None)[source]

IoC (sensitivity − surrogate_sensitivity) across thresholds. Useful to see the threshold range where the model truly beats chance.

scitex_seizure_metrics.plots.metric_correlation_heatmap(per_patient_df, *, ax=None, metrics=None, method='spearman')[source]

Heatmap of metric-to-metric correlations across patients. Surfaces redundancy (“this metric tells us nothing new”) and the sample-vs-alarm divergence axis.

Parameters:

method (str)

scitex_seizure_metrics.plots.reliability_diagram(cal_report, *, ax=None, title='Reliability diagram')[source]

Plot a reliability diagram from a CalibrationReport.

The dashed identity line represents perfect calibration. Bin counts are shown via marker size.

Parameters:

title (str)

scitex_seizure_metrics.plots.sample_vs_alarm_scatter(per_patient_df, *, ax=None, x_metric='roc_auc', y_metric='sensitivity')[source]

Reproduce the Andrade 2024 finding: per-patient sample-based AUC vs alarm-based sensitivity. Identity line shows the (false) hope of direct correspondence.

Parameters:
  • x_metric (str)

  • y_metric (str)

scitex_seizure_metrics.plots.sensitivity_tiw(curves, *, ax=None, percent=True, show_chance=True, mark_operating_point=True, labels=None, aspect=1.0, save_path=None)[source]

Sensitivity vs time-in-warning trade-off (Karoly 2017 Fig 6).

The field-standard forecasting view: each subject’s empirical operating curve plotted as sensitivity (y) against time-in-warning (x), overlaid on the chance diagonal (sensitivity == TiW). A curve above the diagonal carries signal beyond a time-matched coin.

The drawn curve is each subject’s monotone upper envelope — the best sensitivity achievable at each time-in-warning budget (a forecaster can always discard signal to slide down-left, so the envelope is the meaningful operating frontier). Drawing the envelope guarantees the target-budget operating-point marker sits on the curve rather than floating above or below a linearly-interpolated raw polyline.

Parameters:
  • curves – a single SensitivityTiWCurve or an iterable of them (one line per subject).

  • ax – existing axis to draw on; a new figure is made if None.

  • percent (bool) – show axes as percentages (0-100) instead of fractions.

  • show_chance (bool) – overlay the chance diagonal.

  • mark_operating_point (bool) – mark each curve’s sensitivity-at-target-TiW operating point (lands on the envelope).

  • labels – optional list of legend labels (one per curve); falls back to each curve’s .name (capital-first).

  • aspect (float) – data aspect ratio (height / width). Defaults to 1.0 so the square 0-100 % axes are visually square; pass "auto" to let matplotlib stretch to the axes box.

  • save_path (str | None) – if given, save the figure as both .png and .pdf (the extension of save_path is ignored).

Returns:

(fig, ax). Following package convention, nothing is written to disk unless save_path is supplied.

References

Karoly PJ et al., Brain 2017; 140: 2169 (Fig 6). Karoly 2019.

scitex_seizure_metrics.plots.sensitivity_vs_fp_per_hour(sweep_df, *, ax=None, acceptable_fp_per_hour=0.15, wearable_fp_per_hour=0.042)[source]

Operating-curve plot from forecasting.sweep_thresholds output.

Plots sensitivity (y) vs FP/hr (x). Optional reference lines for Mormann’s 0.15/h and the wearable target 0.042/h.

Parameters:
  • acceptable_fp_per_hour (float | None)

  • wearable_fp_per_hour (float | None)