Visualization Module¶
The temporalcv.viz module provides Tufte-inspired visualizations for cross-validation, gate results, and prediction intervals. All visualizations follow Edward Tufte’s principles for data graphics.
Tufte Principles Applied¶
Maximize data-ink ratio — Remove chartjunk, use minimal spines
Direct labeling — Label data directly, minimize legends
Muted colors — Avoid saturated colors that distract
Small multiples — Enable comparison through consistent formatting
When to Use¶
flowchart TD
Start[Need Visualization?] --> Q1{What are you visualizing?}
Q1 -->|CV folds| CVFoldsDisplay
Q1 -->|Gate results| GateDisplay[GateResultDisplay or GateComparisonDisplay]
Q1 -->|Prediction intervals| PredictionIntervalDisplay
Q1 -->|Model metrics| MetricComparisonDisplay
CVFoldsDisplay --> Usage1[Show train/test/gap structure]
GateDisplay --> Usage2[Show HALT/WARN/PASS status]
PredictionIntervalDisplay --> Usage3[Show coverage and width]
MetricComparisonDisplay --> Usage4[Compare MAE, RMSE across models]
API Patterns¶
The module provides two API styles:
sklearn-style Display Classes¶
Best for complex visualizations and method chaining:
from temporalcv.viz import CVFoldsDisplay
display = CVFoldsDisplay.from_cv(cv, X, y)
display.plot(tufte=True, title="Walk-Forward CV")
fig = display.figure_ # Access matplotlib figure
statsmodels-style Functions¶
Best for quick one-liners:
from temporalcv.viz import plot_cv_folds
ax = plot_cv_folds(cv, X, title="Walk-Forward CV")
plt.show()
Display Classes¶
CVFoldsDisplay¶
Visualize cross-validation fold structure with train/test/gap regions.
- class temporalcv.viz.CVFoldsDisplay(train_indices, test_indices, *, gap_indices=None, n_samples=None)[source]¶
Bases:
BaseDisplayVisualization of cross-validation fold structure.
Displays train/test splits as horizontal bars, with optional gap visualization for time series cross-validation.
- Parameters:
train_indices (
listofarray-like) – Training indices for each fold.test_indices (
listofarray-like) – Test indices for each fold.gap_indices (
listofarray-like, optional) – Gap indices for each fold (for walk-forward CV with gap).n_samples (
int, optional) – Total number of samples. Inferred from indices if not provided.
- ax_¶
The axes used for plotting.
- Type:
matplotlib.axes.Axes
- figure_¶
The figure containing the plot.
- Type:
matplotlib.figure.Figure
See also
temporalcv.WalkForwardCVWalk-forward cross-validator with gap.
temporalcv.cv_financial.PurgedKFoldPurged K-Fold for finance.
Examples
>>> from temporalcv import WalkForwardCV >>> from temporalcv.viz import CVFoldsDisplay >>> import numpy as np >>> >>> X = np.random.randn(200, 5) >>> y = np.random.randn(200) >>> cv = WalkForwardCV(n_splits=5, test_size=20, extra_gap=1) >>> >>> # From cross-validator >>> display = CVFoldsDisplay.from_cv(cv, X, y) >>> display.plot() >>> >>> # Or from pre-computed splits >>> splits = list(cv.split(X, y)) >>> display = CVFoldsDisplay.from_splits(splits) >>> display.plot()
- classmethod from_cv(cv, X, y=None, *, groups=None)[source]¶
Create display from a cross-validator object.
- Parameters:
cv (
cross-validator) – A scikit-learn compatible cross-validator with split() method.X (
array-likeofshape (n_samples,n_features)) – Training data.y (
array-likeofshape (n_samples,), optional) – Target values.groups (
array-likeofshape (n_samples,), optional) – Group labels for GroupKFold-like splitters.
- Returns:
The display object.
- Return type:
Examples
>>> from temporalcv import WalkForwardCV >>> cv = WalkForwardCV(n_splits=5, test_size=20) >>> display = CVFoldsDisplay.from_cv(cv, X, y)
- classmethod from_splits(splits, *, n_samples=None)[source]¶
Create display from pre-computed splits.
- Parameters:
- Returns:
The display object.
- Return type:
Examples
>>> splits = list(cv.split(X, y)) >>> display = CVFoldsDisplay.from_splits(splits, n_samples=len(X))
- plot(*, ax=None, tufte=True, bar_height=0.6, show_labels=True, title=None)[source]¶
Plot the cross-validation fold structure.
- Parameters:
ax (
matplotlib.axes.Axes, optional) – Axes to plot on. If None, creates new figure.tufte (
bool) – If True, apply Tufte styling (default).bar_height (
float) – Height of each fold bar (0-1).show_labels (
bool) – If True, show fold labels and sample counts.title (
str, optional) – Plot title. If None, uses default.
- Returns:
The display object for method chaining.
- Return type:
self
Examples
>>> display.plot(title="Walk-Forward CV Folds") >>> plt.tight_layout() >>> plt.show()
Example:
from temporalcv import WalkForwardCV
from temporalcv.viz import CVFoldsDisplay
cv = WalkForwardCV(n_splits=5, test_size=20, extra_gap=5)
display = CVFoldsDisplay.from_cv(cv, X, y)
display.plot(title="Walk-Forward with Gap")
GateResultDisplay¶
Visualize a single validation gate result (HALT/WARN/PASS).
- class temporalcv.viz.GateResultDisplay(name, status, message, *, metrics=None)[source]¶
Bases:
BaseDisplayVisualization of a single gate result.
Displays the gate status (HALT/WARN/PASS) with metric details.
- Parameters:
- ax_¶
The axes used for plotting.
- Type:
matplotlib.axes.Axes
- figure_¶
The figure containing the plot.
- Type:
matplotlib.figure.Figure
See also
temporalcv.gates.gate_signal_verificationSignal verification gate.
temporalcv.gates.gate_suspicious_improvementImprovement gate.
Examples
>>> from temporalcv.gates import gate_signal_verification >>> from temporalcv.viz import GateResultDisplay >>> >>> result = gate_signal_verification(model, X, y, n_shuffles=100) >>> display = GateResultDisplay.from_gate(result) >>> display.plot()
- classmethod from_gate(gate_result)[source]¶
Create display from a GateResult object.
- Parameters:
gate_result (
GateResult) – Result from a gate function (e.g., gate_signal_verification).- Returns:
The display object.
- Return type:
Examples
>>> result = gate_signal_verification(model, X, y) >>> display = GateResultDisplay.from_gate(result)
Example:
from temporalcv.gates import gate_signal_verification
from temporalcv.viz import GateResultDisplay
result = gate_signal_verification(model, X, y, n_shuffles=100)
display = GateResultDisplay.from_gate(result)
display.plot()
GateComparisonDisplay¶
Compare multiple gate results side by side.
- class temporalcv.viz.GateComparisonDisplay(names, statuses, messages=None)[source]¶
Bases:
BaseDisplayVisualization comparing multiple gate results.
Displays multiple gates side by side for a comprehensive view.
- Parameters:
- ax_¶
The axes used for plotting.
- Type:
matplotlib.axes.Axes
- figure_¶
The figure containing the plot.
- Type:
matplotlib.figure.Figure
See also
temporalcv.gates.run_gatesRun multiple gates.
GateResultDisplaySingle gate visualization.
Examples
>>> from temporalcv.gates import run_gates, gate_signal_verification >>> from temporalcv.viz import GateComparisonDisplay >>> >>> gates = [ ... gate_signal_verification(model, X, y), ... gate_suspicious_improvement(model_mae, baseline_mae), ... ] >>> report = run_gates(gates) >>> display = GateComparisonDisplay.from_report(report) >>> display.plot()
- classmethod from_gates(gate_results)[source]¶
Create display from a list of GateResult objects.
- Parameters:
gate_results (
listofGateResult) – Results from gate functions.- Returns:
The display object.
- Return type:
- classmethod from_report(report)[source]¶
Create display from a GateReport object.
- Parameters:
report (
GateReport) – Report from run_gates().- Returns:
The display object.
- Return type:
- plot(*, ax=None, tufte=True, orientation='horizontal', show_messages=False, title=None)[source]¶
Plot the gate comparison.
- Parameters:
ax (
matplotlib.axes.Axes, optional) – Axes to plot on. If None, creates new figure.tufte (
bool) – If True, apply Tufte styling (default).orientation (
str) – “horizontal” (bars left-right) or “vertical” (bars top-bottom).show_messages (
bool) – If True, show gate messages.title (
str, optional) – Plot title.
- Returns:
The display object for method chaining.
- Return type:
self
Example:
from temporalcv.gates import run_gates
from temporalcv.viz import GateComparisonDisplay
report = run_gates([gate1, gate2, gate3])
display = GateComparisonDisplay.from_report(report)
display.plot(orientation="horizontal")
PredictionIntervalDisplay¶
Visualize prediction intervals with coverage highlighting.
- class temporalcv.viz.PredictionIntervalDisplay(predictions, lower, upper, *, actuals=None, confidence=0.9, x=None)[source]¶
Bases:
BaseDisplayVisualization of prediction intervals with actuals.
Displays prediction intervals as a shaded region with actual values overlaid, highlighting coverage.
- Parameters:
predictions (
array-like) – Point predictions.lower (
array-like) – Lower bounds of intervals.upper (
array-like) – Upper bounds of intervals.actuals (
array-like, optional) – Actual values for coverage visualization.confidence (
float) – Confidence level (e.g., 0.90 for 90% intervals).x (np.ndarray | None)
- ax_¶
The axes used for plotting.
- Type:
matplotlib.axes.Axes
- figure_¶
The figure containing the plot.
- Type:
matplotlib.figure.Figure
See also
temporalcv.conformal.SplitConformalPredictorSplit conformal.
temporalcv.conformal.AdaptiveConformalPredictorAdaptive conformal.
Examples
>>> from temporalcv.conformal import SplitConformalPredictor >>> from temporalcv.viz import PredictionIntervalDisplay >>> >>> conformal = SplitConformalPredictor(alpha=0.10) >>> conformal.calibrate(cal_preds, cal_actuals) >>> intervals = conformal.predict_interval(test_preds) >>> >>> display = PredictionIntervalDisplay.from_conformal(intervals, test_actuals) >>> display.plot()
- Parameters:
- classmethod from_conformal(intervals, actuals=None, *, x=None)[source]¶
Create display from a PredictionInterval object.
- Parameters:
intervals (
PredictionInterval) – Prediction interval object from conformal predictor.actuals (
array-like, optional) – Actual values for coverage visualization.x (
array-like, optional) – X-axis values (e.g., time indices).
- Returns:
The display object.
- Return type:
Examples
>>> intervals = conformal.predict_interval(test_preds) >>> display = PredictionIntervalDisplay.from_conformal(intervals, test_actuals)
- classmethod from_predictions(predictions, lower, upper, *, actuals=None, confidence=0.9, x=None)[source]¶
Create display from arrays.
- Parameters:
predictions (
array-like) – Point predictions.lower (
array-like) – Lower bounds.upper (
array-like) – Upper bounds.actuals (
array-like, optional) – Actual values.confidence (
float) – Confidence level.x (
array-like, optional) – X-axis values.
- Returns:
The display object.
- Return type:
- plot(*, ax=None, tufte=True, show_predictions=True, show_actuals=True, show_coverage=True, title=None)[source]¶
Plot the prediction intervals.
- Parameters:
ax (
matplotlib.axes.Axes, optional) – Axes to plot on. If None, creates new figure.tufte (
bool) – If True, apply Tufte styling (default).show_predictions (
bool) – If True, show point predictions as line.show_actuals (
bool) – If True, show actual values.show_coverage (
bool) – If True, highlight covered/uncovered points.title (
str, optional) – Plot title.
- Returns:
The display object for method chaining.
- Return type:
self
Example:
from temporalcv.conformal import SplitConformalPredictor
from temporalcv.viz import PredictionIntervalDisplay
conformal = SplitConformalPredictor(alpha=0.10)
conformal.calibrate(cal_preds, cal_actuals)
intervals = conformal.predict_interval(test_preds)
display = PredictionIntervalDisplay.from_conformal(intervals, test_actuals)
display.plot(show_coverage=True)
display.plot_width() # Show interval width variation
MetricComparisonDisplay¶
Compare metrics across multiple models.
- class temporalcv.viz.MetricComparisonDisplay(model_names, metric_names, values, *, lower_is_better=None, baseline_idx=None)[source]¶
Bases:
BaseDisplayVisualization comparing metrics across models.
Displays metric comparisons as grouped bar charts with Tufte styling.
- Parameters:
- ax_¶
The axes used for plotting.
- Type:
matplotlib.axes.Axes
- figure_¶
The figure containing the plot.
- Type:
matplotlib.figure.Figure
See also
temporalcv.compare.compare_horizonsCompare across horizons.
temporalcv.compare.compare_modelsCompare model performance.
Examples
>>> from temporalcv.viz import MetricComparisonDisplay >>> >>> # From dictionary >>> results = {"Model A": {"MAE": 0.15}, "Model B": {"MAE": 0.12}} >>> display = MetricComparisonDisplay.from_dict(results) >>> display.plot() >>> >>> # From arrays >>> display = MetricComparisonDisplay.from_arrays( ... model_names=["A", "B"], ... metric_names=["MAE", "RMSE"], ... values=[[0.15, 0.22], [0.12, 0.19]], ... ) >>> display.plot()
- Parameters:
- classmethod from_dict(results, *, lower_is_better=None, baseline=None)[source]¶
Create display from a nested dictionary.
- Parameters:
- Returns:
The display object.
- Return type:
Examples
>>> results = { ... "Baseline": {"MAE": 0.20, "RMSE": 0.28}, ... "Model A": {"MAE": 0.15, "RMSE": 0.22}, ... } >>> display = MetricComparisonDisplay.from_dict(results, baseline="Baseline")
- classmethod from_arrays(model_names, metric_names, values, *, lower_is_better=None, baseline_idx=None)[source]¶
Create display from arrays.
- Parameters:
- Returns:
The display object.
- Return type:
- plot(*, ax=None, tufte=True, orientation='vertical', show_values=True, show_best=True, title=None, metric_idx=None)[source]¶
Plot the metric comparison.
- Parameters:
ax (
matplotlib.axes.Axes, optional) – Axes to plot on. If None, creates new figure.tufte (
bool) – If True, apply Tufte styling (default).orientation (
str) – “vertical” (bars go up) or “horizontal” (bars go right).show_values (
bool) – If True, show metric values on bars.show_best (
bool) – If True, highlight best model for each metric.title (
str, optional) – Plot title.metric_idx (
int, optional) – If provided, plot only this metric (useful for single-metric comparison).
- Returns:
The display object for method chaining.
- Return type:
self
Example:
from temporalcv.viz import MetricComparisonDisplay
results = {
"Baseline": {"MAE": 0.20, "RMSE": 0.28},
"Model A": {"MAE": 0.15, "RMSE": 0.22},
"Model B": {"MAE": 0.12, "RMSE": 0.19},
}
display = MetricComparisonDisplay.from_dict(results, baseline="Baseline")
display.plot(show_best=True) # Highlights best model per metric
display.plot_relative() # Shows % improvement vs baseline
Functions¶
plot_cv_folds¶
- temporalcv.viz.plot_cv_folds(cv, X, y=None, *, groups=None, ax=None, tufte=True, title=None)[source]¶
Plot cross-validation fold structure.
Convenience function wrapping CVFoldsDisplay.
- Parameters:
cv (
cross-validator) – A scikit-learn compatible cross-validator.X (
array-like) – Training data.y (
array-like, optional) – Target values.groups (
array-like, optional) – Group labels.ax (
matplotlib.axes.Axes, optional) – Axes to plot on. If None, creates new figure.tufte (
bool) – If True, apply Tufte styling (default).title (
str, optional) – Plot title.
- Returns:
The axes with the plot.
- Return type:
matplotlib.axes.Axes
Examples
>>> from temporalcv import WalkForwardCV >>> from temporalcv.viz import plot_cv_folds >>> >>> cv = WalkForwardCV(n_splits=5, test_size=20) >>> plot_cv_folds(cv, X, title="Walk-Forward CV") >>> plt.show()
See also
CVFoldsDisplayClass-based API for more customization.
plot_gate_result¶
- temporalcv.viz.plot_gate_result(gate_result, *, ax=None, tufte=True, show_message=True)[source]¶
Plot a single gate result.
Displays the gate status (HALT/WARN/PASS) with message.
- Parameters:
- Returns:
The axes with the plot.
- Return type:
matplotlib.axes.Axes
Examples
>>> from temporalcv.gates import gate_signal_verification >>> from temporalcv.viz import plot_gate_result >>> >>> result = gate_signal_verification(model, X, y, n_shuffles=100) >>> plot_gate_result(result) >>> plt.show()
See also
GateResultDisplayClass-based API.
plot_gate_comparisonCompare multiple gates.
plot_gate_comparison¶
- temporalcv.viz.plot_gate_comparison(gate_results, *, ax=None, tufte=True, orientation='horizontal', title=None)[source]¶
Plot comparison of multiple gate results.
Displays multiple gates side by side for a comprehensive view.
- Parameters:
gate_results (
listofGateResultorGateReport) – Results from gate functions or a GateReport from run_gates().ax (
matplotlib.axes.Axes, optional) – Axes to plot on.tufte (
bool) – If True, apply Tufte styling.orientation (
str) – “horizontal” (bars left-right) or “vertical” (bars top-bottom).title (
str, optional) – Plot title.
- Returns:
The axes with the plot.
- Return type:
matplotlib.axes.Axes
Examples
>>> from temporalcv.gates import run_gates, gate_signal_verification >>> from temporalcv.viz import plot_gate_comparison >>> >>> gates = [ ... gate_signal_verification(model, X, y), ... gate_suspicious_improvement(model_mae, baseline_mae), ... ] >>> report = run_gates(gates) >>> plot_gate_comparison(report, title="Validation Gates") >>> plt.show()
See also
GateComparisonDisplayClass-based API.
plot_gate_resultSingle gate visualization.
plot_prediction_intervals¶
- temporalcv.viz.plot_prediction_intervals(intervals, actuals=None, *, x=None, ax=None, tufte=True, show_coverage=True, title=None)[source]¶
Plot prediction intervals with actuals.
Convenience function wrapping PredictionIntervalDisplay.
- Parameters:
intervals (
PredictionInterval) – Prediction interval object from conformal predictor.actuals (
array-like, optional) – Actual values for coverage visualization.x (
array-like, optional) – X-axis values (e.g., time indices).ax (
matplotlib.axes.Axes, optional) – Axes to plot on.tufte (
bool) – If True, apply Tufte styling.show_coverage (
bool) – If True, highlight covered/uncovered points.title (
str, optional) – Plot title.
- Returns:
The axes with the plot.
- Return type:
matplotlib.axes.Axes
Examples
>>> from temporalcv.conformal import SplitConformalPredictor >>> from temporalcv.viz import plot_prediction_intervals >>> >>> conformal = SplitConformalPredictor(alpha=0.10) >>> conformal.calibrate(cal_preds, cal_actuals) >>> intervals = conformal.predict_interval(test_preds) >>> >>> plot_prediction_intervals(intervals, test_actuals) >>> plt.show()
See also
PredictionIntervalDisplayClass-based API.
plot_interval_width¶
- temporalcv.viz.plot_interval_width(intervals, *, x=None, ax=None, tufte=True, title=None)[source]¶
Plot prediction interval widths over time.
Useful for adaptive conformal where width varies.
- Parameters:
- Returns:
The axes with the plot.
- Return type:
matplotlib.axes.Axes
Examples
>>> from temporalcv.conformal import AdaptiveConformalPredictor >>> from temporalcv.viz import plot_interval_width >>> >>> adaptive = AdaptiveConformalPredictor(alpha=0.10, gamma=0.01) >>> # ... fit and predict ... >>> plot_interval_width(intervals) >>> plt.show()
See also
PredictionIntervalDisplay.plot_widthClass-based method.
plot_metric_comparison¶
- temporalcv.viz.plot_metric_comparison(results, *, ax=None, tufte=True, baseline=None, show_values=True, title=None)[source]¶
Plot metric comparison across models.
- Parameters:
results (
dict) – Nested dict of {model_name: {metric_name: value}}.ax (
matplotlib.axes.Axes, optional) – Axes to plot on.tufte (
bool) – If True, apply Tufte styling.baseline (
str, optional) – Name of baseline model for highlighting.show_values (
bool) – If True, show values on bars.title (
str, optional) – Plot title.
- Returns:
The axes with the plot.
- Return type:
matplotlib.axes.Axes
Examples
>>> from temporalcv.viz import plot_metric_comparison >>> >>> results = { ... "Model A": {"MAE": 0.15, "RMSE": 0.22}, ... "Model B": {"MAE": 0.12, "RMSE": 0.19}, ... } >>> plot_metric_comparison(results, baseline="Model A") >>> plt.show()
See also
MetricComparisonDisplayClass-based API.
Styling Primitives¶
For custom visualizations, use the low-level styling functions:
apply_tufte_style¶
Apply Tufte’s principles to any matplotlib axes:
from temporalcv.viz import apply_tufte_style
fig, ax = plt.subplots()
ax.plot(x, y)
apply_tufte_style(ax) # Removes top/right spines, subtle colors
- temporalcv.viz.apply_tufte_style(ax)[source]¶
Apply Tufte’s principles to a matplotlib axes.
Implements: - Remove top and right spines (maximize data-ink) - Subtle spine colors - Remove grid (or make very subtle) - Refined tick styling
- Parameters:
ax (
matplotlib.axes.Axes) – The axes to style.- Returns:
The styled axes (for chaining).
- Return type:
matplotlib.axes.Axes
Examples
>>> fig, ax = plt.subplots() >>> ax.plot([1, 2, 3], [1, 4, 2]) >>> apply_tufte_style(ax) >>> plt.show()
direct_label¶
Label data points directly (eliminates legends):
from temporalcv.viz import direct_label
ax.plot(x, y)
direct_label(ax, x[-1], y[-1], "Series A", offset=(5, 0))
- temporalcv.viz.direct_label(ax, x, y, text, offset=(5, 5), **kwargs)[source]¶
Add a direct label to a data point (Tufte principle: label on the data).
Direct labeling eliminates the need for legends, improving data-ink ratio.
- Parameters:
- Return type:
Examples
>>> fig, ax = plt.subplots() >>> ax.plot([1, 2, 3], [1, 4, 2]) >>> direct_label(ax, 2, 4, "Peak", offset=(5, 5))
create_tufte_figure¶
Create a figure with Tufte styling pre-applied:
from temporalcv.viz import create_tufte_figure
fig, axes = create_tufte_figure(nrows=2, ncols=2)
# All axes already have Tufte styling
Color Palettes¶
from temporalcv.viz import TUFTE_PALETTE, COLORS
# TUFTE_PALETTE: primary, secondary, accent, success, warning, etc.
# COLORS: train, test, gap, pass, warn, halt, prediction, actual
Common Patterns¶
Subplot Layout¶
from temporalcv.viz import (
CVFoldsDisplay,
GateComparisonDisplay,
create_tufte_figure,
)
fig, (ax1, ax2) = create_tufte_figure(nrows=1, ncols=2, figsize=(12, 4))
CVFoldsDisplay.from_cv(cv, X).plot(ax=ax1, title="CV Structure")
GateComparisonDisplay.from_report(report).plot(ax=ax2, title="Gates")
plt.tight_layout()
Saving Figures¶
display = CVFoldsDisplay.from_cv(cv, X)
display.plot()
# High-quality PNG for reports
display.figure_.savefig("cv_folds.png", dpi=300, bbox_inches="tight")
# Vector format for publication
display.figure_.savefig("cv_folds.svg", format="svg", bbox_inches="tight")
Disabling Tufte Style¶
If you prefer matplotlib defaults:
display.plot(tufte=False) # Use default matplotlib styling
See Also¶
Example 00: Quickstart — Basic visualization usage
Example 05: Conformal Prediction — Interval visualization
Example 16: Failure Case - Rolling Stats — Gate visualization
References¶
Tufte, E. R. (1983). The Visual Display of Quantitative Information.
Tufte, E. R. (2001). Envisioning Information.