coloring_nested_tire_graphs: redraw rainbow orbit as edge colorings (σ on spoke edges, not vertices)

Previous figures drew σ as VERTEX colors on a 6-cycle.  This was
misleading: σ = (1,2,3,2,3,1) is not a proper vertex 3-coloring of
a hexagon (σ_5 = σ_0 = 1 at adjacent vertices), and the user
correctly flagged this.

σ is the coloring of the 6 *spoke edges* -- the G'-edges of G' that
cross γ, equivalently the 6 edges of γ ⊂ G under the duality
γ-edge ↔ crossing G'-edge.

Adjacent γ-edges meet at γ-vertices, which are not G'-vertices, so
σ has NO proper-coloring constraint on itself.  Proper-edge-coloring
constraints live on each tire's full annular cycle, which is longer
than 6 (T_1's is 12, T_2's is 9), with γ-spokes interleaved among
non-γ spokes; that's where the extendibility of σ is actually
checked.

Redrawn figures:
- fig_rainbow_orbit.png: σ drawn as edge colors of γ (not vertex
  colors), all 6 orbit elements.
- fig_rainbow_pattern.png: abstract pattern abcbca as edge labels,
  with explanatory text in the legend.
- fig_rainbow_setup.png: shows γ between the two tires with each
  tire's full annular cycle (length 12 and 9), the interleaved
  non-γ dual vertices, the dashed G'-spoke edges crossing γ
  colored by σ, and T_1's antipodal chord in O_1.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-26 03:03:56 -04:00
