codexfetal-hemoglobin-affinity-model.py
fetal-hemoglobin-affinity-model.py
"""Illustrative Hill curves, not measured fetal/adult hemoglobin parameters.
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
def occupancy(pressure, midpoint, exponent=2):
p = np.asarray(pressure)
return p**exponent / (midpoint**exponent + p**exponent)
def main():
p = np.linspace(0, 80, 801)
fig, ax = plt.subplots(figsize=(8, 4.2), dpi=100, facecolor='white')
ax.set_facecolor('white')
for midpoint, color, label in [(20, '#245d9c', 'Higher-affinity model'), (30, '#c86429', 'Lower-affinity model')]:
ax.plot(p, occupancy(p, midpoint), lw=2.2, color=color,
label=f'{label}: midpoint {midpoint}')
ax.scatter([25], [occupancy(25, midpoint)], color=color, s=34, zorder=4)
ax.axvline(25, color='#666666', ls=':', lw=1)
ax.set(xlim=(0, 80), ylim=(0, 1), xlabel='Oxygen partial pressure (arbitrary units)',
ylabel='Fraction of sites occupied', title='Higher affinity changes occupancy at the same oxygen pressure')
ax.legend(loc='lower right', fontsize=9)
ax.grid(alpha=0.15)
fig.text(0.5, 0.015, 'Original Hill models, exponent 2. Midpoints are stipulated; no physiological reference values or fitted data.',
ha='center', fontsize=8)
fig.tight_layout(rect=(0, 0.045, 1, 1))
fig.savefig(Path('fetal-hemoglobin-affinity-model.png'), facecolor='white')
plt.close(fig)
if __name__ == '__main__':
main()