Manim 图与网络:Graph 类画树、网络图与布局算法切换动画
Manim CE's Graph class turns vertex/edge lists into laid-out network diagrams with one call, and animates between layouts. This guide covers the built-in layouts — spring (force-directed, seedable for reproducibility), circular, kamada_kawai, planar, partite (for bipartite graphs), random, and tree with root_vertex — plus per-vertex and per-edge styling through vertex_config/edge_config, label control, degree-based sizing, highlighting vertices and edges mid-animation, and the change_layout() animation that morphs an entire network from one arrangement to another. Also: adding/removing vertices and edges dynamically, curving multiple edges between the same pair, and self-loops. A complete runnable example builds a small social network, walks a BFS frontier with lagged highlights, then re-lays the graph as a tree.
一个调用出一张图
from manim import *
class GraphTour(Scene):
def construct(self):
g = Graph(
[1, 2, 3, 4, 5, 6],
[(1, 2), (2, 3), (3, 4), (4, 5), (5, 1), (2, 6), (3, 6)],
layout="spring", layout_config={"seed": 2},
labels=True,
vertex_config={"radius": 0.28, "color": BLUE,
"fill_opacity": 1},
edge_config={"stroke_width": 2.5},
)
self.play(Create(g), run_time=2)
self.wait()
顶点列表 + 边列表,Graph 自动完成布局计算、顶点圆点绘制、边连线裁剪。这是 0.15+ 的正式 API,比早期手画 Line + Dot 省一半代码。
内置布局算法
| layout | 效果 | 常用参数 |
|---|---|---|
| spring | 力导向(networkx 风格) | seed 固定随机结果 |
| kamada_kawai | 更均匀的力导向 | — |
| circular | 顶点排成一圈 | — |
| planar | 无边交叉的平面布局 | — |
| partite | 分层排列(二部图) | partitions |
| tree | 层次树 | root_vertex |
| random | 随机散点 | seed |
布局切换:最好看的图动画
self.play(g.animate.change_layout("circular"), run_time=2)
self.play(g.animate.change_layout(
"tree", layout_config={"root_vertex": 1}), run_time=2)
同一张图在"力导向 → 环形 → 树"之间平滑变形,是讲图论算法(同一结构、不同视角)的利器。
顶点/边的个性化配置
g = Graph(
[1, 2, 3, 4],
[(1, 2), (2, 3), (3, 4), (1, 3)],
vertex_config={
1: {"color": RED}, # 指定顶点单独配色
"default": {"color": BLUE}, # 其余默认
},
edge_config={
(1, 3): {"color": YELLOW, "stroke_width": 4},
},
)
按度数缩放顶点(社交网络风格):
degrees = {v: 0 for v in vertices}
for a, b in edges:
degrees[a] += 1; degrees[b] += 1
g = Graph(vertices, edges,
vertex_config={v: {"radius": 0.2 + 0.08 * degrees[v]}
for v in vertices})
动画中高亮:遍历的可视化
# 高亮单点 / 单边
self.play(g.vertices[2].animate.scale(1.6).set_color(YELLOW))
self.play(g.edges[(1, 2)].animate.set_stroke(YELLOW, width=5))
# BFS 逐层扩散: LaggedStart 按发现顺序点亮
order = [1, 2, 3, 6, 4, 5] # 你的遍历顺序
self.play(LaggedStart(
*[g.vertices[v].animate.set_color(TEAL) for v in order],
lag_ratio=0.4))
0.18+ 还有一步到位的 g.animate.highlight_vertices([...]) / highlight_edges(用 create_highlighted 风格),旧版本用上面的手动写法即可。
动态增删点边
self.play(g.animate.add_vertices(7))
self.play(g.animate.add_edges((6, 7)))
self.play(g.animate.remove_edges((1, 2)))
多重边与自环:边写成 ((1, 2),)(元组套元组)允许两点间多条边;自环直接 (1, 1)。新版本会自动弯曲避免重叠。
与 networkx 联动
Graph 的 layout 参数背后就是 networkx:复杂布局可以自己算好坐标再喂给 manim:
import networkx as nx
nxg = nx.karate_club_graph()
g = Graph.from_networkx(nxg, layout="spring",
layout_config={"seed": 1})