用Python可视化平面图:3分钟动态验证欧拉公式
第一次接触欧拉公式时,盯着那个简洁的n-m+r=2看了半天——公式里的字母我都认识,可它们组合起来就像天书。直到某天用Python画出了K5和K3,3的平面嵌入图,突然发现那些抽象的数学符号在屏幕上活了过来。这就像用X光机给数学定理做了次透视,公式背后的几何结构变得一目了然。
1. 平面图的可视化准备
安装好networkx和matplotlib后,我们先从最简单的环形图开始热身。在Jupyter Notebook里运行以下代码,你会看到六个节点均匀分布在圆周上,像钟表刻度般整齐排列:
import networkx as nx import matplotlib.pyplot as plt G = nx.cycle_graph(6) pos = nx.circular_layout(G) # 环形布局 nx.draw(G, pos, with_labels=True, node_color='lightblue') plt.show()平面图(Planar Graph)的核心特征是边可以在平面上绘制且互不交叉。但有些图天生就拒绝这种优雅——比如著名的K5(五个节点两两相连)和K3,3(二分图各三个节点全连接)。试试用下面的代码生成K5:
K5 = nx.complete_graph(5) pos = nx.spring_layout(K5, seed=42) # 随机布局 nx.draw(K5, pos, with_labels=True, node_color='salmon') plt.show()你会看到边像纠结的意大利面般缠绕在一起。这就是典型的非平面图特征,也是图论中著名的库拉托夫斯基定理的直观体现。
2. 欧拉公式的动态验证
欧拉公式的魔法在于它将拓扑不变量联系起来。让我们用Python构建一个立方体图来验证:
cube = nx.grid_graph([2,2,2]) # 3D立方体图 pos = nx.spring_layout(cube) nx.draw(cube, pos, with_labels=True) # 计算要素 n = len(cube.nodes) # 节点数=8 m = len(cube.edges) # 边数=12 r = 6 # 通过可视化可数出面数(6个正方形面) print(f"n - m + r = {n} - {m} + {r} = {n - m + r}") # 输出8-12+6=2更酷的是实时修改图形观察公式变化。删除一条对角线边,面数会如何变化?
cube.remove_edge((0,0,0), (1,1,1)) # 删除空间对角线 r = 5 # 现在外部大面+4个侧面 print(f"修改后: 8 - 11 + 5 = {8 - 11 + 5}") # 依然等于23. 极大平面图的特征识别
极大平面图就像充满三角形的网格气球。判断标准很简单:每个面都是三角形(度数为3)。用代码检测四面体图:
tetrahedron = nx.complete_graph(4) pos = nx.planar_layout(tetrahedron) nx.draw(tetrahedron, pos, with_labels=True) # 面度数检测 def is_maximal_planar(G): return all(len(face) == 3 for face in nx.planar_faces(G)) print(f"是否极大平面图: {is_maximal_planar(tetrahedron)}") # 返回True对比K5删边后的情况:
K5_minus_edge = nx.complete_graph(5) K5_minus_edge.remove_edge(0,1) # 删除任意一条边 print(f"K5删边后是否极大平面: {is_maximal_planar(K5_minus_edge)}") # 仍然False4. 平面性判定实战技巧
虽然库拉托夫斯基定理给出了理论依据,但实际判断时可以用以下经验法则:
- 边数阈值:对于n≥3的简单连通图,若m > 3n-6则必定非平面
- 二分图特例:对于不含3-cycles的图,若m > 2n-4则非平面
用Python快速验证K3,3:
K33 = nx.complete_bipartite_graph(3,3) n, m = len(K33.nodes), len(K33.edges) print(f"3n-6={3*6-6}, 实际边数{m}") # 12>9 print(f"2n-4={2*6-4}, 实际边数{m}") # 9>8可视化时有个小技巧——使用planar_layout尝试平面排布:
try: pos = nx.planar_layout(K33) # 会抛出NetworkXException except nx.NetworkXException: print("无法生成平面布局,证实是非平面图")5. 高级可视化技巧
要让面边界更清晰,可以使用面填充技术。以下代码展示如何突出显示平面图的外部面:
from matplotlib.patches import Polygon G = nx.octahedral_graph() # 八面体图 pos = nx.planar_layout(G) nx.draw(G, pos, with_labels=True) # 获取外部面顶点坐标 outer_face = [pos[v] for v in [0,1,2,3,0]] plt.gca().add_patch(Polygon(outer_face, alpha=0.2, color='gold')) plt.show()对于更复杂的图形,可以结合graphviz的twopi布局获得更好的展示效果:
pos = nx.nx_agraph.graphviz_layout(G, prog='twopi', args='-Goverlap=scale') nx.draw(G, pos, node_size=500, alpha=0.8)记得在代码中适时添加plt.savefig('planar_demo.png', dpi=300)保存高质量图像,方便后续研究或报告使用。