codex/ip3-membrane-to-calcium-store-pathway.py

ip3-membrane-to-calcium-store-pathway.py
"""Original qualitative IP3 pathway; writes matching opaque PNG to the CWD.

Tested with Python 3.14, NumPy 2.3.5 and Matplotlib 3.10.7.
Shapes and arrow lengths encode no measured geometry, amount or timing.
"""

from pathlib import Path

import matplotlib.pyplot as plt
from matplotlib.patches import FancyArrowPatch, FancyBboxPatch, Rectangle


def main():
    plt.rcParams.update({"font.size": 12, "font.family": "DejaVu Sans"})
    fig, ax = plt.subplots(figsize=(10, 6.8), dpi=130, facecolor="white")
    ax.set(xlim=(0, 10), ylim=(0, 7))
    ax.axis("off")
    orange, blue, green = "#ad5f17", "#24689b", "#357d66"
    ax.add_patch(Rectangle((0.2, 5.6), 9.6, 1.1, color="#fff6e8", zorder=0))
    ax.add_patch(Rectangle((0.2, 0.5), 9.6, 4.7, color="#f1f7fb", zorder=0))
    ax.add_patch(Rectangle((0.2, 5.2), 9.6, 0.4, color="#b8c9d5", zorder=0))
    ax.text(9.6, 6.48, "Extracellular fluid", ha="right", fontsize=12, weight="bold")
    ax.text(0.35, 4.85, "Cytosol", fontsize=12, weight="bold")
    ax.text(9.65, 5.4, "Cell membrane", ha="right", fontsize=11)

    def box(x, y, w, h, label, color="white", edge=blue):
        ax.add_patch(FancyBboxPatch((x, y), w, h, boxstyle="round,pad=0.06",
                                   facecolor=color, edgecolor=edge, linewidth=1.7))
        ax.text(x + w / 2, y + h / 2, label, ha="center", va="center")

    def arrow(start, end, color=blue, dashed=False, rad=0):
        ax.add_patch(FancyArrowPatch(start, end, arrowstyle="-|>", mutation_scale=16,
                                    linewidth=1.8, color=color,
                                    linestyle="--" if dashed else "-",
                                    connectionstyle=f"arc3,rad={rad}"))

    box(1.3, 6.0, 1.8, 0.45, "Ligand", "#fff4da", orange)
    box(1.35, 5.0, 1.7, 0.65, "Surface\nreceptor", "#fce9ce", orange)
    arrow((2.2, 6.0), (2.2, 5.67), orange, True)
    box(1.4, 3.85, 1.6, 0.65, "G protein", "#fff4da", orange)
    arrow((2.2, 4.97), (2.2, 4.55), orange, True)
    box(3.55, 3.85, 1.3, 0.65, "PLC\ncatalysis", "#fff4da", orange)
    arrow((3.07, 4.18), (3.48, 4.18), orange, True)
    box(3.45, 5.22, 1.5, 0.36, r"PIP$_2$", "white")
    arrow((4.2, 5.2), (4.2, 4.55))
    ax.text(4.3, 4.8, "hydrolysis", fontsize=10)
    box(5.7, 5.22, 1.1, 0.36, "DAG", "white")
    arrow((4.75, 4.55), (6.2, 5.16), rad=-0.12)
    ax.text(6.25, 5.82, "Membrane-associated product", ha="center", fontsize=10)
    box(4.75, 2.95, 1.5, 0.55, r"Soluble IP$_3$", "#fff4da", orange)
    arrow((4.52, 3.8), (5.1, 3.55))

    box(0.65, 0.85, 3.7, 1.7, "ER lumen\nStored calcium", "#edf6e8", green)
    box(3.5, 1.75, 1.15, 0.55, r"IP$_3$R", "white", green)
    arrow((5.2, 2.88), (4.65, 2.27), orange, True)
    ax.text(5.55, 2.53, "Channel gating", ha="center", fontsize=10, color=orange)
    arrow((4.7, 2.03), (6.05, 2.03))
    ax.text(5.25, 1.68, r"Ca$^{2+}$ release", ha="center", fontsize=10)
    box(6.2, 1.72, 2.75, 0.65, "Free cytosolic\ncalcium", "white")
    arrow((7.6, 2.42), (7.6, 3.25), orange, True)
    box(6.55, 3.3, 2.1, 0.65, "Target proteins", "#fff4da", orange)
    arrow((6.15, 1.74), (4.38, 1.23), green, rad=-0.12)
    ax.text(5.65, 0.85, "Pump back into ER", ha="center", fontsize=10, color=green)
    arrow((9.05, 2.05), (9.05, 6.08), green)
    ax.text(9.3, 3.9, "Export pump", rotation=90, va="center", fontsize=10, color=green)
    ax.text(0.4, 0.22, "Dashed: activation relay    Solid: products or calcium movement",
            fontsize=10, color="#374650")
    fig.suptitle("IP3 links membrane reception to an intracellular calcium store", fontsize=15)
    fig.subplots_adjust(left=0.02, right=0.98, bottom=0.02, top=0.92)
    fig.savefig(Path.cwd() / (Path(__file__).stem + ".png"), facecolor="white",
                transparent=False)
    plt.close(fig)


if __name__ == "__main__":
    main()