Buckets:
| # /// script | |
| # requires-python = ">=3.11" | |
| # dependencies = ["pandas", "plotly", "matplotlib", "kaleido"] | |
| # /// | |
| """Build logbook figures (interactive Plotly HTML) and poster figures (PNG) from | |
| the experiment's results.csv / lp_quality_gap.csv / scaling.csv.""" | |
| import argparse | |
| from pathlib import Path | |
| import pandas as pd | |
| import plotly.graph_objects as go | |
| import matplotlib | |
| matplotlib.use("Agg") | |
| import matplotlib.pyplot as plt | |
| PIPELINE_LABEL = { | |
| "oracle__lagrangian": "Oracle (true effects)", | |
| "buoplr_net__lagrangian": "BUOPLR (proposed)", | |
| "independent_mlp__lagrangian": "Indep. per-outcome net + Lagrangian", | |
| "linear_additive__lagrangian": "Linear-additive + Lagrangian", | |
| "buoplr_net__greedy": "BUOPLR net + greedy", | |
| "independent_mlp__greedy": "Indep. net + greedy", | |
| "linear_additive__greedy": "Linear-additive + greedy", | |
| "control_no_treatment": "No-treatment control", | |
| } | |
| COLORS = { | |
| "oracle__lagrangian": "#9AA5B1", | |
| "buoplr_net__lagrangian": "#B8860B", | |
| "independent_mlp__lagrangian": "#6E7B8B", | |
| "linear_additive__lagrangian": "#B0B8C1", | |
| "buoplr_net__greedy": "#D9B96A", | |
| "independent_mlp__greedy": "#AEB7C0", | |
| "linear_additive__greedy": "#C7CDD3", | |
| "control_no_treatment": "#E3E6E9", | |
| } | |
| def fig_pipeline_comparison(results_csv: Path, out_html: Path, out_png: Path): | |
| df = pd.read_csv(results_csv) | |
| df = df[df["pipeline"] != "control_no_treatment"].copy() | |
| df["label"] = df["pipeline"].map(lambda p: PIPELINE_LABEL.get(p, p)) | |
| df = df.sort_values("total_main_uplift", ascending=True) | |
| colors = [COLORS.get(p, "#888") for p in df["pipeline"]] | |
| fig = go.Figure(go.Bar( | |
| x=df["total_main_uplift"], y=df["label"], orientation="h", | |
| marker_color=colors, | |
| text=[f"{v:.1f}" for v in df["total_main_uplift"]], textposition="outside", | |
| )) | |
| fig.update_layout( | |
| title="Realized incremental main-outcome uplift by pipeline (synthetic proxy)", | |
| xaxis_title="Total realized main-outcome uplift on held-out users", | |
| template="plotly_white", height=480, margin=dict(l=260, r=40, t=60, b=50), | |
| ) | |
| fig.write_html(str(out_html), include_plotlyjs="cdn") | |
| fig_mpl, ax = plt.subplots(figsize=(13.0, 8.7), dpi=380) # AR ~1.49 to match poster hero-stage | |
| ax.barh(df["label"], df["total_main_uplift"], color=colors, edgecolor="#33363b", linewidth=0.6) | |
| for i, v in enumerate(df["total_main_uplift"]): | |
| ax.text(v, i, f" {v:.0f}", va="center", fontsize=9) | |
| ax.set_xlabel("Total realized main-outcome uplift (held-out users)", fontsize=9) | |
| ax.set_title("BUOPLR vs baselines — offline pipeline comparison", fontsize=11) | |
| ax.tick_params(labelsize=8) | |
| ax.set_xlim(0, df["total_main_uplift"].max() * 1.15) | |
| plt.tight_layout() | |
| fig_mpl.savefig(out_png) | |
| plt.close(fig_mpl) | |
| def fig_lp_quality_gap(lp_csv: Path, out_html: Path, out_png: Path): | |
| df = pd.read_csv(lp_csv) | |
| labels = {"linear_additive": "Linear-additive", "independent_mlp": "Independent per-outcome net", | |
| "buoplr_net": "BUOPLR net"} | |
| df["label"] = df["uplift_model"].map(lambda m: labels.get(m, m)) | |
| fig = go.Figure() | |
| fig.add_bar(name="Restricted Lagrangian (BUOPLR stage-2)", x=df["label"], y=df["lagrangian_uplift"], | |
| marker_color="#B8860B") | |
| fig.add_bar(name="Exact LP (upper bound, not scalable)", x=df["label"], y=df["lp_uplift"], | |
| marker_color="#9AA5B1") | |
| fig.update_layout(barmode="group", template="plotly_white", | |
| title=f"Assignment quality gap at n={int(df['n_users'].iloc[0])} users: Lagrangian relaxation vs exact LP", | |
| yaxis_title="Total realized main-outcome uplift", height=440, | |
| margin=dict(l=60, r=40, t=70, b=50)) | |
| fig.write_html(str(out_html), include_plotlyjs="cdn") | |
| fig_mpl, ax = plt.subplots(figsize=(6.5, 4.0), dpi=200) | |
| x = range(len(df)) | |
| w = 0.35 | |
| ax.bar([i - w / 2 for i in x], df["lagrangian_uplift"], width=w, label="Restricted Lagrangian\n(BUOPLR stage-2)", color="#B8860B") | |
| ax.bar([i + w / 2 for i in x], df["lp_uplift"], width=w, label="Exact LP\n(not scalable)", color="#9AA5B1") | |
| ax.set_xticks(list(x)) | |
| ax.set_xticklabels(df["label"], fontsize=8) | |
| ax.set_ylabel("Realized main-outcome uplift") | |
| ax.set_title(f"Lagrangian vs exact LP @ n={int(df['n_users'].iloc[0])}") | |
| ax.legend(fontsize=8) | |
| plt.tight_layout() | |
| fig_mpl.savefig(out_png, dpi=200) | |
| plt.close(fig_mpl) | |
| def fig_scaling(scaling_csv: Path, out_html: Path, out_png: Path): | |
| df = pd.read_csv(scaling_csv).sort_values("n_users") | |
| fig = go.Figure() | |
| fig.add_trace(go.Scatter(x=df["n_users"], y=df["lagrangian_assign_s"], mode="lines+markers", | |
| name="BUOPLR restricted Lagrangian", line=dict(color="#B8860B"))) | |
| fig.add_trace(go.Scatter(x=df["n_users"], y=df["greedy_assign_s"], mode="lines+markers", | |
| name="Greedy myopic", line=dict(color="#6E7B8B"))) | |
| fig.update_layout(template="plotly_white", title="Assignment-stage runtime vs. number of users", | |
| xaxis_title="Users", yaxis_title="Assignment runtime (s)", | |
| xaxis_type="log", height=440, margin=dict(l=60, r=40, t=60, b=50)) | |
| fig.write_html(str(out_html), include_plotlyjs="cdn") | |
| fig_mpl, ax = plt.subplots(figsize=(6.5, 4.0), dpi=200) | |
| ax.plot(df["n_users"], df["lagrangian_assign_s"], "o-", color="#B8860B", label="BUOPLR Lagrangian") | |
| ax.plot(df["n_users"], df["greedy_assign_s"], "o-", color="#6E7B8B", label="Greedy myopic") | |
| ax.set_xscale("log") | |
| ax.set_xlabel("Users (log scale)") | |
| ax.set_ylabel("Assignment runtime (s)") | |
| ax.set_title("BUOPLR assignment scales near-linearly") | |
| ax.legend(fontsize=9) | |
| plt.tight_layout() | |
| fig_mpl.savefig(out_png, dpi=200) | |
| plt.close(fig_mpl) | |
| def main(): | |
| ap = argparse.ArgumentParser() | |
| ap.add_argument("--in-dir", type=str, required=True) | |
| ap.add_argument("--out-dir", type=str, required=True) | |
| args = ap.parse_args() | |
| in_dir, out_dir = Path(args.in_dir), Path(args.out_dir) | |
| out_dir.mkdir(parents=True, exist_ok=True) | |
| fig_pipeline_comparison(in_dir / "results.csv", out_dir / "pipeline_comparison.html", | |
| out_dir / "pipeline_comparison.png") | |
| fig_lp_quality_gap(in_dir / "lp_quality_gap.csv", out_dir / "lp_quality_gap.html", | |
| out_dir / "lp_quality_gap.png") | |
| fig_scaling(in_dir / "scaling.csv", out_dir / "scaling.html", out_dir / "scaling.png") | |
| print(f"Wrote figures to {out_dir}") | |
| if __name__ == "__main__": | |
| main() | |
Xet Storage Details
- Size:
- 6.64 kB
- Xet hash:
- 626e589616dc9760c3d6180fcc3b9d2d728754d5ec46b9526dc43cafbf4b2c46
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.