codex/globin-assembly-stoichiometry.py

globin-assembly-stoichiometry.py
"""Ideal alpha/beta/gamma-chain stoichiometry; not an intracellular assembly model.
Python 3.14; NumPy 2.3.5; Matplotlib 3.10.7.
"""
from pathlib import Path
import numpy as np
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
from matplotlib.patches import Polygon

def feasible(hba, hbf):
    return (hba >= 0) & (hbf >= 0) & (hba <= 40) & (hbf <= 30) & (hba + hbf <= 50)

def main():
    fig, ax = plt.subplots(figsize=(7.2, 4.8), dpi=100, facecolor='white')
    ax.set_facecolor('white')
    x = np.linspace(0, 50, 501)
    ax.add_patch(Polygon([(0,0),(40,0),(40,10),(20,30),(0,30)], closed=True,
                         color='#9dc9d4', alpha=0.65, label='Stoichiometrically feasible'))
    ax.plot(x, 50-x, lw=2.2, color='#225d9a', label='Alpha-chain limit: HbA + HbF ≤ 50')
    ax.axvline(40, lw=1.7, ls='--', color='#ad5628', label='Beta-chain limit: HbA ≤ 40')
    ax.axhline(30, lw=1.7, ls=':', color='#795394', label='Gamma-chain limit: HbF ≤ 30')
    ax.set(xlim=(0,50), ylim=(0,50), xlabel='Hemoglobin A tetramers (pmol)',
           ylabel='Fetal hemoglobin tetramers (pmol)', title='Shared alpha chains constrain two tetramer products')
    ax.grid(alpha=0.15)
    ax.legend(loc='upper right', fontsize=8)
    fig.text(0.5, 0.015, 'Original ideal model: 100 pmol alpha, 80 pmol beta, 60 pmol gamma; no losses or other assemblies.',
             ha='center', fontsize=8)
    fig.tight_layout(rect=(0,0.035,1,1))
    fig.savefig(Path('globin-assembly-stoichiometry.png'), facecolor='white')
    plt.close(fig)

if __name__ == '__main__':
    main()