Manuscript revision and pending experiment work, snapshot before restructuring
Clarity pass over the main text (36-item audit), Discussion rewrite and cut, acknowledgements, Souly et al. as ref 62, lettered SI panels, model section moved under Results; plus the untracked curriculum/society/compose/smol configs, runners, figures, stats and tests that the SI already cites. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y64o8FKP7rCuXzC48pxpMm
This commit is contained in:
parent
e4804adabc
commit
84124de143
450 changed files with 52813 additions and 1202 deletions
|
|
@ -21,6 +21,28 @@ def load_bundle(results_dir: str | Path) -> tuple[pd.DataFrame, dict]:
|
|||
return df, resolved["source_config"]
|
||||
|
||||
|
||||
def load_seed_bundles(results_dir: str | Path) -> tuple[pd.DataFrame, dict]:
|
||||
"""Load a per-seed bundle layout ``results_dir/s{seed}/results.parquet`` into one frame.
|
||||
|
||||
Each sub-bundle gets a ``seed`` column from its directory name (the HPC array-job layout, one
|
||||
element per seed). A flat single-seed bundle is accepted too, tagged with its manifest seed.
|
||||
Returns (frame, source config of the first seed).
|
||||
"""
|
||||
results_dir = Path(results_dir)
|
||||
subs = sorted(results_dir.glob("s[0-9]*/results.parquet"))
|
||||
if not subs:
|
||||
df, cfg = load_bundle(results_dir)
|
||||
if "seed" not in df.columns:
|
||||
df = df.assign(seed=int(cfg.get("seed", 1)))
|
||||
return df, cfg
|
||||
frames, cfg0 = [], None
|
||||
for p in subs:
|
||||
df, cfg = load_bundle(p.parent)
|
||||
cfg0 = cfg0 or cfg
|
||||
frames.append(df.assign(seed=int(p.parent.name[1:])))
|
||||
return pd.concat(frames, ignore_index=True), cfg0
|
||||
|
||||
|
||||
def mean_ci(df: pd.DataFrame, by: str, value: str, ci: float = 0.95):
|
||||
"""Return (index, mean, half-width) for a normal-approx CI of ``value`` grouped by ``by``."""
|
||||
from scipy import stats
|
||||
|
|
@ -38,3 +60,23 @@ def savefig(fig, results_dir: str | Path, name: str) -> None:
|
|||
fig.savefig(results_dir / f"{name}.png", dpi=150, bbox_inches="tight")
|
||||
fig.savefig(results_dir / f"{name}.pdf", bbox_inches="tight")
|
||||
print(f"wrote {results_dir}/{name}.png and .pdf")
|
||||
|
||||
|
||||
def letter_axes(fig, x: float = -0.1, y: float = 1.04, fontsize: float = 13) -> None:
|
||||
"""Letter every data axes of ``fig`` A, B, C ... in reading order (top row first, left to right).
|
||||
|
||||
Twin axes and colourbars share a frame with a lettered axes and are skipped. Call once, after
|
||||
every axes exists and before saving.
|
||||
"""
|
||||
seen: list[tuple[float, float]] = []
|
||||
axes = []
|
||||
for ax in fig.axes:
|
||||
b = ax.get_position()
|
||||
key = (round(b.x0, 3), round(b.y0, 3))
|
||||
if key in seen or b.width < 0.05: # twin axes / colourbars
|
||||
continue
|
||||
seen.append(key); axes.append(ax)
|
||||
axes.sort(key=lambda a: (-round(a.get_position().y0, 2), a.get_position().x0))
|
||||
for i, ax in enumerate(axes):
|
||||
ax.text(x, y, chr(ord("A") + i), transform=ax.transAxes, fontsize=fontsize, fontweight="bold",
|
||||
va="bottom", ha="left", clip_on=False)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue