codex/past-exam-of-the-flows-fluctuations-and-complexity-and-symmetry-and-relativity-paper-of-part-b-of-the-physics-course-of-the-university-of-oxford/2011-rossler-spiral.py

past-exam-of-the-flows-fluctuations-and-complexity-and-symmetry-and-relativity-paper-of-part-b-of-the-physics-course-of-the-university-of-oxford/2011-rossler-spiral.py
"""Generate the local linearized Rössler phase portrait; Python 3.14, NumPy 2.3, Matplotlib 3.10."""
from pathlib import Path
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np

a=0.16
omega=np.sqrt(1-a*a/4)
t=np.linspace(0,12*np.pi,3000)
# Exact solution of X'=-Y, Y'=X+aY, with (X(0),Y(0))=(.05,0).
X=.05*np.exp(a*t/2)*(np.cos(omega*t)-a*np.sin(omega*t)/(2*omega))
Y=.05*np.exp(a*t/2)*np.sin(omega*t)/omega
fig,ax=plt.subplots(figsize=(5.6,4.9),layout='constrained',facecolor='white')
ax.set_facecolor('white')
ax.axhline(0,color='.8',lw=.7);ax.axvline(0,color='.8',lw=.7)
ax.plot(X,Y,color='#1764a0',lw=1.8)
for idx in [350,1100,1800,2500]:
 ax.annotate('',xy=(X[idx+30],Y[idx+30]),xytext=(X[idx],Y[idx]),arrowprops=dict(arrowstyle='->',color='#1764a0',lw=1.7))
ax.scatter([0],[0],s=28,color='#b23c28',zorder=3)
ax.annotate('Inner equilibrium',xy=(0,0),xytext=(.12,-.12),fontsize=10)
ax.set(xlabel=r'$X=x-x_-$',ylabel=r'$Y=y-y_-$',title='Local planar motion: outward, counterclockwise')
ax.set_aspect('equal',adjustable='box')
fig.savefig(Path.cwd()/Path(__file__).with_suffix('.png').name,dpi=145,facecolor='white',transparent=False)