parent 7b8a5eb81a
commit 8dd9d537f9
4 changed files with 229 additions and 173 deletions
@@ -3,26 +3,29 @@ tire_fiber_step2.tex, Observation rainbow:
k = 6, T_1 = (6, (0,3), SP) vs T_2 = (3, -, SR) k = 6, T_1 = (6, (0,3), SP) vs T_2 = (3, -, SR)
|S_1 ∩ S_2| = 6 |S_1 ∩ S_2| = 6
The 6 elements are exactly {(a, b, c, b, c, a) : {a,b,c} = {1,2,3}} The 6 elements are exactly {(a, b, c, b, c, a) : {a,b,c} = {1,2,3}}.
--- the S_3 orbit of the pattern abstractly written abcbca.
Produces three figures: IMPORTANT INTERPRETATION:
σ{1,2,3}^6 is the coloring of the SIX G'-EDGES THAT CROSS γ,
equivalently a coloring of the 6 edges of the shared cycle γ ⊂ G.
fig_rainbow_pattern.png: σ is NOT a proper 3-coloring of a 6-cycle: adjacent entries CAN
The abstract pattern abcbca on the shared 6-cycle, showing the coincide, because:
three antipodal/positional symmetry classes (positions {0,5}, - T_1's annular cycle has length m_1 + |γ| = 6 + 6 = 12.
{1,3}, {2,4}). - T_2's annular cycle has length |γ| + k_2 = 6 + 3 = 9.
- σ records 6 "γ-side" spoke positions interleaved with
non-γ-side spoke positions on the longer cycle.
fig_rainbow_orbit.png: Proper-edge-coloring constraints live on each tire's full annular
All six concrete colourings in the S_3 orbit, drawn as small cycle, not on σ directly. σ is simply the boundary data, like a
hexagons with positions colored. Highlights how each permutation Birkhoff ring coloring.
of {1,2,3} gives one element.
fig_rainbow_setup.png: Produces:
The geometric setup: shared cycle gamma (the hexagon), T_1 fig_rainbow_orbit.png -- all 6 orbit elements as colored γ-edges
outside (with its antipodal chord), T_2 inside (the triangle), fig_rainbow_pattern.png -- abstract pattern (a,b,c,b,c,a)
spoke edges crossing gamma. Shows why the antipodal chord in T_1 fig_rainbow_setup.png -- geometric setup, showing why σ is on
pins the pattern. γ's EDGES, with the longer annular
cycles indicated.
""" """
import math import math
import os import os
@@ -30,17 +33,14 @@ import matplotlib.pyplot as plt
import matplotlib.patches as patches import matplotlib.patches as patches
# Color palette: a 3-color set used consistently across all figures.
COLORS = { COLORS = {
1: '#1f77b4', # blue ("color 1") 1: '#1f77b4', # blue
2: '#d62728', # red ("color 2") 2: '#d62728', # red
3: '#2ca02c', # green ("color 3") 3: '#2ca02c', # green
} }
NAMES = {1: '1', 2: '2', 3: '3'}
def hex_positions(n=6, radius=1.0, angle_offset=math.pi / 2): def hex_positions(n=6, radius=1.0, angle_offset=math.pi / 2):
"""Return positions of n evenly-spaced points on a circle of given radius."""
return [ return [
(radius * math.cos(angle_offset - 2 * math.pi * i / n), (radius * math.cos(angle_offset - 2 * math.pi * i / n),
radius * math.sin(angle_offset - 2 * math.pi * i / n)) radius * math.sin(angle_offset - 2 * math.pi * i / n))
@@ -48,79 +48,92 @@ def hex_positions(n=6, radius=1.0, angle_offset=math.pi / 2):
] ]
def draw_hex_with_pattern(ax, pattern, *, radius=1.0, label_size=10, def draw_gamma_with_edge_colors(ax, sigma, *, radius=1.0, edge_width=5.0,
dot_size=20, ring_color='#888888'): vertex_size=8, vertex_color='#222',
"""Draw a 6-cycle with edges in ring_color and vertices colored by pattern show_indices=True):
(length-6 list of colors). pattern[i] is the color of position i. """Draw the 6-cycle γ with edge i colored by sigma[i]. Vertices
""" are small black dots (they carry no color)."""
pos = hex_positions(6, radius=radius) pos = hex_positions(6, radius=radius)
# cycle edges # Edges
for i in range(6): for i in range(6):
x1, y1 = pos[i] x1, y1 = pos[i]
x2, y2 = pos[(i + 1) % 6] x2, y2 = pos[(i + 1) % 6]
ax.plot([x1, x2], [y1, y2], color=ring_color, linewidth=1.6, zorder=1) ax.plot([x1, x2], [y1, y2], color=COLORS[sigma[i]],
# vertices linewidth=edge_width, solid_capstyle='round', zorder=1)
for i, c in enumerate(pattern): # Edge index label, placed at midpoint, slightly inside
if show_indices:
mx, my = (x1 + x2) / 2, (y1 + y2) / 2
# nudge toward origin
ix, iy = mx * 0.78, my * 0.78
ax.annotate(f"$e_{i}$", (ix, iy), color='#444',
ha='center', va='center', fontsize=8, zorder=4)
# Vertices (small uncolored dots)
for i in range(6):
x, y = pos[i] x, y = pos[i]
ax.plot(x, y, 'o', color=COLORS[c], markersize=dot_size, zorder=2, ax.plot(x, y, 'o', color=vertex_color, markersize=vertex_size,
markeredgecolor='black', markeredgewidth=0.8) zorder=2)
# tiny label of position if show_indices:
lx, ly = 1.32 * x, 1.32 * y # vertex label outside
ax.annotate(str(i), (lx, ly), color='#444', ha='center', va='center', lx, ly = 1.28 * x, 1.28 * y
fontsize=label_size - 1, zorder=3) ax.annotate(f"$v_{i}$", (lx, ly), color='#555',
ha='center', va='center', fontsize=8, zorder=3)
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# Figure 1: the abstract pattern abcbca on a hexagon. # Figure 1: abstract pattern abcbca, σ shown as EDGE colors.
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
def fig_pattern(outdir): def fig_pattern(outdir):
fig, ax = plt.subplots(figsize=(6.0, 5.4)) fig, ax = plt.subplots(figsize=(7.0, 5.4))
pos = hex_positions(6, radius=1.0) pos = hex_positions(6, radius=1.0)
# Draw cycle edges # Edges with class letters as text labels at midpoint
for i in range(6): classes = ['a', 'b', 'c', 'b', 'c', 'a']
x1, y1 = pos[i]
x2, y2 = pos[(i + 1) % 6]
ax.plot([x1, x2], [y1, y2], color='#888888', linewidth=2.0, zorder=1)
classes = {0: 'a', 1: 'b', 2: 'c', 3: 'b', 4: 'c', 5: 'a'}
class_colors = { class_colors = {
'a': '#bdbdbd', 'a': '#bdbdbd',
'b': '#ffe082', 'b': '#ffe082',
'c': '#a5d6a7', 'c': '#a5d6a7',
} }
for i in range(6):
x1, y1 = pos[i]
x2, y2 = pos[(i + 1) % 6]
ax.plot([x1, x2], [y1, y2], color=class_colors[classes[i]],
linewidth=8.0, solid_capstyle='round', zorder=1)
mx, my = (x1 + x2) / 2, (y1 + y2) / 2
ax.annotate(classes[i], (mx, my), color='black', ha='center',
va='center', fontsize=13, fontweight='bold', zorder=2)
for i in range(6): for i in range(6):
x, y = pos[i] x, y = pos[i]
cls = classes[i] ax.plot(x, y, 'o', color='#222', markersize=11, zorder=3)
ax.plot(x, y, 'o', color=class_colors[cls], markersize=34, zorder=2, lx, ly = 1.25 * x, 1.25 * y
markeredgecolor='black', markeredgewidth=1.0) ax.annotate(f"$v_{i}$", (lx, ly), color='#444', ha='center',
ax.annotate(cls, (x, y), color='black', ha='center', va='center', va='center', fontsize=10, zorder=4)
fontsize=15, fontweight='bold', zorder=3)
lx, ly = 1.34 * x, 1.34 * y
ax.annotate(f'$v_{i}$', (lx, ly), color='#333', ha='center',
va='center', fontsize=11, zorder=3)
# Legend showing the position-class assignments
legend = ( legend = (
r"$\sigma = (a, b, c, b, c, a)$" + "\n" r"$\sigma$ colors the 6 edges of $\gamma$" + "\n"
+ r"position classes:" + "\n" + r"(equivalently, the 6 dual edges of $G'$" + "\n"
+ r" $a$: $\{v_0, v_5\}$" + "\n" + r" that cross $\gamma$)." + "\n\n"
+ r" $b$: $\{v_1, v_3\}$" + "\n" + r"Pattern: $(e_0,\dots,e_5) = (a,b,c,b,c,a)$" + "\n"
+ r" $c$: $\{v_2, v_4\}$" + r" $a$ on $\{e_0, e_5\}$" + "\n"
+ r" $b$ on $\{e_1, e_3\}$" + "\n"
+ r" $c$ on $\{e_2, e_4\}$" + "\n\n"
+ r"Adjacent edges *may* share a color:" + "\n"
+ r" $e_5$ and $e_0$ both $= a$ here." + "\n"
+ r" This is fine because proper-coloring" + "\n"
+ r" constraints live on each tire's" + "\n"
+ r" longer annular cycle, not on $\sigma$."
) )
ax.text(1.85, 0.0, legend, fontsize=11, color='#222', ax.text(1.85, 0.0, legend, fontsize=9, color='#222',
family='monospace',
verticalalignment='center', verticalalignment='center',
bbox=dict(boxstyle='round,pad=0.5', facecolor='#f8f8f8', bbox=dict(boxstyle='round,pad=0.5', facecolor='#f8f8f8',
edgecolor='#bbb')) edgecolor='#bbb'))
ax.set_xlim(-1.6, 4.0) ax.set_xlim(-1.6, 5.0)
ax.set_ylim(-1.7, 1.7) ax.set_ylim(-1.7, 1.7)
ax.set_aspect('equal') ax.set_aspect('equal')
ax.axis('off') ax.axis('off')
ax.set_title(r"Rainbow pattern $(a,b,c,b,c,a)$ on the shared cycle $\gamma$" ax.set_title(r"Rainbow pattern $(a,b,c,b,c,a)$ as an edge coloring of "
+ " (length $k=6$)", + r"$\gamma$ ($|\gamma| = 6$)",
fontsize=11) fontsize=11)
out = os.path.join(outdir, 'fig_rainbow_pattern.png') out = os.path.join(outdir, 'fig_rainbow_pattern.png')
@@ -130,11 +143,9 @@ def fig_pattern(outdir):
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# Figure 2: the 6 concrete colourings in the S_3 orbit. # Figure 2: the 6 orbit elements as edge colorings of γ.
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
def fig_orbit(outdir): def fig_orbit(outdir):
# The 6 permutations of (a, b, c) -> (1, 2, 3) instantiated into the
# pattern (a, b, c, b, c, a).
perms = [ perms = [
(1, 2, 3), (1, 2, 3),
(1, 3, 2), (1, 3, 2),
@@ -144,26 +155,28 @@ def fig_orbit(outdir):
(3, 2, 1), (3, 2, 1),
] ]
fig, axes = plt.subplots(2, 3, figsize=(10.5, 7.5)) fig, axes = plt.subplots(2, 3, figsize=(11.0, 7.6))
for idx, (a, b, c) in enumerate(perms): for idx, (a, b, c) in enumerate(perms):
ax = axes[idx // 3, idx % 3] ax = axes[idx // 3, idx % 3]
pattern = [a, b, c, b, c, a] sigma = (a, b, c, b, c, a)
draw_hex_with_pattern(ax, pattern, dot_size=24) draw_gamma_with_edge_colors(ax, sigma)
ax.set_xlim(-1.7, 1.7) ax.set_xlim(-1.6, 1.6)
ax.set_ylim(-1.7, 1.7) ax.set_ylim(-1.6, 1.6)
ax.set_aspect('equal') ax.set_aspect('equal')
ax.axis('off') ax.axis('off')
# title shows pattern explicitly
title = (f"$(a,b,c) = ({a},{b},{c})$\n" title = (f"$(a,b,c) = ({a},{b},{c})$\n"
+ r"$\sigma = ($" + ",".join(str(x) for x in pattern) + r"$)$") + r"$\sigma = ($" + ",".join(str(x) for x in sigma) + r"$)$")
ax.set_title(title, fontsize=10) ax.set_title(title, fontsize=10)
fig.suptitle(r"The 6-element rainbow orbit: $S_3$ acting on pattern " fig.suptitle(r"The 6-element rainbow orbit, drawn as edge colorings of "
+ r"$(a,b,c,b,c,a)$, the entire $|S_1 \cap S_2| = 6$ in step-2" + r"the shared cycle $\gamma$" + "\n"
+ r"$\sigma$ is the coloring of the 6 dual edges of $G'$ "
+ r"crossing $\gamma$, equivalently the 6 edges of $\gamma$"
+ "\n" + "\n"
+ r"$T_1 = (m{=}6, \mathrm{chord}{=}(0,3), \mathrm{SP})$ vs. " + r"Case: $T_1{=}(m{=}6,\, \mathrm{chord}{=}(0,3),\, "
+ r"$T_2 = (k{=}3, \mathrm{SR})$ on shared cycle of length $k{=}6$", + r"\mathrm{SP})$ vs. $T_2{=}(k{=}3,\, \mathrm{SR})$, "
+ r"$|S_1 \cap S_2| = 6$",
fontsize=11, y=1.00) fontsize=11, y=1.00)
plt.tight_layout() plt.tight_layout()
out = os.path.join(outdir, 'fig_rainbow_orbit.png') out = os.path.join(outdir, 'fig_rainbow_orbit.png')
@@ -173,127 +186,170 @@ def fig_orbit(outdir):
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# Figure 3: geometric setup --- T_1 (hexagon + antipodal chord) outside gamma, # Figure 3: geometric setup. Shows γ between T_1 and T_2; σ as colored
# T_2 (triangle) inside gamma, the 6 spoke edges crossing gamma. # G'-edges across γ; each tire's annular cycle indicated with the correct
# number of vertices and interleaved non-γ spokes.
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
def fig_setup(outdir): def fig_setup(outdir):
fig, ax = plt.subplots(figsize=(8.5, 7.5)) fig, ax = plt.subplots(figsize=(11.5, 7.2))
# Shared cycle gamma at radius R_gamma # γ at radius R_gamma; we draw it as a hexagon.
R_gamma = 1.4 R_gamma = 1.5
gamma_pos = hex_positions(6, radius=R_gamma) gamma_pos = hex_positions(6, radius=R_gamma)
# T_1 lives outside gamma. Its "B_in" is gamma; its "B_out" is a bigger # T_1's annular cycle is a 12-cycle in G'. In Π_G it sits between
# hexagon at R_out, with an antipodal chord across T_1's B_in side. # γ and a larger outer boundary; vertices of T_1's annular cycle are
# For visualization, draw T_1's annular region as an annulus around gamma. # DUAL vertices of T_1's annular faces. 6 of them are on the
R_out = 2.5 # γ-side, 6 on the m_1 side. We draw them as 12 points spread
R_in = 0.55 # outside γ.
T1_outer = hex_positions(6, radius=R_out) R_T1_inner = 2.0 # γ-side of T_1's annular cycle vertices
R_T1_outer = 3.2 # m_1-side of T_1's annular cycle vertices
# Draw T_1 outer boundary (B_out for T_1) # Position T_1 dual vertices: alternate inner / outer as one goes around.
for i in range(6): # In a balanced spoke-only triangulation, the 12 dual vertices alternate
x1, y1 = T1_outer[i] # between γ-side (I-move) and outer-side (O-move).
x2, y2 = T1_outer[(i + 1) % 6] T1_inner_pts = []
ax.plot([x1, x2], [y1, y2], color='#444', linewidth=2.0, zorder=2) T1_outer_pts = []
# Draw the annular region for T_1 (shaded)
outer_poly = patches.Polygon(T1_outer + gamma_pos[::-1], closed=True,
facecolor='#e3f2fd', edgecolor='none',
alpha=0.55, zorder=0)
ax.add_patch(outer_poly)
# Draw spokes between gamma_pos[i] and T1_outer[i] (representing radial spokes
# in T_1's annular triangulation, schematically).
for i in range(6): for i in range(6):
# γ-side dual vertex: just outside γ-edge i, halfway between v_i and v_{i+1}
x1, y1 = gamma_pos[i] x1, y1 = gamma_pos[i]
x2, y2 = T1_outer[i] x2, y2 = gamma_pos[(i + 1) % 6]
ax.plot([x1, x2], [y1, y2], color='#a0a0a0', linewidth=0.9, mx, my = (x1 + x2) / 2, (y1 + y2) / 2
linestyle=':', zorder=2) r_m = math.hypot(mx, my)
ux, uy = mx / r_m, my / r_m
T1_inner_pts.append((R_T1_inner * ux, R_T1_inner * uy))
# m_1-side dual vertex: just past v_i, outside.
r_v = math.hypot(x1, y1)
ux, uy = x1 / r_v, y1 / r_v
T1_outer_pts.append((R_T1_outer * ux, R_T1_outer * uy))
# T_1's antipodal chord across its B_in (= gamma): # T_1 outer boundary B_out (length m_1 = 6) and the 12-cycle of
# this chord is in the O of T_1, conceptually living outside gamma in T_1's # annular face dual vertices: alternate T1_inner_pts and T1_outer_pts
# interior outerplanar O. For the diagram we represent it as a curved chord # going around. Draw the 12-cycle edges as light gray.
# outside gamma connecting two opposite gamma vertices. T1_cycle = []
chord_p1 = gamma_pos[0] for i in range(6):
chord_p2 = gamma_pos[3] T1_cycle.append(T1_inner_pts[i])
# Draw outside gamma using an arc above T1_cycle.append(T1_outer_pts[(i + 1) % 6])
for i in range(12):
x1, y1 = T1_cycle[i]
x2, y2 = T1_cycle[(i + 1) % 12]
ax.plot([x1, x2], [y1, y2], color='#90a4ae', linewidth=1.0,
linestyle=':', zorder=1)
for (x, y) in T1_inner_pts:
ax.plot(x, y, 'o', color='#607d8b', markersize=7, zorder=3)
for (x, y) in T1_outer_pts:
ax.plot(x, y, 'o', color='#90a4ae', markersize=5, zorder=3)
# T_1's chord (in O_1, antipodal) -- draw outside γ as an arc.
chord_p1 = T1_outer_pts[0]
chord_p2 = T1_outer_pts[3]
chord_arc = patches.FancyArrowPatch(chord_p1, chord_p2, chord_arc = patches.FancyArrowPatch(chord_p1, chord_p2,
connectionstyle='arc3,rad=0.55', connectionstyle='arc3,rad=0.45',
arrowstyle='-', color='#9c27b0', arrowstyle='-', color='#9c27b0',
linewidth=2.2, linestyle=(0, (3, 2)), linewidth=1.8, linestyle=(0, (3, 2)),
zorder=4) zorder=2)
ax.add_patch(chord_arc) ax.add_patch(chord_arc)
# T_2 lives inside gamma. T_2's B_out = gamma (length 6), # T_2's annular cycle (length |γ| + k_2 = 6 + 3 = 9) inside γ.
# T_2's B_in = a triangle of length 3. # 6 γ-side dual vertices and 3 k_2-side dual vertices.
triangle_pos = hex_positions(3, radius=R_in, angle_offset=math.pi / 2) R_T2_inner = 0.45 # k_2-side
for i in range(3): R_T2_outer = 1.05 # γ-side
x1, y1 = triangle_pos[i] T2_outer_pts = []
x2, y2 = triangle_pos[(i + 1) % 3]
ax.plot([x1, x2], [y1, y2], color='#444', linewidth=2.0, zorder=2)
# Draw T_2's annular region (between gamma and triangle, shaded)
inner_poly = patches.Polygon(gamma_pos + triangle_pos[::-1], closed=True,
facecolor='#fff3e0', edgecolor='none',
alpha=0.55, zorder=0)
ax.add_patch(inner_poly)
# Draw shared cycle gamma (on top of everything)
for i in range(6): for i in range(6):
x1, y1 = gamma_pos[i] x1, y1 = gamma_pos[i]
x2, y2 = gamma_pos[(i + 1) % 6] x2, y2 = gamma_pos[(i + 1) % 6]
ax.plot([x1, x2], [y1, y2], color='#333', linewidth=3.0, zorder=3) mx, my = (x1 + x2) / 2, (y1 + y2) / 2
r_m = math.hypot(mx, my)
ux, uy = mx / r_m, my / r_m
T2_outer_pts.append((R_T2_outer * ux, R_T2_outer * uy))
T2_inner_pts = []
for i in range(3):
angle = math.pi / 2 + 2 * math.pi * i / 3
T2_inner_pts.append((R_T2_inner * math.cos(angle),
R_T2_inner * math.sin(angle)))
# T_2's 9-cycle: 2 γ-spokes, 1 k_2-spoke, ... let's just draw the cycle
# cleanly without committing to an exact interleaving.
T2_cycle = []
for i in range(6):
T2_cycle.append(T2_outer_pts[i])
if i % 2 == 1:
T2_cycle.append(T2_inner_pts[i // 2])
for i in range(9):
x1, y1 = T2_cycle[i]
x2, y2 = T2_cycle[(i + 1) % 9]
ax.plot([x1, x2], [y1, y2], color='#ffb74d', linewidth=1.0,
linestyle=':', zorder=1)
for (x, y) in T2_outer_pts:
ax.plot(x, y, 'o', color='#f57c00', markersize=7, zorder=3)
for (x, y) in T2_inner_pts:
ax.plot(x, y, 'o', color='#ffb74d', markersize=5, zorder=3)
# Place vertices of gamma colored by one of the rainbow patterns: (1,2,3,2,3,1) # Now draw γ with edges colored by σ = (1, 2, 3, 2, 3, 1).
pattern = [1, 2, 3, 2, 3, 1] sigma = (1, 2, 3, 2, 3, 1)
for i in range(6):
x1, y1 = gamma_pos[i]
x2, y2 = gamma_pos[(i + 1) % 6]
ax.plot([x1, x2], [y1, y2], color=COLORS[sigma[i]], linewidth=5.0,
solid_capstyle='round', zorder=4)
mx, my = (x1 + x2) / 2, (y1 + y2) / 2
# Also draw the dual G'-edges crossing γ at midpoint -- short segments
# from T_2-side dual vertex to T_1-side dual vertex.
sx1, sy1 = T2_outer_pts[i]
sx2, sy2 = T1_inner_pts[i]
ax.plot([sx1, sx2], [sy1, sy2], color=COLORS[sigma[i]],
linewidth=2.5, linestyle=(0, (4, 2)), zorder=2)
# γ vertices
for i in range(6): for i in range(6):
x, y = gamma_pos[i] x, y = gamma_pos[i]
ax.plot(x, y, 'o', color=COLORS[pattern[i]], markersize=26, zorder=4, ax.plot(x, y, 'o', color='#222', markersize=10, zorder=5)
markeredgecolor='black', markeredgewidth=1.0) lx, ly = R_gamma * 1.12 * x / math.hypot(x, y), R_gamma * 1.12 * y / math.hypot(x, y)
ax.annotate(f"$v_{i}$", (x * 1.0, y * 1.0), color='white', ax.annotate(f"$v_{i}$", (lx + 0.05 * x, ly + 0.05 * y),
ha='center', va='center', fontsize=10, fontweight='bold', color='#222', ha='center', va='center', fontsize=9,
zorder=5) fontweight='bold', zorder=6)
# Triangle vertices # Labels with arrows
for i, (x, y) in enumerate(triangle_pos): ax.annotate(r'$T_1$ annular cycle, length $|γ|+m_1 = 12$' + '\n'
ax.plot(x, y, 'o', color='#666', markersize=14, zorder=4, + r'γ-side dual vertices (dark): 6' + '\n'
markeredgecolor='black', markeredgewidth=0.6) + r'$m_1$-side dual vertices (light): 6',
xy=(R_T1_inner * 1.0, 0.0), xytext=(4.0, 1.0),
# Annotate which regions are T_1 and T_2 (placed off to the side with arrows) fontsize=9, color='#37474f',
ax.annotate(r'$T_1$ annulus' + '\n'
+ r'$m_1 = 6$,' + '\n'
+ r'chord $(v_0, v_3) \in O_1$' + '\n'
+ r'Steiner-poor',
xy=(R_out - 0.1, -0.5), xytext=(3.7, -1.4),
fontsize=10, color='#1565c0',
ha='left', va='center', ha='left', va='center',
arrowprops=dict(arrowstyle='->', color='#1565c0', lw=1.0)) arrowprops=dict(arrowstyle='->', color='#37474f', lw=0.8))
ax.annotate(r'$T_2$ annulus' + '\n' ax.annotate(r'$T_2$ annular cycle, length $|γ|+k_2 = 9$' + '\n'
+ r'$k_2 = 3$, no chord' + '\n' + r'γ-side dual vertices (orange): 6' + '\n'
+ r'Steiner-rich', + r'$k_2$-side dual vertices (light): 3',
xy=(R_in + 0.2, 0.0), xytext=(3.7, 0.8), xy=(R_T2_outer * 0.7, -0.7), xytext=(4.0, -1.0),
fontsize=10, color='#e65100', fontsize=9, color='#e65100',
ha='left', va='center', ha='left', va='center',
arrowprops=dict(arrowstyle='->', color='#e65100', lw=1.0)) arrowprops=dict(arrowstyle='->', color='#e65100', lw=0.8))
ax.annotate(r'shared cycle $\gamma$' + '\n' + r'(length $k = 6$)', ax.annotate(r'antipodal chord' + '\n' + r'$(v_0, v_3) \in O_1$',
xy=(R_gamma * 0.9, R_gamma * 0.4), xytext=(3.7, 2.1), xy=(0, R_T1_outer * 1.0 - 0.1), xytext=(-4.6, 2.4),
fontsize=9, color='#9c27b0',
ha='left', va='center',
arrowprops=dict(arrowstyle='->', color='#9c27b0', lw=0.8))
ax.annotate(r'shared cycle $\gamma$' + '\n'
+ r'$|γ|=6$, drawn with' + '\n'
+ r'$\sigma=(1,2,3,2,3,1)$',
xy=(R_gamma * 0.7, 0.7), xytext=(-5.2, 0.0),
fontsize=10, color='#222', fontsize=10, color='#222',
ha='left', va='center', ha='left', va='center',
arrowprops=dict(arrowstyle='->', color='#222', lw=1.0)) arrowprops=dict(arrowstyle='->', color='#222', lw=0.8))
ax.annotate(r'antipodal chord' + '\n' + r'$(v_0, v_3)$ in $O_1$', ax.annotate(r'$\sigma$ is the coloring of the 6 dual' + '\n'
xy=(-0.55, 1.7), xytext=(-3.2, 2.4), + r'$G\,\!\!\!\!^{\,\prime}$-edges crossing $γ$' + '\n'
fontsize=10, color='#9c27b0', + r'(dashed, same colors as $γ$-edges)',
xy=(R_gamma * 1.05, -R_gamma * 0.05), xytext=(-5.2, -1.4),
fontsize=9, color='#333',
ha='left', va='center', ha='left', va='center',
arrowprops=dict(arrowstyle='->', color='#9c27b0', lw=1.0)) arrowprops=dict(arrowstyle='->', color='#333', lw=0.8))
ax.set_xlim(-3.6, 5.4) ax.set_xlim(-5.5, 7.5)
ax.set_ylim(-2.8, 3.2) ax.set_ylim(-3.8, 3.8)
ax.set_aspect('equal') ax.set_aspect('equal')
ax.axis('off') ax.axis('off')
ax.set_title(r"Geometric setup behind the rainbow orbit: $T_1$ outside $\gamma$," ax.set_title(r"Geometric setup: $\sigma = (1,2,3,2,3,1)$ is one of the "
+ r" $T_2$ inside $\gamma$" + "\n" + r"6 orbit elements. " + "\n"
+ r"shown with the spoke configuration $\sigma = (1,2,3,2,3,1)$" + r"It colors the 6 $G'$-edges that cross $\gamma$. "
+ r" from the orbit", + r"Each tire's full annular cycle is longer than 6, with "
+ r"interleaved non-$\gamma$ spokes.",
fontsize=11) fontsize=11)
out = os.path.join(outdir, 'fig_rainbow_setup.png') out = os.path.join(outdir, 'fig_rainbow_setup.png')
Binary file not shown.

Before

Width:  |  Height:  |  Size: 88 KiB

After

Width:  |  Height:  |  Size: 109 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 110 KiB

After

Width:  |  Height:  |  Size: 142 KiB