codexnuclear-dna-content-versus-ploidy.py
nuclear-dna-content-versus-ploidy.py
"""Show original DNA-content/ploidy states, not fluorescence measurements.
Tested with Python 3.14, matplotlib 3.10.7 and numpy 2.3.5.
Run from the desired output directory; save the matching basename PNG there.
"""
from pathlib import Path
import matplotlib.pyplot as plt
from matplotlib.patches import FancyBboxPatch
def main():
plt.rcParams.update({"font.size": 12, "font.family": "DejaVu Sans"})
fig, (ax, panel) = plt.subplots(1, 2, figsize=(12, 5.8), dpi=100,
gridspec_kw={"width_ratios": [1.15, 1]})
fig.patch.set_facecolor("white")
ax.set_facecolor("white")
ax.set(xlim=(0.55, 2.55), ylim=(0.45, 4.9), xticks=[1, 2],
xticklabels=["1 set (haploid)", "2 sets (diploid)"],
yticks=[1, 2, 3, 4], yticklabels=["1C", "2C", "3C", "4C"])
ax.set_xlabel("Ploidy: complete chromosome sets", labelpad=12)
ax.set_ylabel("Nuclear DNA content", labelpad=8)
ax.set_title("A. Allocation path per product", weight="bold", pad=18)
ax.grid(axis="y", color="#e4e9ed")
ax.spines[["top", "right"]].set_visible(False)
for xy, label, offset in [((2, 2), "Diploid G1", (10, -26)),
((2, 4), "Diploid G2", (10, 9)),
((1, 2), "After meiosis I", (-8, 14)),
((1, 1), "After meiosis II", (10, -14))]:
ax.scatter(*xy, s=130, color="#167c91", edgecolors="white", zorder=4)
ax.annotate(label, xy=xy, xytext=offset, textcoords="offset points",
ha="right" if offset[0] < 0 else "left", fontsize=11)
for start, end in [((2, 2.12), (2, 3.88)), ((1.9, 3.9), (1.08, 2.13)),
((1, 1.88), (1, 1.12))]:
ax.annotate("", xy=end, xytext=start,
arrowprops={"arrowstyle": "->", "lw": 2.2, "color": "#435267"})
ax.text(2.12, 3.0, "DNA\nreplication", fontsize=11, va="center")
ax.text(1.40, 3.43, "Meiosis I", fontsize=11, rotation=37,
bbox={"facecolor": "white", "edgecolor": "none", "pad": 2})
ax.text(0.93, 1.5, "Meiosis II", fontsize=11, ha="right", va="center")
panel.set(xlim=(0, 1), ylim=(0, 1))
panel.axis("off")
panel.set_title("B. Same amount, different set count", weight="bold", pad=18)
panel.text(0.5, 0.85, "2C", ha="center", fontsize=30, weight="bold", color="#167c91")
for y, title, text in [(0.56, "Diploid G1", "2 sets × 1 copy per chromosome\n6 chromosomes; 6 DNA copies"),
(0.22, "Haploid after meiosis I", "1 set × 2 sister copies\n3 chromosomes; 6 DNA copies")]:
panel.add_patch(FancyBboxPatch((0.02, y - 0.11), 0.96, 0.24,
boxstyle="round,pad=0.015", facecolor="#f6f8fa",
edgecolor="#b7c4cf"))
panel.text(0.5, y + 0.064, title, ha="center", weight="bold", fontsize=13)
panel.text(0.5, y - 0.035, text, ha="center", va="center", fontsize=12, linespacing=1.5)
panel.text(0.5, 0.01, "A DNA amount alone does not identify ploidy.", ha="center", fontsize=11)
fig.suptitle("Illustrative nuclear DNA content versus ploidy: stipulated 2n = 6",
fontsize=17, weight="bold", y=0.96)
fig.text(0.5, 0.025, "Original idealized states, not measurements. Arrows describe completed products; they do not represent elapsed time.",
ha="center", fontsize=10, color="#435267")
fig.subplots_adjust(left=0.08, right=0.97, top=0.8, bottom=0.16, wspace=0.4)
fig.savefig(Path.cwd() / (Path(__file__).stem + ".png"), facecolor="white", transparent=False)
plt.close(fig)
if __name__ == "__main__":
main()