codexgraph-minor-connected-branch-set-adjacency.py
graph-minor-connected-branch-set-adjacency.py
"""Draw connected branch sets, their quotient triangle, and a path minor.
Python 3.14, matplotlib 3.10.7. Run from _media; output goes to CWD.
"""
from pathlib import Path
import matplotlib.pyplot as plt
from matplotlib.patches import Circle, Ellipse
COLORS = {"A": "#2268a8", "B": "#b85b13", "C": "#258354"}
PALE = {"A": "#e5effa", "B": "#fff0da", "C": "#e6f5e9"}
def node(ax, label, position, group):
ax.add_patch(Circle(position, 0.17, facecolor="white", edgecolor=COLORS[group],
linewidth=2, zorder=4))
ax.text(*position, label, ha="center", va="center", fontsize=14,
color=COLORS[group], weight="bold", zorder=5)
def main():
plt.rcParams.update({"font.family": "DejaVu Sans", "font.size": 12})
fig = plt.figure(figsize=(10, 4.75), dpi=120, facecolor="white")
host = fig.add_axes((0.025, 0.22, 0.37, 0.58))
quotient = fig.add_axes((0.46, 0.22, 0.22, 0.58))
path = fig.add_axes((0.765, 0.22, 0.22, 0.58))
pos = {"1": (-1.0, 0.8), "2": (-1.0, -0.5),
"3": (0.0, -1.1), "4": (1.0, -0.5),
"5": (1.0, 0.8), "6": (0.0, 1.4)}
groups = {"1": "A", "2": "A", "3": "B", "4": "B", "5": "C", "6": "C"}
for a, b in [("1", "2"), ("3", "4"), ("5", "6")]:
group = groups[a]
p, q = pos[a], pos[b]
centre = ((p[0] + q[0]) / 2, (p[1] + q[1]) / 2)
angle = {"A": 90, "B": 31, "C": -31}[group]
length = 1.8 if group == "A" else 1.65
host.add_patch(Ellipse(centre, length, 0.65, angle=angle,
facecolor=PALE[group], edgecolor=COLORS[group],
linewidth=1.2, zorder=0))
host.plot(*zip(p, q), color=COLORS[group], linewidth=3, zorder=1)
for a, b, label, text_pos in [
("2", "3", "AB: 23", (-0.95, -1.17)),
("4", "5", "BC: 45", (1.14, 0.12)),
("6", "1", "CA: 61", (-0.8, 1.57)),
]:
host.plot(*zip(pos[a], pos[b]), color="#34495e", linewidth=2, zorder=1)
host.text(*text_pos, label, fontsize=11, color="#34495e",
ha="left" if label.startswith("BC") else "center")
host.plot(*zip(pos["2"], pos["4"]), color="#68737e", linewidth=1.8,
linestyle="--", zorder=2)
host.text(0, -0.36, "extra AB: 24", ha="center", fontsize=11, color="#68737e")
for label, position in pos.items():
node(host, label, position, groups[label])
target = {"A": (-0.9, 0.9), "B": (0.9, 0.9), "C": (0, -0.9)}
for ax, edges in [(quotient, [("A", "B"), ("B", "C"), ("C", "A")]),
(path, [("A", "B"), ("B", "C")])]:
for a, b in edges:
ax.plot(*zip(target[a], target[b]), color="#34495e", linewidth=2.2)
for label, position in target.items():
node(ax, label, position, label)
for ax in (host, quotient, path):
ax.set(xlim=(-1.65, 1.75), ylim=(-1.5, 1.85), aspect="equal")
ax.axis("off")
fig.suptitle("Branch sets retain selected adjacencies", fontsize=16, weight="bold", y=0.97)
fig.text(0.21, 0.84, "Host: 6 vertices, 7 edges", ha="center", weight="bold")
fig.text(0.57, 0.84, "Triangle minor", ha="center", weight="bold")
fig.text(0.875, 0.84, "Path minor", ha="center", weight="bold")
overlay = fig.add_axes((0, 0, 1, 1), frameon=False)
overlay.set(xlim=(0, 1), ylim=(0, 1))
overlay.axis("off")
for start, end in [(0.397, 0.455), (0.685, 0.758)]:
overlay.annotate("", xy=(end, 0.53), xytext=(start, 0.53),
arrowprops={"arrowstyle": "->", "lw": 1.6})
fig.text(0.427, 0.34, "contract\n12, 34, 56", ha="center", fontsize=10)
fig.text(0.721, 0.34, "delete\nAC", ha="center", fontsize=10)
for x, group, members in [(0.16, "A", "{1, 2}"), (0.5, "B", "{3, 4}"),
(0.83, "C", "{5, 6}")]:
fig.text(x, 0.145, f"{group} = {members}", color=COLORS[group],
weight="bold", ha="center", fontsize=13)
fig.text(0.5, 0.055, "Coloured internal edges establish connectedness; black edges witness target adjacency.",
ha="center", fontsize=11)
fig.savefig(Path.cwd() / (Path(__file__).stem + ".png"), facecolor="white",
transparent=False)
plt.close(fig)
if __name__ == "__main__":
main()