Files
math-research/papers/even_level_graph_generators/experiments/draw_witnesses.py
T
didericis b3998fbdb3 Redraw n=21 witness figures as crossing-free planar graphs
Replace the radial (crossing-heavy) figure with two crossing-free planar
drawings (networkx planar_layout / Chrobak-Payne):
  fig:n21-elgs  -- the six witness Even Level Graphs, parity-coloured, with
                   the bridge-switch-flipped edges dashed red;
  fig:n21-duals -- the six resulting duals, with the introduced bridge edges
                   solid green.
ELG and dual are drawn with independent planar layouts so neither has any
edge crossing (a flip diagonal would otherwise cross other edges when its
quadrilateral is non-convex, which happens for duals 0 and 3). Drop forced
equal aspect so panels fill and labels separate.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-22 11:23:36 -04:00

115 lines
4.3 KiB
Python

"""Draw the six Holton-McKay duals and their witness Even Level Graphs as
crossing-free planar drawings (networkx planar_layout, Chrobak-Payne).
Two figures:
n21_elgs.png -- the six witness Even Level Graphs, parity-coloured,
with the edges flipped by the bridge switches dashed red;
n21_duals.png -- the six resulting duals, parity-coloured (same fixed
parity labelling), with the introduced bridge edges green.
Reads experiments/witnesses/dual_*.json. ELG and dual are drawn with
independent planar layouts so neither has any edge crossing.
"""
import sys
import os
import json
sys.path.insert(0, '/Users/didericis/Code/math-research/papers/'
'level_resolutions_of_maximal_planar_graphs/experiments')
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
import networkx as nx
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
from matplotlib.lines import Line2D
HERE = os.path.dirname(os.path.abspath(__file__))
WDIR = os.path.join(HERE, 'witnesses')
FDIR = os.path.join(HERE, '..', 'figures')
EVEN_C = '#9ecae1' # even-parity vertices
ODD_C = '#fdae6b' # odd-parity vertices
def load(i):
return json.load(open(os.path.join(WDIR, f'dual_{i}.json')))
def graph_of(edges, labels):
G = nx.Graph()
G.add_nodes_from(int(v) for v in labels)
G.add_edges_from((a, b) for a, b in edges)
return G
def draw(ax, G, labels, highlight, hcolor, hstyle, title):
pos = nx.planar_layout(G)
colors = [EVEN_C if labels[str(v)] == 0 else ODD_C for v in G.nodes()]
hl = {frozenset(e) for e in highlight}
plain = [e for e in G.edges() if frozenset(e) not in hl]
nx.draw_networkx_edges(G, pos, edgelist=plain, ax=ax,
edge_color='#b0b0b0', width=0.8)
if hl:
nx.draw_networkx_edges(G, pos, edgelist=[tuple(e) for e in hl], ax=ax,
edge_color=hcolor, width=2.4, style=hstyle)
nx.draw_networkx_nodes(G, pos, node_color=colors, node_size=200,
edgecolors='#444444', linewidths=0.6, ax=ax)
nx.draw_networkx_labels(G, pos, font_size=8, ax=ax)
ax.set_title(title, fontsize=10)
ax.margins(0.12)
ax.axis('off')
def legend(fig, kind):
handles = [
Line2D([0], [0], marker='o', color='w', markerfacecolor=EVEN_C,
markeredgecolor='#444', markersize=9, label='even parity'),
Line2D([0], [0], marker='o', color='w', markerfacecolor=ODD_C,
markeredgecolor='#444', markersize=9, label='odd parity'),
]
if kind == 'elg':
handles.append(Line2D([0], [0], color='#d62728', lw=2.4, ls='dashed',
label='edge flipped by a bridge switch'))
else:
handles.append(Line2D([0], [0], color='#2ca02c', lw=2.4,
label='bridge edge introduced'))
fig.legend(handles=handles, loc='lower center', ncol=3, fontsize=9,
frameon=False)
def main():
os.makedirs(FDIR, exist_ok=True)
# Figure 1: the six witness Even Level Graphs (flipped edges red dashed)
fig, axes = plt.subplots(2, 3, figsize=(19, 12))
for i, ax in zip(range(6), axes.flat):
d = load(i)
G = graph_of(d['elg_edges'], d['labels'])
removed = [s['remove'] for s in d['bridge_switches']]
k = d['num_bridge_switches']
sub = (f"{k} bridge switch" + ("es" if k != 1 else "")
if k else "Even Level Graph outright")
draw(ax, G, d['labels'], removed, '#d62728', 'dashed',
f"dual {i}: ELG (source {d['elg_source']})\n{sub}")
legend(fig, 'elg')
fig.tight_layout(rect=(0, 0.04, 1, 1))
p1 = os.path.join(FDIR, 'n21_elgs.png')
fig.savefig(p1, dpi=160)
plt.close(fig)
print(f'wrote {p1}')
# Figure 2: the six resulting duals (introduced bridge edges green)
fig, axes = plt.subplots(2, 3, figsize=(19, 12))
for i, ax in zip(range(6), axes.flat):
d = load(i)
G = graph_of(d['dual_edges'], d['labels'])
added = [s['add'] for s in d['bridge_switches']]
draw(ax, G, d['labels'], added, '#2ca02c', 'solid', f"dual {i}")
legend(fig, 'dual')
fig.tight_layout(rect=(0, 0.04, 1, 1))
p2 = os.path.join(FDIR, 'n21_duals.png')
fig.savefig(p2, dpi=160)
plt.close(fig)
print(f'wrote {p2}')
if __name__ == '__main__':
main()