codex/chloroplast-photosynthesis-compartments.py

chloroplast-photosynthesis-compartments.py
"""Draw chloroplast stage locations; write basename.png to CWD.

Tested with Python 3.14 and the repository's Matplotlib/NumPy environment.
Original schematic, not an experimental photograph or a scale drawing.
"""

from pathlib import Path

import matplotlib

matplotlib.use("Agg")
import matplotlib.pyplot as plt
from matplotlib.patches import FancyArrowPatch, FancyBboxPatch


def main():
    green, blue, orange, ink = "#438251", "#176b92", "#a65412", "#253442"
    plt.rcParams.update({"font.size": 12, "font.family": "DejaVu Sans"})
    fig, ax = plt.subplots(figsize=(11.2, 6.8))
    fig.patch.set_facecolor("white")
    ax.set_facecolor("white")
    ax.set(xlim=(0, 15), ylim=(0, 9.6))
    ax.axis("off")

    def rounded(x, y, w, h, fill, edge, lw=1.6):
        ax.add_patch(FancyBboxPatch(
            (x, y), w, h, boxstyle="round,pad=0.02,rounding_size=0.35",
            facecolor=fill, edgecolor=edge, linewidth=lw,
        ))

    def arrow(start, end, color=blue, dashed=False):
        ax.add_patch(FancyArrowPatch(
            start, end, arrowstyle="-|>", mutation_scale=17,
            color=color, linewidth=2, linestyle="--" if dashed else "-",
        ))

    ax.text(7.5, 9.2, "Chloroplast: two stages in different compartments",
            ha="center", fontsize=17, weight="bold", color=ink)
    rounded(1.7, 1.5, 11.6, 6.4, "#f6faf0", green)
    rounded(1.87, 1.67, 11.26, 6.06, "#f6faf0", green, 1)
    ax.text(11.6, 7.25, "Stroma", color=green, fontsize=14, weight="bold")
    ax.text(7.4, 1.05, "Chloroplast envelope", color=green, ha="center", fontsize=11)

    rounded(2.55, 3.05, 3.7, 2.85, "#d9ecdd", green, 5)
    ax.text(4.4, 4.1, "Thylakoid interior\n(lumen)", ha="center", color=green)
    rounded(2.75, 5.1, 3.3, 1.28, "#ffffff", green)
    ax.text(4.4, 5.75, "1  Light reactions\nat the membrane", ha="center",
            va="center", weight="bold", fontsize=11, color=ink)
    ax.text(4.4, 2.6, "Thylakoid membrane", color=green, ha="center", fontsize=11)

    rounded(9.2, 3.5, 3.15, 2.45, "#ffffff", blue)
    ax.text(10.78, 4.72, "2  Calvin cycle\nCarbon fixation\nin the stroma",
            ha="center", va="center", color=ink, weight="bold", fontsize=12)

    ax.text(4.4, 8.4, "Light", ha="center", color=orange, weight="bold")
    arrow((4.4, 8.1), (4.4, 6.45), orange, True)
    ax.text(0.75, 5.8, "H₂O\nWater", ha="center", va="center", color=blue)
    arrow((1.22, 5.75), (2.7, 5.75))
    arrow((2.52, 3.8), (1.1, 3.8))
    ax.text(0.75, 3.15, "O₂\nReleased oxygen", ha="center", va="center",
            color=blue, fontsize=10)
    ax.text(10.78, 8.4, "CO₂", ha="center", color=blue, weight="bold")
    arrow((10.78, 8.1), (10.78, 6.02))
    arrow((6.12, 5.6), (9.14, 5.6), orange, True)
    ax.text(7.63, 6.08, "ATP + NADPH", ha="center", color=orange, fontsize=11)
    ax.text(7.63, 5.18, "energy + electrons", ha="center", color=orange, fontsize=10)
    arrow((9.14, 3.85), (6.33, 3.85), orange, True)
    ax.text(7.65, 3.4, "ADP + Pᵢ; NADP⁺\ncarriers return for reuse",
            ha="center", va="top", color=orange, fontsize=10)
    arrow((12.42, 4.65), (14.25, 4.65))
    ax.text(14.15, 3.55, "Triose\nphosphate\nfor sugars",
            ha="center", color=blue, fontsize=10)
    ax.text(7.5, 0.3,
            "Original schematic, not an experimental photo. Sizes and molecular counts are not to scale.\n"
            "Solid blue: selected matter transfers. Dashed orange: light and carrier coupling.",
            ha="center", va="center", color=ink, fontsize=10)
    fig.subplots_adjust(left=0.025, right=0.985, top=0.97, bottom=0.03)
    fig.savefig(Path.cwd() / f"{Path(__file__).stem}.png", dpi=120,
                facecolor="white", transparent=False)
    plt.close(fig)


if __name__ == "__main__":
    main()