codex/past-exam-of-the-biological-physics-course-of-the-university-of-oxford/2018-gene-circuit-and-switch.py

past-exam-of-the-biological-physics-course-of-the-university-of-oxford/2018-gene-circuit-and-switch.py
"""Original model illustration; Python 3.14, NumPy 2.3, Matplotlib 3.10."""
from pathlib import Path
import numpy as np
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
from matplotlib.patches import Ellipse, Circle
plt.rcParams.update({'font.size':11,'axes.spines.top':False,'axes.spines.right':False,'figure.facecolor':'white','savefig.facecolor':'white'})

fig,axs=plt.subplots(2,2,figsize=(10,7.5),layout='constrained');t=np.linspace(0,8,1001);h=.25;F=10
for name,y,d,color in [('I1',1-np.exp(-t),-np.log(1-h),'tab:blue'),('I4',np.exp(-t),-np.log(h),'tab:orange')]:
    axs[0,0].plot(t,y,label=name,color=color,lw=2);axs[0,0].plot(d,h,'o',color=color)
    z=np.where(t<=d,F*(1-np.exp(-t)),1+(F*(1-np.exp(-d))-1)*np.exp(-(t-d)))
    axs[0,1].plot(t,z,label=name,color=color,lw=2);axs[0,1].axvline(d,color=color,ls=':',alpha=.6)
axs[0,0].axhline(h,color='.5',ls='--',label='Y threshold 0.25');axs[0,0].set(xlabel=r'time $\alpha t$',ylabel=r'$Y/Y_s$',title='Rise or fall crosses the regulation threshold');axs[0,0].legend(fontsize=9)
axs[0,1].axhline(1,color='.5',ls='--');axs[0,1].set(xlabel=r'time $\alpha t$',ylabel=r'$Z/Z_s$',title='Both graded motifs produce pulses: F = 10');axs[0,1].legend()
for ax,gamma in zip(axs[1],[1.5,3]):
    q=np.linspace(0,gamma+.3,600)
    ax.plot(gamma/(1+q*q),q,label=r'$\dot Y=0$',lw=2);ax.plot(q,gamma/(1+q*q),label=r'$\dot Z=0$',lw=2)
    roots=np.roots([1,0,1,-gamma]);sym=next(x.real for x in roots if abs(x.imag)<1e-8)
    ax.plot(sym,sym,'o',mfc='black' if gamma<2 else 'white',mec='black',ms=8,label='stable' if gamma<2 else 'saddle')
    if gamma>2:
        hi=(gamma+np.sqrt(gamma*gamma-4))/2;lo=1/hi
        ax.plot([hi,lo],[lo,hi],'o',color='black',ms=7,label='stable alternatives')
    ax.set(xlabel='Y (reduced concentration)',ylabel='Z (reduced concentration)',xlim=(0,gamma+.3),ylim=(0,gamma+.3),title=rf'Quadratic Hill repression: $\gamma={gamma:g}$')
    ax.legend(fontsize=8)

fig.savefig(Path.cwd()/Path(__file__).with_suffix('.png').name,dpi=120,facecolor='white',transparent=False)
plt.close(fig)