"""Export a publication-ready figure of the measured selected milestones.""" from pathlib import Path import matplotlib matplotlib.use("Agg") import matplotlib.pyplot as plt ROOT = Path(__file__).resolve().parents[1] plt.rcParams.update({"font.family": "DejaVu Sans", "font.size": 12, "figure.facecolor": "#0a1523", "axes.facecolor": "#0a1523", "text.color": "#f2f6fa", "axes.labelcolor": "#a9bacc", "xtick.color": "#a9bacc", "ytick.color": "#f2f6fa"}) groups = [ ("2 m sprint", "Licensed actor → race adaptation", "#69e2ce", ["Hannes baseline", "2B / 750", "B3 / 800", "D1 / 900"], [1.192, 1.096, 1.092, 1.084]), ("1.5 m hill / 8°", "Reference benchmark → selected policy", "#ffb36b", ["Pollen benchmark", "H1b / 500"], [5.880, 1.360]), ("2 m passive rollers", "Transfer adaptation → PPO polish", "#9bbcff", ["Pollen benchmark", "R1 / 300", "R1 / 400", "R1 / 900", "R2 / 1100"], [3.136, 1.864, 1.648, 1.576, 1.516]), ] fig, axes = plt.subplots(1, 3, figsize=(17, 7), gridspec_kw={"wspace": .46}) fig.suptitle("Selected checkpoints. Exact Arena score.", x=.07, y=.94, ha="left", fontsize=23, fontweight="bold") fig.text(.07, .875, "Timed finish mean over five seeds · every shown policy finished 5/5 · lower is better", color="#a9bacc", fontsize=12) for ax, (title, subtitle, color, labels, scores) in zip(axes, groups): ax.barh(range(len(scores)), scores, color=color, height=.58, alpha=.82) ax.invert_yaxis() ax.set_yticks(range(len(labels)), labels, fontsize=11) ax.set_xlim(0, max(scores) * 1.29) ax.set_xlabel("Timed finish / seconds", fontsize=10, labelpad=12) ax.set_title(title + "\n" + subtitle, loc="left", fontsize=12, pad=22, color=color) ax.xaxis.grid(True, color="#263d4f", linewidth=.7) ax.set_axisbelow(True) for index, score in enumerate(scores): ax.text(score + max(scores) * .025, index, f"{score:.3f} s", va="center", fontsize=11, fontweight="bold" if index == len(scores) - 1 else "normal") for spine in ax.spines.values(): spine.set_visible(False) ax.tick_params(axis="y", length=0) fig.subplots_adjust(left=.13, right=.97, top=.72, bottom=.20) fig.text(.07, .08, "References were benchmarks, not reused weight parents. All trained policies descend from the licensed Hannes actor.", color="#a9bacc", fontsize=10) fig.text(.07, .035, "Snapshot: October 2026. Local best policies and published Arena entries can differ; see models/manifest.json.", color="#a9bacc", fontsize=9) fig.savefig(ROOT / "media/experiment-progress.png", dpi=140, facecolor=fig.get_facecolor()) fig.savefig(ROOT / "media/experiment-progress.svg", facecolor=fig.get_facecolor()) print("Exported PNG and SVG progress figures.")