figs: a5 dedup title->axis arrow + CSV, overlay onset dot->labeled vline

- a5: drop per-panel title (restated the axis); fold direction into the xlabel
  (DEPLOY hack rate (down=better) / solve (up=better)). Dump a5_generalisation.csv
  (per mode,arm deploy hack/solve mean+/-std) -- the reproducibility source it lacked.
- overlay (dyn_sub4_hack_overlay etc): replace the per-arm onset DOT with a single
  dashed labeled 'first hack' vertical line, matching the small-multiples/longrun.
- (dyn_sub4_hack_overlay shares dyn_sub4.csv -- same runs, different view, no new CSV.)

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
This commit is contained in:
wassname
2026-06-05 04:13:37 +00:00
co-authored by Claudypoo
parent 8daf58d25e
commit 5242f66b7e
11 changed files with 889 additions and 917 deletions
+20 -9
View File
@@ -21,6 +21,7 @@ Usage:
from __future__ import annotations
import argparse
import csv
import json
from collections import defaultdict
from pathlib import Path
@@ -66,7 +67,7 @@ def _mode_stats(by_arm, arm, modes, field):
return np.array(means), np.array(stds)
def _panel(ax, by_arm, modes, arms, field, title, xlabel):
def _panel(ax, by_arm, modes, arms, field, xlabel):
"""Cleveland dot plot: y = mode, x = rate. One dot per arm with a thin connector
per mode, so the arm-to-arm change reads as a line segment (vanilla -> route).
xerr = std across seeds (drawn only when >1 seed). Tufte: faint x-grid only, no
@@ -97,9 +98,8 @@ def _panel(ax, by_arm, modes, arms, field, title, xlabel):
ax.set_yticklabels([f"{m}\n{'IN' if m == 'run_tests' else 'held-out'}" for m in modes], fontsize=8)
ax.set_xlim(-0.04, 1.08)
ax.set_ylim(y.min() - 0.5, y.max() + 0.5)
ax.set_xlabel(xlabel)
ax.set_title(title, fontsize=10)
ax.spines[["top", "right", "left"]].set_visible(False)
ax.set_xlabel(xlabel, fontsize=9) # carries the metric AND the better-direction;
ax.spines[["top", "right", "left"]].set_visible(False) # no title (would just restate it)
ax.tick_params(length=0)
ax.grid(axis="x", lw=0.3, alpha=0.3)
@@ -125,10 +125,8 @@ def main() -> None:
modes = [m for m in MODE_ORDER if any(m in r["by_mode"] for r in records)]
fig, (a1, a2) = plt.subplots(1, 2, figsize=(9.5, 0.7 + 0.7 * len(modes)), sharey=True)
_panel(a1, by_arm, modes, arms, "deploy_hack",
"DEPLOY hack rate (lower = better)", "deploy hack rate")
_panel(a2, by_arm, modes, arms, "deploy_solve",
"DEPLOY solve rate (higher = better)", "deploy solve rate")
_panel(a1, by_arm, modes, arms, "deploy_hack", r"DEPLOY hack rate ($\downarrow$ lower = better)")
_panel(a2, by_arm, modes, arms, "deploy_solve", r"DEPLOY solve rate ($\uparrow$ higher = better)")
a1.legend(fontsize=8, frameon=False, loc="lower right")
if args.title:
n_seed = {r.get("seed") for r in records}
@@ -136,7 +134,20 @@ def main() -> None:
f"quarantine deleted = shipped model", fontsize=11)
fig.tight_layout()
save_fig(fig, args.out)
logger.info(f"wrote {args.out} ({len(arms)} arms x {len(modes)} modes)")
# CSV reproducibility source (mirrors the dynamics plots' dump): per (mode, arm)
# the deploy hack/solve mean +/- std-across-seeds, exactly what the dots encode.
csv_path = args.out.with_suffix(".csv")
with csv_path.open("w", newline="") as f:
w = csv.writer(f)
w.writerow(["mode", "in_dist", "arm", "n_seed",
"deploy_hack_mean", "deploy_hack_std", "deploy_solve_mean", "deploy_solve_std"])
for arm in arms:
hk_m, hk_s = _mode_stats(by_arm, arm, modes, "deploy_hack")
sv_m, sv_s = _mode_stats(by_arm, arm, modes, "deploy_solve")
for j, m in enumerate(modes):
w.writerow([m, m == "run_tests", ARM[arm][0], len(by_arm[arm]),
f"{hk_m[j]:.6f}", f"{hk_s[j]:.6f}", f"{sv_m[j]:.6f}", f"{sv_s[j]:.6f}"])
logger.info(f"wrote {args.out} and {csv_path.name} ({len(arms)} arms x {len(modes)} modes)")
if __name__ == "__main__":