"""A1. Codex structure from the transliteration's page variables: quire, page-in-quire, illustration type, Currier language, Davis hand. Outputs: out/tables/codex_map.csv, out/tables/section_summary.csv, out/figs/codex_map.pdf, out/tables/quire_summary.tex """ import os, sys _here = os.path.dirname(os.path.abspath(__file__)) # data/analysis, or a subfolder of it sys.path.insert(0, _here if os.path.exists(os.path.join(_here, "paths.py")) else os.path.dirname(_here)) from paths import * # noqa: repository locations import csv, collections, os import matplotlib; matplotlib.use("Agg") import matplotlib.pyplot as plt from matplotlib.patches import Rectangle from corpus import Corpus, section_name import ivtff os.makedirs("out/tables", exist_ok=True); os.makedirs("out/figs", exist_ok=True) C = Corpus() rows = [] for p in C.pages: v = C.pagevars[p] ntok = sum(1 for _ in C.words(C.loci_where(pages={p}))) nrun = len(C.running_text(pages={p})) nlab = len(C.labels(pages={p})) rows.append(dict(page=p, folio=ivtff.folio_number(p), quire=v.get("Q"), pos=v.get("P"), bifolio=v.get("B"), illus=v.get("I"), section=section_name(v.get("I")), lang=v.get("L", "-"), hand=v.get("H", "-"), currier_hand=v.get("C", "-"), extraneous=v.get("X", ""), tokens=ntok, running=nrun, labels=nlab)) with open("out/tables/codex_map.csv", "w", newline="") as f: w = csv.DictWriter(f, fieldnames=rows[0].keys()); w.writeheader(); w.writerows(rows) # --- section summary sec = collections.OrderedDict() for r in rows: s = sec.setdefault(r["section"], dict(pages=0, tokens=0, running=0, labels=0, A=0, B=0, hands=collections.Counter(), folios=set())) s["pages"] += 1; s["tokens"] += r["tokens"]; s["running"] += r["running"]; s["labels"] += r["labels"] if r["lang"] == "A": s["A"] += 1 if r["lang"] == "B": s["B"] += 1 s["hands"][r["hand"]] += 1; s["folios"].add(r["folio"]) with open("out/tables/section_summary.csv", "w", newline="") as f: w = csv.writer(f); w.writerow(["section", "pages", "tokens", "running_text_tokens", "label_tokens", "pages_A", "pages_B", "hands", "folio_range"]) for k, s in sec.items(): fr = f"{min(s['folios'])}-{max(s['folios'])}" w.writerow([k, s["pages"], s["tokens"], s["running"], s["labels"], s["A"], s["B"], " ".join(f"{h}:{n}" for h, n in sorted(s["hands"].items())), fr]) print(open("out/tables/section_summary.csv").read()) # --- quire summary (which sections / languages / hands each quire holds; folio ranges) Q = collections.OrderedDict() for r in rows: q = Q.setdefault(r["quire"], dict(folios=set(), secs=collections.Counter(), langs=collections.Counter(), hands=collections.Counter())) q["folios"].add(r["folio"]); q["secs"][r["illus"]] += 1; q["langs"][r["lang"]] += 1; q["hands"][r["hand"]] += 1 quire_num = {chr(ord("A") + i): i + 1 for i in range(20)} with open("out/tables/quire_summary.csv", "w", newline="") as f: w = csv.writer(f); w.writerow(["quire", "folios", "n_pages", "illustration_types", "languages", "hands"]) for q, d in Q.items(): fl = sorted(d["folios"]) w.writerow([quire_num[q], f"{fl[0]}-{fl[-1]}", sum(d["secs"].values()), " ".join(f"{k}:{n}" for k, n in sorted(d["secs"].items())), " ".join(f"{k}:{n}" for k, n in sorted(d["langs"].items())), " ".join(f"{k}:{n}" for k, n in sorted(d["hands"].items()))]) print(open("out/tables/quire_summary.csv").read()) # --- figure: codex map. One row per quire, one cell per page in quire order; # fill = illustration type, edge colour = Currier language, text = folio. colors = {"H": "#8fbc8f", "A": "#7b9ed9", "Z": "#4f6fb5", "B": "#6ec6c6", "C": "#b7a6d9", "P": "#e3b36a", "S": "#d98f8f", "T": "#d9d9d9"} fig, ax = plt.subplots(figsize=(7.2, 6.4)) quires = list(Q.keys()) maxp = max(sum(d["secs"].values()) for d in Q.values()) for yi, q in enumerate(quires): pr = [r for r in rows if r["quire"] == q] pr.sort(key=lambda r: r["pos"]) for xi, r in enumerate(pr): ec = {"A": "black", "B": "#c0392b"}.get(r["lang"], "#888888") lw = 1.6 if r["lang"] in ("A", "B") else 0.5 ax.add_patch(Rectangle((xi, -yi), 0.92, 0.84, facecolor=colors[r["illus"]], edgecolor=ec, linewidth=lw)) ax.text(xi + 0.46, -yi + 0.42, str(r["folio"]) + ("v" if r["page"].endswith("v") or "v" in r["page"][-2:] else "r"), ha="center", va="center", fontsize=4.6, color="black") ax.text(xi + 0.46, -yi + 0.12, r["hand"], ha="center", va="center", fontsize=4, color="#333333") ax.text(-0.3, -yi + 0.42, f"Q{quire_num[q]}", ha="right", va="center", fontsize=7) ax.set_xlim(-1.2, maxp); ax.set_ylim(-len(quires) + 0.5, 1.3) ax.axis("off") import matplotlib.patches as mpatches handles = [mpatches.Patch(facecolor=colors[k], edgecolor="none", label=section_name(k)) for k in ["H", "A", "Z", "B", "C", "P", "S", "T"]] handles += [mpatches.Patch(facecolor="white", edgecolor="black", linewidth=1.6, label="Currier A"), mpatches.Patch(facecolor="white", edgecolor="#c0392b", linewidth=1.6, label="Currier B")] ax.legend(handles=handles, loc="upper center", bbox_to_anchor=(0.5, 1.09), ncol=5, fontsize=6, frameon=False) fig.tight_layout(); fig.savefig("out/figs/codex_map.pdf"); print("codex_map.pdf written")