"""Make publication figures from recorded measurements; never simulated gains.""" from pathlib import Path import argparse,csv,json import numpy as np 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":10,"axes.spines.top":False,"axes.spines.right":False}) COLORS={"raw_importance":"#788995","screen_cv":"#ca8845","world_cv":"#116e83","world_active_cv":"#9a4966","world_guarded_cv":"#298653","constant_world_cv":"#555e62","neural_cv":"#6d6dc4"} LABELS={"raw_importance":"Raw importance","screen_cv":"Screen memory","world_cv":"World memory","world_active_cv":"Active world","world_guarded_cv":"Guarded active","constant_world_cv":"Constant prior","neural_cv":"Neural prior"} FIGURES=ROOT/"figures_reproduced" def save(fig,name): FIGURES.mkdir(parents=True,exist_ok=True) for ext in ("png","pdf"):fig.savefig(FIGURES/f"{name}.{ext}",dpi=180,bbox_inches="tight") plt.close(fig) def run(results="results",output="figures_reproduced"): global FIGURES FIGURES=ROOT/output;result_dir=ROOT/results initial=json.loads((result_dir/"rendering_report.json").read_text()) follow=json.loads((result_dir/"followup_report.json").read_text()) fig,axes=plt.subplots(1,2,figsize=(11,4.3)) for ax,report,phase,methods,title in [ (axes[0],initial,"revisit",["raw_importance","screen_cv","world_cv","world_active_cv"],"Initial study: revisit"), (axes[1],follow,"hidden_change",["raw_importance","screen_cv","world_cv","world_active_cv","world_guarded_cv"],"Independent scenes: hidden change")]: values=[next(s for s in report["summary"] if s["phase"]==phase and s["method"]==m) for m in methods] y=np.array([v["expected_mse"] for v in values]);ci=np.array([v["expected_mse_scene_bootstrap_95"] for v in values]) ax.bar(np.arange(len(methods)),y,color=[COLORS[m] for m in methods],width=.68) ax.errorbar(np.arange(len(methods)),y,yerr=np.stack([y-ci[:,0],ci[:,1]-y]),fmt="none",color="#243746",capsize=3) ax.set_xticks(np.arange(len(methods)),[LABELS[m] for m in methods],rotation=25,ha="right",fontsize=9) ax.set_title(title,fontweight="bold");ax.set_ylabel("Expected linear RGB MSE") ax.ticklabel_format(axis="y",style="sci",scilimits=(0,0));ax.grid(axis="y",alpha=.18) fig.suptitle("Two shadow rays per receiver per frame; 95% scene-bootstrap intervals",y=1.01,fontsize=12) fig.tight_layout();save(fig,"physical_results") rows=list(csv.DictReader((result_dir/"followup_raw.csv").open())) fig,ax=plt.subplots(figsize=(8,4)) for method in ["raw_importance","screen_cv","world_cv","world_active_cv","world_guarded_cv"]: y=[np.mean([float(r["conditional_expected_mse"]) for r in rows if r["phase"]=="hidden_change" and int(r["phase_frame"])==i and r["method"]==method]) for i in range(8)] ax.plot(range(8),y,marker="o",label=LABELS[method],color=COLORS[method],lw=2) ax.set(xlabel="Frame after unannounced geometry change",ylabel="Expected linear RGB MSE",title="Trust revocation cannot prevent the first surprise frame") ax.set_xticks(range(8));ax.grid(alpha=.2) ax.legend(fontsize=9,ncol=3,loc="upper center",bbox_to_anchor=(.5,-.2)) fig.tight_layout();save(fig,"change_recovery") snapshots=np.load(result_dir/"rendering_example_frames.npz",allow_pickle=False) fig,axes=plt.subplots(2,4,figsize=(10,5.6)) for row,phase in enumerate(("revisit","hidden_change")): for col,method in enumerate(("reference","raw_importance","screen_cv","world_cv")): im=snapshots[f"{phase}_{method}"] axes[row,col].imshow(np.clip(im,0,1)**(1/2.2),origin="lower",interpolation="nearest") axes[row,col].set_title("Exact finite-light" if method=="reference" else LABELS[method],fontsize=10) axes[row,col].set_xticks([]);axes[row,col].set_yticks([]) axes[row,0].set_ylabel("Revisit" if row==0 else "First change frame",fontsize=10) fig.suptitle("One recorded scene/seed; preview clipping is excluded from reported error metrics",fontsize=11) fig.tight_layout();save(fig,"physical_frames") training=json.loads((ROOT/"results/training.json").read_text()) fig,ax=plt.subplots(figsize=(6,3.1)) ax.plot([v["epoch"] for v in training["history"]],[v["validation_bce"] for v in training["history"]],color="#116e83",lw=2) ax.axvline(training["selected_epoch"],color="#ca8845",linestyle="--",label=f"Selected epoch {training['selected_epoch']}") ax.set(xlabel="Epoch",ylabel="Validation binary cross-entropy",title="Later training overfits this small scene collection") ax.legend();ax.grid(alpha=.2);fig.tight_layout();save(fig,"training_curve") if __name__=="__main__": parser=argparse.ArgumentParser();parser.add_argument("--results",default="results") parser.add_argument("--output",default="figures_reproduced") args=parser.parse_args();run(args.results,args.output)