"""Annotated diagram so the user can answer the v_c-rotation clarification questions. Shows the 9-vertex L_k with e_0 = (0, 3) highlighted, both candidate v_c vertices (0 and 3) labelled, and the four (v_c, direction) fans laid out around each.""" import os import math import matplotlib.pyplot as plt from matplotlib.patches import Polygon, FancyArrowPatch OUT_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), os.pardir) n = 9 POS = {i: (math.cos(math.radians(90 - i * 360 / n)), math.sin(math.radians(90 - i * 360 / n))) for i in range(n)} OUTER_EDGES = [(i, (i + 1) % n) for i in range(n)] CHORDS = [(0, 2), (0, 3), (3, 5), (3, 6), (0, 6), (6, 8)] # Inner faces FACES = { (0, 1, 2): 0, (0, 2, 3): 0, (3, 4, 5): 0, (3, 5, 6): 0, (6, 7, 8): 0, (6, 8, 0): 0, (0, 3, 6): 1, # F } F_idx_face = (0, 3, 6) Fp_face = (0, 2, 3) e0 = (0, 3) def cw_order_around(v): """Sort vertices adjacent to v by clockwise angle (decreasing angle from v, starting at angle 90).""" adj = set() for f in FACES: if v in f: for u in f: if u != v: adj.add(u) # angle of each adjacent vertex def angle(u): return (90 - u * 360 / n) % 360 return sorted(adj, key=lambda u: -angle(u)) fig, axes = plt.subplots(1, 2, figsize=(14, 7)) palette = {0: '#86efac', 1: '#fde68a'} edge_pal = {0: '#16a34a', 1: '#d97706'} def draw_base(ax, title): # Fill faces by depth for face, depth in FACES.items(): poly = Polygon([POS[v] for v in face], closed=True, facecolor=palette[depth], edgecolor=edge_pal[depth], linewidth=1.2, alpha=0.5, zorder=0) ax.add_patch(poly) # Edges for (a, b) in OUTER_EDGES + CHORDS: color, lw = '#333', 1.2 if {a, b} == set(e0): color, lw = '#dc2626', 3.4 # e_0 highlighted ax.plot([POS[a][0], POS[b][0]], [POS[a][1], POS[b][1]], color=color, linewidth=lw, zorder=1) # Vertices for i, (x, y) in POS.items(): color = '#3b82f6' if i in e0 else '#1f2937' size = 470 if i in e0 else 280 ax.scatter([x], [y], s=size, c=color, edgecolors='black', linewidths=1.2, zorder=2) ax.text(x, y, str(i), ha='center', va='center', fontsize=11 if i in e0 else 9, color='white', fontweight='bold', zorder=3) # Annotate F and F' cx_F = sum(POS[v][0] for v in F_idx_face) / 3 cy_F = sum(POS[v][1] for v in F_idx_face) / 3 ax.text(cx_F, cy_F + 0.1, r'$F$', ha='center', fontsize=14, color='#92400e', fontweight='bold', zorder=4) ax.text(cx_F, cy_F - 0.1, '(depth 1)', ha='center', fontsize=9, color='#92400e', zorder=4) cx_Fp = sum(POS[v][0] for v in Fp_face) / 3 cy_Fp = sum(POS[v][1] for v in Fp_face) / 3 ax.text(cx_Fp + 0.1, cy_Fp, r"$F'$" + '\n(depth 0)', ha='center', fontsize=10, color='#16a34a', fontweight='bold', zorder=4) # F''s outer-cycle edge: (2, 3) px, py = POS[2], POS[3] mid = ((px[0] + py[0]) / 2, (px[1] + py[1]) / 2) ax.annotate("outer edge of $F'$", xy=(mid[0] + 0.05, mid[1] - 0.05), xytext=(1.35, 0.5), fontsize=9, color='#16a34a', arrowprops=dict(arrowstyle='->', color='#16a34a', lw=1.0)) ax.set_aspect('equal'); ax.axis('off') ax.set_xlim(-1.5, 1.7); ax.set_ylim(-1.4, 1.4) ax.set_title(title, fontsize=12) def annotate_fan(ax, vc, label): """Draw arrows around v_c showing CW order of edges.""" cw_neighbours = cw_order_around(vc) # rotate so the e_0 neighbour comes first e0_other = [u for u in e0 if u != vc][0] idx = cw_neighbours.index(e0_other) cw_neighbours = cw_neighbours[idx:] + cw_neighbours[:idx] px, py = POS[vc] # Draw a partial arc around v_c for i, u in enumerate(cw_neighbours): # midpoint between v_c and u, slightly inside ux, uy = POS[u] midx = px * 0.7 + ux * 0.3 midy = py * 0.7 + uy * 0.3 # is edge on outer cycle? is_outer = (min(vc, u), max(vc, u)) in OUTER_EDGES or \ (max(vc, u), min(vc, u)) in OUTER_EDGES marker_color = '#1d4ed8' if not is_outer else '#dc2626' marker = 'o' ax.scatter([midx], [midy], s=120, c=marker_color, marker=marker, edgecolors='white', linewidths=1.5, zorder=5) ax.text(midx, midy, str(i + 1), ha='center', va='center', fontsize=8, color='white', fontweight='bold', zorder=6) # Label ax.text(px + 0.05, py + 0.25, label, ha='center', fontsize=11, color='#1d4ed8', fontweight='bold') draw_base(axes[0], r'Option A: $v_c = 0$ (CW order: 1=$(0,3)$, 2=$(0,6)$, 3=$(0,8)$ outer ...)') annotate_fan(axes[0], 0, r'$v_c = 0$') draw_base(axes[1], r'Option B: $v_c = 3$ (CW order: 1=$(0,3)$, 2=$(2,3)$ outer ...)') annotate_fan(axes[1], 3, r'$v_c = 3$') # Add legend below fig.text(0.5, 0.02, 'Blue circles = chord edges (would be switched). ' 'Red circles = outer-cycle edges (algorithm stops here). ' 'Numbers = clockwise order around $v_c$ starting from $e_0$.', ha='center', fontsize=10) fig.tight_layout(rect=[0, 0.04, 1, 1]) out = os.path.join(OUT_DIR, 'fig_v_c_question.png') fig.savefig(out, dpi=180, bbox_inches='tight') plt.close(fig) print(f'wrote {out}')