"""Generate paper-141-dehn.png in CWD; Python 3.14, matplotlib 3.10.7, numpy 2.3.5. Original vector construction of the graph and crossings; no source PDF image is copied. """ import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt from matplotlib.patches import Ellipse,Circle import numpy as np fig,(ax,right)=plt.subplots(1,2,figsize=(10,5.2),dpi=100,gridspec_kw={'width_ratios':[1.05,1]}) A=np.array([0,2]);B=np.array([-.75,0]);C=np.array([.75,0]);D=np.array([0,-2]) # (start, control points, end, under at start?, under at end?) edges=[(A,[-2.8,2.7],[-2.8,-2.7],D,False,True), (D,[2.8,-2.7],[2.8,2.7],A,False,True), (A,[-1.15,1.3],[-1.0,.6],B,True,False), (B,[-.55,-.8],[.55,-.8],C,False,True), (C,[1.0,.6],[1.15,1.3],A,True,False), (D,[1.15,-1.3],[1.0,-.6],C,True,False), (C,[.55,.8],[-.55,.8],B,False,True), (B,[-1.0,-.6],[-1.15,-1.3],D,True,False)] def bezier(start,c1,c2,end,t): t=np.asarray(t)[:,None] return (1-t)**3*start+3*(1-t)**2*t*np.array(c1)+3*(1-t)*t**2*np.array(c2)+t**3*end for start,c1,c2,end,under0,under1 in edges: t=np.linspace(.055 if under0 else 0,.945 if under1 else 1,240) xy=bezier(start,c1,c2,end,t);ax.plot(xy[:,0],xy[:,1],'k',lw=2.5,zorder=3) # The right outside arc points upward, as in the source. xy=bezier(*edges[1][:4],np.array([.57,.60]));ax.annotate('',xy=xy[1],xytext=xy[0],arrowprops={'arrowstyle':'->','color':'black','lw':2},zorder=5) regions={'d':(-1.42,0),'e':(1.42,0),'a':(0,1.05),'b':(0,0),'c':(0,-1.05),'o':(-2.37,1.62)} for name,(x,y) in regions.items(): ax.text(x,y,name,ha='center',va='center',fontsize=16,color='#2368ad',zorder=6) if name!='o': # Dashed region curves stand for the face-boundary alpha curves on the thickened graph. width,height=(.45,.70) if name in 'de' else (.7,.32) ax.add_patch(Ellipse((x,y),width,height,fill=False,edgecolor='#2368ad',ls='--',lw=1.1)) for name,v in zip('ABCD',[A,B,C,D]): ax.add_patch(Circle(v,.20,fill=False,color='#b53232',lw=1.1,zorder=4)) dx,dy={'A':(-.35,.26),'B':(-.38,.19),'C':(.24,.19),'D':(-.35,-.3)}[name] ax.text(v[0]+dx,v[1]+dy,name,fontsize=12,color='#b53232') # State corners: A,d; B,a; C,b; D,c. for x,y in [(-.20,2.00),(-.72,.20),(.56,-.10),(.03,-1.75)]:ax.plot(x,y,'o',color='#d68a00',ms=7,zorder=7) for name in ('o','e'): x,y=regions[name];ax.text(x+.24,y+.16,'*',fontsize=22,color='#d68a00') ax.text(0,-2.96,r'Blue dashed: face boundaries $\alpha$'+'\n'+r'Red: crossing disks $\beta$ (sheet lifts in text)'+'\n'+r'Gold: state markers; starred regions $o,e$',ha='center',fontsize=10) ax.set_xlim(-2.65,2.55);ax.set_ylim(-3.4,2.6);ax.set_aspect('equal');ax.axis('off');ax.set_title('Figure-eight: graph, regions, and state',fontsize=12) right.axis('off');right.set_xlim(0,1);right.set_ylim(0,1) right.text(.5,.96,'Signed crossing words',ha='center',fontsize=13) words=[r'$A:\ ae^{-1}d^{-1}$',r'$B:\ ad^{-1}cb^{-1}$',r'$C:\ ba^{-1}ec^{-1}$',r'$D:\ cd^{-1}e^{-1}$'] for i,w in enumerate(words):right.text(.12,.87-i*.075,w,fontsize=14) right.text(.5,.51,'Full Alexander matrix',ha='center',fontsize=13) xs=np.linspace(.13,.89,5);ys=[.40,.31,.22,.13] for x,l in zip(xs,['d','e','a','b','c']):right.text(x,.46,l,ha='center',color='#2368ad',fontsize=13) entries=[['-1','-t','1','0','0'],['-t','0','1','-1','t'],['0','t','-t','1','-1'],['-t','-1','0','0','1']] for i,y in enumerate(ys): right.text(.02,y,'ABCD'[i],ha='center',color='#b53232',fontsize=12) for j,x in enumerate(xs):right.text(x,y,'$'+entries[i][j]+'$',ha='center',va='center',fontsize=15) for j in [[0],[2],[3],[4]][i]:right.add_patch(Ellipse((xs[j],y),.12,.075,fill=False,color='#d68a00',lw=1.8)) right.text(.5,.01,r'Chosen state term: $(+1)(-1)(1)(1)(1)=-1$',ha='center',fontsize=11) fig.subplots_adjust(left=.025,right=.98,bottom=.06,top=.91,wspace=.15) fig.savefig('paper-141-dehn.png',facecolor='white')