codexpast-exam-of-the-mathematics-course-of-the-university-of-cambridge2010iiipaper-67-instability.py
past-exam-of-the-mathematics-course-of-the-university-of-cambridge/2010/iii/paper-67-instability.py
"""Draw the analytic instability domain; tested with Python 3.14.
Uses root-pinned NumPy/Matplotlib, preserves caller MPLCONFIGDIR, and writes
paper-67-instability.png to the caller's current working directory.
"""
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
def main():
threshold = 3 + 2*np.sqrt(2)
b = np.linspace(.025, 1, 1200)
d = threshold/b
fig, ax = plt.subplots(figsize=(7, 4.1), dpi=120, facecolor='white',
constrained_layout=True)
ax.set_facecolor('white')
ax.fill_between(b, d, 35, where=d<35, color='#b9dcd2', alpha=1)
ax.plot(b, d, color='#176b55', linewidth=2,
label=r'Neutral boundary: $d=(3+2\sqrt{2})/b$')
ax.axvline(1, linestyle='--', color='#555555', linewidth=1.3)
ax.text(.58, 24, 'Diffusion-driven\ninstability', ha='center',
va='center', fontsize=12, color='#124f3f')
ax.text(.56, 3, 'No diffusion-driven instability', ha='center', fontsize=9)
ax.text(1.055, 18, 'Homogeneous\nkinetics not stable', fontsize=9,
rotation=90, ha='center', va='center')
ax.annotate(r'$d\to\infty$ as $b\to0^+$', xy=(.18,32.4),
xytext=(.32,32), arrowprops={'arrowstyle':'->'}, fontsize=9)
ax.scatter([1],[threshold], facecolors='white', edgecolors='#176b55', zorder=4)
ax.set(xlim=(0,1.16), ylim=(0,35), xlabel='Reaction parameter b',
ylabel='Inhibitor / activator diffusivity ratio d',
title='Diffusion-driven instability: 0 < b < 1 and db > 3 + 2√2')
ax.grid(alpha=.22)
ax.legend(loc='upper right', fontsize=8)
fig.savefig('paper-67-instability.png', facecolor='white', transparent=False)
plt.close(fig)
if __name__ == '__main__':
main()