codexpast-exam-of-the-topology-course-of-the-university-of-oxford2015-square-surface-pairings.py
past-exam-of-the-topology-course-of-the-university-of-oxford/2015-square-surface-pairings.py
"""Generate 2015-square-surface-pairings.png in the current directory; Python 3.14/Matplotlib."""
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
def main():
examples=[('Sphere', [('a',1),('a',-1),('b',1),('b',-1)], 3, 'orientable'),
('Projective plane', [('a',1),('a',1),('b',1),('b',-1)], 2, 'nonorientable'),
('Torus', [('a',1),('b',1),('a',-1),('b',-1)], 1, 'orientable'),
('Klein bottle', [('a',1),('b',1),('a',-1),('b',1)], 1, 'nonorientable')]
vertices=np.array([[0,0],[1,0],[1,1],[0,1]])
fig, axes=plt.subplots(1,4,figsize=(11.4,3.2),dpi=110,facecolor='white')
for ax,(name,word,count,orientation) in zip(axes,examples):
ax.fill([0,1,1,0],[0,0,1,1],facecolor='#f8fafc')
for i,(letter,sign) in enumerate(word):
a=vertices[i];b=vertices[(i+1)%4];color='#2563eb' if letter=='a' else '#b45309'
ax.plot([a[0],b[0]],[a[1],b[1]],color=color,lw=1.4)
start,end=(a,b) if sign==1 else (b,a)
p=start+0.32*(end-start);q=start+0.68*(end-start)
ax.annotate('',xy=q,xytext=p,arrowprops={'arrowstyle':'-|>','color':color,'lw':2})
centre=(a+b)/2;outward=np.array([b[1]-a[1],a[0]-b[0]])
labelpos=centre+0.16*outward
ax.text(*labelpos,letter,ha='center',va='center',fontsize=12,color=color)
ax.set_title(name,fontsize=11,pad=10)
ax.text(0.5,-0.35,rf'$V={count},\quad\chi={count-1}$'+'\n'+orientation,ha='center',va='center',fontsize=9)
ax.set_xlim(-0.3,1.3);ax.set_ylim(-0.58,1.25);ax.set_aspect('equal');ax.axis('off')
fig.tight_layout(pad=1.1,w_pad=1.5)
fig.savefig('2015-square-surface-pairings.png',dpi=110,facecolor='white')
plt.close(fig)
if __name__=='__main__':main()