Restructure: descriptive tier and experiment names, paper/manuscript
- paper/pnas -> paper/manuscript (venue-neutral)
- configs/layer1 -> configs/inheritance, src/knowledge -> src/inheritance
(imported as `inheritance`), make layer1 -> make inheritance; layer2 alias dropped
- inheritance and trained-network bundles named after the manuscript figure
they feed (fig2_grounding_sweep, figS3_rebaselining, ...), or descriptively
where they feed none; configs keep their `experiment:` value so parquet
hashes are unchanged, only output.dir moves
- figure scripts, SI figure sources, notebooks, REPRODUCING.md, README and the
SI Methods/tables updated; make clean no longer deletes tracked manifests;
reproduce.sh hashes the s{seed}/ layouts too
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y64o8FKP7rCuXzC48pxpMm
This commit is contained in:
parent
84124de143
commit
ab3dc10587
240 changed files with 477 additions and 476 deletions
|
|
@ -1,79 +0,0 @@
|
|||
"""E12 figure — model speciation: the merge-compatibility limit of the sexual society.
|
||||
|
||||
Three panels, reading only the committed bundles. (A) BDM: mean recombinant (hybrid) fitness vs
|
||||
parental divergence, one line per epistasis density rho, against the rising parent fitness — the
|
||||
compatible -> outbreeding-depression -> hybrid-inviability trajectory, peaking then crashing sooner the
|
||||
denser the epistasis. (B) BDM: the reproductive-isolation rate (fraction of hybrids below the ancestor)
|
||||
vs divergence — the isolation cliff, moving to lower divergence as epistasis density rises. (C) NK: the
|
||||
epistasis wedge — as landscape ruggedness K grows, recombining two adapted local-optimum parents flips
|
||||
from a gain to outbreeding depression.
|
||||
|
||||
Usage: python figures/plot_E12.py
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).parent))
|
||||
from _figlib import load_bundle, savefig # noqa: E402
|
||||
|
||||
|
||||
def _agg(df, keys, value):
|
||||
g = df.groupby(keys)[value].agg(["mean", "std", "count"]).reset_index()
|
||||
g["se"] = g["std"] / np.sqrt(g["count"].clip(lower=1))
|
||||
return g
|
||||
|
||||
|
||||
def main() -> None:
|
||||
bdm, _ = load_bundle("results/E12")
|
||||
nk, _ = load_bundle("results/E12_nk")
|
||||
rhos = sorted(bdm["rho"].unique())
|
||||
colors = plt.cm.viridis(np.linspace(0.15, 0.85, len(rhos)))
|
||||
|
||||
fig, axes = plt.subplots(1, 3, figsize=(16, 5))
|
||||
|
||||
# Panel A: hybrid fitness vs divergence, per epistasis density, + parent fitness.
|
||||
ax = axes[0]
|
||||
par = _agg(bdm, "divergence", "parent_fitness")
|
||||
ax.plot(par["divergence"], par["mean"], "k--", lw=1.6, label="parent fitness")
|
||||
for rho, c in zip(rhos, colors):
|
||||
g = _agg(bdm[bdm["rho"] == rho], "divergence", "offspring_fitness")
|
||||
ax.plot(g["divergence"], g["mean"], "-o", color=c, lw=2, label=f"hybrid, ρ={rho}")
|
||||
ax.fill_between(g["divergence"], g["mean"] - g["se"], g["mean"] + g["se"], color=c, alpha=0.15)
|
||||
ax.axhline(0, color="#999", lw=0.8, ls=":")
|
||||
ax.set(xlabel="parental divergence (substitutions $d$)", ylabel="fitness",
|
||||
title="Hybrid fitness collapses as lineages diverge\n(compatible → outbreeding depression → inviability)")
|
||||
ax.legend(frameon=False, fontsize=8)
|
||||
|
||||
# Panel B: reproductive-isolation rate vs divergence, per epistasis density.
|
||||
ax = axes[1]
|
||||
for rho, c in zip(rhos, colors):
|
||||
g = _agg(bdm[bdm["rho"] == rho], "divergence", "isolation")
|
||||
ax.plot(g["divergence"], g["mean"], "-o", color=c, lw=2, label=f"ρ={rho}")
|
||||
ax.set(xlabel="parental divergence (substitutions $d$)", ylabel="reproductive isolation\n(P hybrid inviable)",
|
||||
ylim=(-0.02, 1.02),
|
||||
title="The isolation cliff moves to lower divergence\nas epistasis density rises")
|
||||
ax.legend(frameon=False, fontsize=9, title="epistasis density")
|
||||
|
||||
# Panel C: NK epistasis wedge — recombination gain vs ruggedness K.
|
||||
ax = axes[2]
|
||||
g = _agg(nk, "K", "offspring_minus_parent")
|
||||
ax.axhline(0, color="#999", lw=0.8, ls=":")
|
||||
ax.plot(g["K"], g["mean"], "-o", color="#d62728", lw=2)
|
||||
ax.fill_between(g["K"], g["mean"] - g["se"], g["mean"] + g["se"], color="#d62728", alpha=0.15)
|
||||
ax.set(xlabel="landscape ruggedness $K$ (epistasis)", ylabel="recombination gain\n(hybrid − worse parent)",
|
||||
title="Epistasis wedge: recombining adapted parents\nflips from gain to loss as ruggedness grows")
|
||||
|
||||
fig.suptitle("E12 — model speciation: when two diverged models are too incompatible to merge",
|
||||
y=1.02, fontsize=13)
|
||||
fig.tight_layout()
|
||||
savefig(fig, "results/E12", "E12")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Loading…
Add table
Add a link
Reference in a new issue