b3998fbdb3
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>
115 lines
4.3 KiB
Python
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()
|