Visualisation API¶
Visualisation APIs cover reward/safety plots, episodic plots, shield telemetry, legends, and styling helpers used by notebooks.
Reward and Safety Figures¶
src.visualisation.reward_safety.plot_cum_reward_and_safety_side_by_side ¶
plot_cum_reward_and_safety_side_by_side(
*,
figure_title: str | None = None,
smooth=False,
smooth_kind="moving",
smooth_window=21,
ema_alpha=0.15,
smooth_points=800,
show_seed_traces=False,
show_level_changes: bool = True,
level_line_aggregate: str = "median",
annotate_level_changes: bool = True,
wm_hist: list[Iterable] | None = None,
wm_prepend_to: str | Iterable[str] = "IPPO_Shielded",
show_world_model_line: bool = True,
wm_line_aggregate: str = "median",
annotate_world_model_line: bool = True,
truncate_to_smallest: bool = False,
band: str = "ci95",
include_legend: bool = True,
paper_panel: bool = False,
save_path: str | None = None,
**alg_histories,
)
Example
plot_cum_reward_and_safety_side_by_side( IPPO=ippo_histories, IPPO_Lag=ippo_lag_histories, smooth=True, smooth_kind="moving", smooth_window=21, smooth_points=800 )
src.visualisation.reward_safety_episodic.plot_reward_and_safety_episodic ¶
plot_reward_and_safety_episodic(
*,
figure_title: str | None = None,
smooth: bool = False,
smooth_kind: str = "moving",
smooth_window: int = 21,
ema_alpha: float = 0.15,
smooth_points: int = 800,
show_seed_traces: bool = False,
reward_per_step: bool = False,
safety_per_step: bool = False,
show_level_changes: bool = True,
level_line_aggregate: str = "median",
annotate_level_changes: bool = True,
wm_hist: list[Iterable] | None = None,
wm_prepend_to: str | Iterable[str] = "IPPO_Shielded",
show_world_model_line: bool = True,
wm_line_aggregate: str = "median",
annotate_world_model_line: bool = True,
truncate_to_smallest: bool = False,
band: str = "ci95",
include_legend: bool = True,
paper_panel: bool = False,
save_path: str | None = None,
**alg_histories,
)
Episodic view:
Left panel: per-episode violations Right panel: per-episode reward
For each episode
x = t_end (global timestep where the episode terminated) y = cum_violations or cum_reward for that episode.
If *_per_step=True, y is divided by ep_len (episode length) so you get average per-step violation / reward within the episode.
src.visualisation.reward_safety_episodic.plot_episode_metric_series ¶
plot_episode_metric_series(
*,
metric_key: str,
ylabel: str,
title: str = "",
smooth: bool = False,
smooth_kind: str = "moving",
smooth_window: int = 21,
ema_alpha: float = 0.15,
smooth_points: int = 800,
show_seed_traces: bool = False,
wm_hist: list[Iterable] | None = None,
wm_prepend_to: str | Iterable[str] = "IPPO_Shielded",
truncate_to_smallest: bool = False,
band: str = "ci95",
include_legend: bool = True,
paper_panel: bool = False,
lower_clip: float | None = None,
save_path: str | None = None,
**alg_histories,
)
Plot one completed-episode metric against each episode's end timestep.
src.visualisation.reward_safety_episodic.export_episode_graph_variants ¶
export_episode_graph_variants(
output_dir: str | Path,
*,
episode_return_key: str = "cum_reward",
episode_safety_key: str = "cum_violations",
episode_return_ylabel: str = "Episode Return",
episode_safety_ylabel: str = "Episode Safety Violations",
smooth: bool = True,
smooth_kind: str = "moving",
smooth_window: int = 21,
ema_alpha: float = 0.15,
smooth_points: int = 800,
show_seed_traces: bool = False,
wm_hist: list[Iterable] | None = None,
wm_prepend_to: str | Iterable[str] = "IPPO_Shielded",
truncate_to_smallest: bool = False,
band: str = "ci95",
**alg_histories,
) -> dict[str, Path]
Export titleless completed-episode graph variants for all and shielded runs.
src.visualisation.shield_telemetry.plot_shield_telemetry ¶
plot_shield_telemetry(
*,
figure_title: str | None = None,
smooth: bool = False,
smooth_kind: str = "moving",
smooth_window: int = 21,
smooth_points: int = 800,
ema_alpha: float = 0.15,
band: str = "ci95",
include_legend: bool = True,
paper_panel: bool = False,
save_path: str | None = None,
**alg_histories,
)
Opponent-Level Figures¶
src.visualisation.levels.extract_bayesian_level_series ¶
Reconstruct the unconstrained Bayesian posterior-mode step series.
src.visualisation.levels.extract_monotone_floor_series ¶
src.visualisation.levels.plot_om_bayesian_levels ¶
plot_om_bayesian_levels(
*,
figure_title: str | None = None,
include_legend: bool = True,
save_path: str | Path | None = None,
show: bool = False,
smooth: bool = False,
smooth_kind: str = "moving",
smooth_window: int = 21,
smooth_points: int = 800,
ema_alpha: float = 0.15,
band: str = "ci95",
paper_panel: bool = False,
**alg_histories: Mapping[str, list[Iterable]],
)
Plot raw Bayesian OM modes and the shield's separate monotone floor.
One faint step line is shown per seed so decreases and switches are not hidden by averaging. Plotting reads episode logs only and performs no new environment interactions.
Legends¶
src.visualisation.legend.ExperimentLegendVariant
dataclass
¶
src.visualisation.legend.build_experiment_legend_handles ¶
build_experiment_legend_handles(
algorithm_labels: tuple[str, ...],
*,
include_world_model_line: bool = True,
include_shield_level_change: bool = True,
) -> list[Line2D]
src.visualisation.legend.export_experiment_legend ¶
export_experiment_legend(
save_path: str | Path,
*,
algorithm_labels: tuple[str, ...],
include_world_model_line: bool = True,
include_shield_level_change: bool = True,
single_row: bool = False,
) -> Path
src.visualisation.legend.export_experiment_legend_variants ¶
Shared Plot Helpers¶
src.visualisation.common.build_seed_series ¶
src.visualisation.common.summarize_band ¶
Align seeds on the union timestep grid; forward-fill within each seed range. Returns grid, mean, lower, upper.
band
- "minmax": lower=min across seeds, upper=max across seeds
- "std": lower=mean-std, upper=mean+std
- "ci95": 95% CI for the mean: mean ± tcrit * (std / sqrt(n))
src.visualisation.common.smooth_curve ¶
Resample to a uniform grid then smooth. kind: "moving" (centered moving average) or "ema" (exponential). window: odd window size for 'moving'. points: number of x samples.
src.visualisation.common.draw_event_line ¶
draw_event_line(
ax,
t: float,
*,
label: str,
kind: str = "dotted",
annotate: str | None = None,
color: str = "0.15",
lw: float | None = None,
alpha: float | None = None,
zorder: int = 1,
dashes: tuple[float, float] | None = None,
text_kwargs: dict | None = None,
)