codexpast-exam-of-the-mathematics-course-of-the-university-of-cambridge2001iiipaper-53-bifurcation.py
past-exam-of-the-mathematics-course-of-the-university-of-cambridge/2001/iii/paper-53-bifurcation.py
#!/usr/bin/env python3
"""Original attracting-orbit sketch for the quadratic period-doubling cascade."""
from pathlib import Path
import numpy as np
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
MU_INFINITY = 1.40115518909205
def draw():
parameters = np.unique(np.concatenate((np.linspace(0, 1.35, 1400),
np.linspace(1.35, MU_INFINITY, 1600))))
orbit = np.zeros_like(parameters)
for _ in range(6000):
orbit = 1 - parameters * orbit * orbit
samples = []
for _ in range(128):
orbit = 1 - parameters * orbit * orbit
samples.append(orbit.copy())
figure, ax = plt.subplots(figsize=(9.2, 5.5), facecolor='white')
ax.set_facecolor('white')
ax.scatter(np.tile(parameters, 128), np.concatenate(samples), s=.07,
color='#1e3e55', alpha=.35, rasterized=True, linewidths=0)
for value, label in [(0.75, r'$b_1=3/4$'), (1.25, r'$b_2=5/4$')]:
ax.axvline(value, color='#777777', linestyle='--', linewidth=.8)
ax.text(value - .014, -.535, label, ha='right', fontsize=11)
superstable = [(1., r'$s_1$'), (1.31070264133683, r'$s_2$'),
(1.38154748443206, r'$s_3$')]
ax.scatter([p[0] for p in superstable], np.zeros(3), s=30,
color='#b24b31', zorder=4, label='Critical-point returns: superstable cycles')
for value, label in superstable:
ax.annotate(label, (value, 0), xytext=(-13, -29), textcoords='offset points',
fontsize=11, ha='right', arrowprops={'arrowstyle':'-', 'color':'#b24b31'})
ax.axvline(MU_INFINITY, color='#b24b31', linewidth=1)
ax.text(MU_INFINITY - .01, 1.015, r'$s_\infty$', ha='right', va='bottom', fontsize=12)
ax.text(.33, .42, 'Stable fixed point', color='#1e3e55', fontsize=12)
ax.text(.94, -.32, 'Period 2', color='#1e3e55', fontsize=12)
ax.text(MU_INFINITY-.01, -.48, '4, 8, 16, ...', ha='right', color='#1e3e55', fontsize=11)
inset = ax.inset_axes([.065, .12, .35, .30])
mask = parameters >= 1.36
inset.scatter(np.tile(parameters[mask], 128), np.asarray(samples)[:,mask].ravel(),
s=.12, color='#1e3e55', alpha=.4, linewidths=0)
inset.set(xlim=(1.36, MU_INFINITY), ylim=(-.42,.17),
title='Central branches (zoom)')
inset.set_xticks([1.37, 1.40])
inset.tick_params(labelsize=8)
inset.title.set_fontsize(9)
inset.grid(alpha=.12)
ax.set(xlim=(0, MU_INFINITY + .02), ylim=(-.59, 1.09),
xlabel=r'Parameter $\mu$', ylabel='Attracting orbit value $x$',
title=r'Quadratic map $x\mapsto1-\mu x^2$: primary cascade')
ax.grid(alpha=.13)
ax.spines[['top', 'right']].set_visible(False)
ax.legend(loc='upper left', fontsize=10, framealpha=.95)
figure.tight_layout()
figure.savefig(Path('paper-53-bifurcation.png'), dpi=150,
facecolor='white', transparent=False)
plt.close(figure)
if __name__ == '__main__':
draw()