File size: 5,112 Bytes
f28d994
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
"""Master entry point: generate the whole figures_paper set.

Usage:
    python figures_paper/scripts/make_all_figures.py --package-root .

Behaviour:
  * auto-creates figures_paper/{pdf,png,svg,data};
  * each figure is isolated in try/except so one failure never aborts the rest;
  * reads real CSV/NPY files where present, otherwise uses reported fallback numbers;
  * prints a per-figure status table;
  * writes figures_paper/README_figures.md with captions, sources, file paths and notes.
"""
from __future__ import annotations
import argparse
import importlib.util
import sys
import traceback
from pathlib import Path

import style

# ordered list of (module_file, suggested LaTeX position)
FIGURES = [
    ("fig1_graph_overview.py",      "Sec. Introduction / Task definition"),
    ("fig2_sparsity.py",            "Sec. Dataset"),
    ("fig3_roadmap.py",             "Sec. Results (overview)"),
    ("fig4_architecture.py",        "Sec. Method"),
    ("fig5_ablation_highorder.py",  "Sec. Ablation"),
    ("fig6_rank_vs_threshold.py",   "Sec. Method / Decision rule"),
    ("fig7_error_heatmap.py",       "Sec. Error analysis"),
    ("figA1_hyperparam.py",         "Appendix"),
    ("figA2_rw_ablation.py",        "Appendix"),
    ("figA3_feature_importance.py", "Appendix"),
    ("figA4_oof_pr.py",             "Appendix"),
]


def _load(fname, scripts):
    spec = importlib.util.spec_from_file_location(fname[:-3], scripts / fname)
    mod = importlib.util.module_from_spec(spec)
    spec.loader.exec_module(mod)
    return mod


def main():
    ap = argparse.ArgumentParser()
    ap.add_argument("--package-root", default=".", help="repo root containing data_and_docs/ and validation_runs/")
    args = ap.parse_args()
    root = Path(args.package_root).resolve()
    scripts = Path(__file__).resolve().parent
    out = style.ensure_dirs(root)

    results = []
    for fname, latex in FIGURES:
        try:
            mod = _load(fname, scripts)
            res = mod.make(root, out)
        except Exception as e:  # noqa: BLE001
            res = dict(key=fname[:-3], title=fname, status="error", files=[], sources=[],
                       caption="", note=f"{type(e).__name__}: {e}", traceback=traceback.format_exc())
        res["latex"] = latex
        results.append(res)
        print(f"[{res.get('status','?'):>8}]  {res['key']}")

    _write_readme(root, results)
    print("\n=== summary ===")
    for r in results:
        print(f"  {r['key']:<28} {r.get('status','?'):<8}  -> {', '.join(r.get('files', [])) or '(no files)'}")
    print("\nREADME -> figures_paper/README_figures.md")


def _write_readme(root, results):
    lines = [
        "# Figures for the CS3319 Project 2 paper\n",
        "Auto-generated by `figures_paper/scripts/make_all_figures.py`. Every figure is emitted as "
        "`.pdf` (vector, `pdf.fonttype=42` TrueType-embedded — venue-safe), `.png` (300 dpi preview) "
        "and `.svg`. Widths follow ACM `sigconf`: single-column 3.25 in, double-column 6.75 in.\n",
        "## Generation\n",
        "```bash\npython figures_paper/scripts/make_all_figures.py --package-root .\n```\n",
        "## Status\n",
        "| figure | status | files | suggested placement |\n|---|---|---|---|",
    ]
    for r in results:
        status = r.get("status", "?")
        files = ", ".join(r.get("files", [])) or "—"
        lines.append(f"| {r['key']} | {status} | {files} | {r.get('latex','')} |")
    lines.append("\n## Captions, sources and notes\n")
    for r in results:
        lines.append(f"### {r['title']}")
        lines.append(f"- **status:** {r.get('status','?')}")
        if r.get("sources"):
            lines.append("- **data sources:** " + "; ".join(r["sources"]))
        if r.get("files"):
            lines.append("- **files:** " + ", ".join(
                f"`figures_paper/{{pdf,png,svg}}/{f}`" for f in r["files"]))
        cap = r.get("caption", "").strip()
        if cap:
            lines.append(f"- **caption draft:** {cap}")
        if r.get("note"):
            lines.append(f"- **note:** {r['note']}")
        if r.get("traceback"):
            lines.append("```python\n" + r["traceback"] + "\n```")
        lines.append("")

    lines += [
        "## Inserting into LaTeX (ACM sigconf)\n",
        "```latex\n\\usepackage{graphicx}\n",
        "% single-column (3.25 in)\n\\begin{figure}\n  \\centering\n  \\includegraphics[width=\\columnwidth]{figures_paper/pdf/fig2_sparsity.pdf}\n  \\caption{...}\n\\end{figure}\n",
        "% double-column (6.75 in)\n\\begin{figure*}\n  \\centering\n  \\includegraphics[width=\\textwidth]{figures_paper/pdf/fig3_roadmap.pdf}\n  \\caption{...}\n\\end{figure*}\n```\n",
        "Use the `.pdf` for the camera-ready (vector, embedded fonts); the `.png` is only for "
        "previews / draft review.\n",
    ]
    (root / "figures_paper" / "README_figures.md").write_text("\n".join(lines), encoding="utf-8")


if __name__ == "__main__":
    # make the scripts dir importable so `import style` / sibling fig modules work
    sys.path.insert(0, str(Path(__file__).resolve().parent))
    main()