codexpast-exam-of-the-mathematical-and-computational-biology-course-of-the-university-of-cambridge2024paper-1-epochs.py
past-exam-of-the-mathematical-and-computational-biology-course-of-the-university-of-cambridge/2024/paper-1-epochs.py
"""Original solution diagram; Python 3.14, matplotlib 3.10.7.
Write paper-1-epochs.png in the current working directory.
Branch labels count descendants, rather than reproducing the exam artwork.
"""
from pathlib import Path
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
plt.rcParams.update({'font.size': 11, 'figure.facecolor': 'white', 'axes.facecolor': 'white'})
fig, axes = plt.subplots(1, 2, figsize=(10, 4.4), constrained_layout=True)
colors = ['#e4edf7', '#e3f3e8', '#fff0d5']
def horizontal(ax, x0, x1, y, descendants):
ax.plot([x0,x1],[y,y], color='#25374b', lw=2.2)
ax.text((x0+x1)/2, y+.11, str(descendants), ha='center', va='bottom', color='#25374b', fontsize=10)
def vertical(ax,x,y0,y1):
ax.plot([x,x],[y0,y1],color='#25374b',lw=2.2)
for ax,title in zip(axes, ['A: pectinate', 'B: balanced']):
for j,(name,c) in enumerate(zip(['2 branches: $T_2$','3 branches: $T_3$','4 branches: $T_4$'],colors)):
ax.axvspan(j,j+1,color=c,zorder=0)
ax.text(j+.5,-.7,name,ha='center',fontsize=10)
ax.set_title(title,pad=14,fontweight='bold')
ax.set_xlim(-.12,3.12); ax.set_ylim(-1,3.7);ax.axis('off')
ax.annotate('',xy=(3.05,-.98),xytext=(0,-.98),arrowprops={'arrowstyle':'->','color':'#555'})
ax.text(1.5,-1.22,'time: root → sampled leaves',ha='center',fontsize=10)
ax=axes[0]
vertical(ax,0,1.75,3)
horizontal(ax,0,3,3,1)
horizontal(ax,0,1,1.75,3)
vertical(ax,1,.5,2)
horizontal(ax,1,3,2,1)
horizontal(ax,1,2,.5,2)
vertical(ax,2,0,1)
horizontal(ax,2,3,0,1);horizontal(ax,2,3,1,1)
ax=axes[1]
vertical(ax,0,.5,2.5)
horizontal(ax,0,2,.5,2);horizontal(ax,0,1,2.5,2)
vertical(ax,1,2,3)
horizontal(ax,1,3,2,1);horizontal(ax,1,3,3,1)
vertical(ax,2,0,1)
horizontal(ax,2,3,0,1);horizontal(ax,2,3,1,1)
for ax in axes:
ax.scatter([3]*4,[0,1,2,3],s=32,color='#25374b',zorder=4)
fig.suptitle('Epochs are intervals with a constant number of branches',fontsize=13,fontweight='bold')
fig.savefig(Path('paper-1-epochs.png'),dpi=125,facecolor='white',bbox_inches='tight')
plt.close(fig)