SPB Git

spb/wp44_uqo

Public
4.8 KB · 73 lines python
1#!/usr/bin/env python32"""WP44 — generate manuscript/tables/numbers.tex: every number quoted in the prose is a LaTeX macro produced here from3result files (never typed by hand). Macro names use letters only (no digits: `\\nCoreEligible`, not `\\n2026`).4Sources: data/metadata/prisma_counts.json, linkage_report.json, results/bibliometrics/*.csv, results/econometrics/*.json,5taxonomy/validation/metrics.json, results/emerging/metrics_h12.json (each optional: missing → macro undefined → compile error,6which is intended: the prose cannot cite a number that does not exist)."""7import json, os, sys, csv, re8R = sys.argv[1] if len(sys.argv) > 1 else os.path.dirname(os.path.dirname(os.path.abspath(__file__)))9out = []10WORDS = {"0": "Zero", "1": "One", "2": "Two", "3": "Three", "4": "Four", "5": "Five", "6": "Six", "7": "Seven", "8": "Eight", "9": "Nine"}11def name(s):12    s = re.sub(r"[^A-Za-z0-9]+", " ", s).title().replace(" ", "")13    return "".join(WORDS[ch] if ch.isdigit() else ch for ch in s)14def fmt(v):15    if isinstance(v, bool): return str(v)16    if isinstance(v, int): return f"{v:,}".replace(",", "{,}")17    if isinstance(v, float):18        return f"{v:,.3f}".replace(",", "{,}") if abs(v) < 100 else f"{v:,.1f}".replace(",", "{,}")19    return str(v).replace("%", "\\%").replace("_", "\\_")20def emit(k, v):21    out.append(f"\\newcommand{{\\{name(k)}}}{{{fmt(v)}}}")22def walk(prefix, obj):23    if isinstance(obj, dict):24        for k, v in obj.items(): walk(f"{prefix} {k}", v)25    elif isinstance(obj, (int, float, str, bool)) and obj is not None:26        emit(prefix, obj)27p = os.path.join(R, "data/metadata/prisma_counts.json")28if os.path.exists(p): walk("prisma", json.load(open(p)))29p = os.path.join(R, "data/metadata/linkage_report.json")30if os.path.exists(p): walk("link", json.load(open(p)))31for f in ["volume_yearly", "citation_windows_yearly", "international_collab_yearly", "industry_share_yearly", "venue_hhi_yearly"]:32    p = os.path.join(R, "results/bibliometrics", f + ".csv")33    if os.path.exists(p):34        for row in csv.DictReader(open(p)):35            y = row.get("year") or row.get("publication_year")36            for k, v in row.items():37                if k in ("year", "publication_year") or v in ("", None): continue38                try: v = int(v) if re.fullmatch(r"-?\d+", v) else float(v)39                except ValueError: pass40                emit(f"{f} {y} {k}", v)41for f, key in [("results/econometrics/its_results.json", "its"), ("taxonomy/validation/metrics.json", "val"), ("results/emerging/metrics_h12.json", "emerg"), ("results/emerging/metrics_h24.json", "emergTwoFour")]:42    p = os.path.join(R, f)43    if os.path.exists(p):44        d = json.load(open(p))45        walk(key, {k: v for k, v in d.items() if not isinstance(v, (list,))})46for f, key in [("data/metadata/dblp_parse_report.json", "dblp"), ("data/metadata/acl_parse_report.json", "acl"), ("data/metadata/api_increment_ledger.json", "increment"), ("data/metadata/increment_report.json", "incrementIngest")]:47    p = os.path.join(R, f)48    if os.path.exists(p):49        d = json.load(open(p))50        if key == "increment":51            sl = d.get("slices", {}); emit("increment api calls", d.get("calls", 0)); emit("increment records retrieved", sum(v.get("records", 0) for v in sl.values()))52            emit("increment truncated slices", sum(1 for v in sl.values() if v.get("truncated"))); emit("increment slices done", sum(1 for v in sl.values() if v.get("done"))); emit("increment cost usd", round(d.get("cost_usd_total", 0), 4))53        elif key == "incrementIngest":54            emit("increment new works", d.get("new_works", 0)); emit("increment already in snapshot", d.get("already_in_snapshot", 0))55        elif key == "dblp":56            emit("dblp parsed records", d.get("rows_written", 0)); [emit(f"dblp type {k}", v) for k, v in d.get("counts_by_type", {}).items()]57        elif key == "acl":58            emit("acl parsed entries", d.get("entries", 0))59p = os.path.join(R, "results/emerging/known_set_lead_times.csv")60if os.path.exists(p):61    for row in csv.DictReader(open(p)):62        for k in ("total_works", "detection_month", "peak_growth_month", "lead_months"):63            v = row.get(k)64            if v in ("", None): continue65            try: v = int(float(v)) if re.fullmatch(r"-?\d+(\.0)?", v) else v66            except ValueError: pass67            emit(f"known {row['concept']} {k}", v)68    leads = [int(float(r["lead_months"])) for r in csv.DictReader(open(p)) if r.get("lead_months") not in ("", None)]69    if leads:70        import statistics; emit("known set median lead months", int(statistics.median(leads))); emit("known set n detected", len(leads)); emit("known set n positive lead", sum(1 for l in leads if l > 0))71open(os.path.join(R, "manuscript/tables/numbers.tex"), "w").write("% machine-generated by tables/make_numbers.py — do not edit\n" + "\n".join(out) + "\n")72print(len(out), "macros")73
Files · 7d8c8f8592599c79aba715f8bff62d0f0aa710b4
Menu

Theme