完整代码:
from manim import * class LargeTreeGeneration01(MovingCameraScene): DEPTH = 3 CHILDREN_PER_VERTEX = 2 LAYOUT_CONFIG = {"vertex_spacing": (0.8, 1)} VERTEX_CONF = {"radius": 0.12, "color": BLUE_B, "fill_opacity": 1} def expand_vertex(self, g, vertex_id: str, depth: int): new_vertices = [f"{vertex_id}/{i}" for i in range(self.CHILDREN_PER_VERTEX)] new_edges = [(vertex_id, child_id) for child_id in new_vertices] g.add_edges( *new_edges, vertex_config=self.VERTEX_CONF, positions={ k: g.vertices[vertex_id].get_center() + 0.1 * DOWN for k in new_vertices }, ) if depth < self.DEPTH: for child_id in new_vertices: self.expand_vertex(g, child_id, depth + 1) return g def construct(self): # 创建一个空的图,只有一个根节点 g = Graph(["ROOT"], [], vertex_config=self.VERTEX_CONF) # 扩展树结构 g = self.expand_vertex(g, "ROOT", 1) self.add(g) # 改变布局,并添加动画 self.play( g.animate.change_layout( "tree", root_vertex="ROOT", layout_config=self.LAYOUT_CONFIG, ) ) # 自动缩放相机以适应图形 self.play(self.camera.auto_zoom(g, margin=1), run_time=0.5)
运行结果:https://download.csdn.net/download/qq_45449625/89591393https://download.csdn.net/download/qq_45449625/89591393
接下来解释一下代码吧:
1. 导入所需库
from manim import *
这一行导入了 Manim 库的所有内容。Manim 是一个用于制作数学动画的 Python 库。
2. 创建类
class LargeTreeGeneration(MovingCameraScene):
这个类 LargeTreeGeneration
继承自 MovingCameraScene
。MovingCameraScene
提供了相应的方法来控制相机的移动和缩放,适合用于制作动态场景。
3. 定义类属性
DEPTH = 4 CHILDREN_PER_VERTEX = 3 LAYOUT_CONFIG = {"vertex_spacing": (0.5, 1)} VERTEX_CONF = {"radius": 0.12, "color": BLUE_B, "fill_opacity": 1}
DEPTH
:指树的深度(最深的层级)。CHILDREN_PER_VERTEX
:每个节点的子节点数量。LAYOUT_CONFIG
:布局配置,控制节点间的垂直和水平间距。VERTEX_CONF
:节点的属性配置,包括半径、颜色和填充透明度。
4. 扩展树的节点
def expand_vertex(self, g, vertex_id: str, depth: int):
这个方法用于递归地生成树的节点和连接。
g
:当前的图形对象。vertex_id
:当前节点的 ID。depth
:当前的深度,始于1。
方法内的逻辑:
new_vertices = [f"{vertex_id}/{i}" for i in range(self.CHILDREN_PER_VERTEX)]
根据当前节点 ID 生成子节点的 ID。
new_edges = [(vertex_id, child_id) for child_id in new_vertices]
创建从当前节点到所有子节点的边。
g.add_edges( *new_edges, vertex_config=self.VERTEX_CONF, positions={ k: g.vertices[vertex_id].get_center() + 0.1 * DOWN for k in new_vertices }, )
将这些边添加到图形对象中,同时为新节点设置位置和配置。
if depth < self.DEPTH: for child_id in new_vertices: self.expand_vertex(g, child_id, depth + 1)
如果当前深度小于指定的深度,则递归调用自己,为每个新子节点继续生成其子节点。
5. 构建场景
def construct(self):
这是 Manim 中用来生成场景的主要方法。
g = Graph(["ROOT"], [], vertex_config=self.VERTEX_CONF)
创建一个图形,从一个根节点("ROOT")开始,且没有初始边。
g = self.expand_vertex(g, "ROOT", 1)
调用 expand_vertex
方法,扩展整个图形。
self.add(g)
将图形添加到当前场景中。
6. 动画效果
self.play( g.animate.change_layout( "tree", root_vertex="ROOT", layout_config=self.LAYOUT_CONFIG, ) )
使用 g.animate.change_layout
方法将图形转换为树形布局,并在动画中展示。
self.play(self.camera.auto_zoom(g, margin=1), run_time=0.5)
将相机自动缩放,以适应整个图形,并在0.5秒内完成该动作。
7. 运行代码
最后一行
%manim -qm -v WARNING LargeTreeGeneration
是用来在 Jupyter Notebook 中运行这个场景的命令,它会编译并展示动画。
总结
整体来看,这段代码使用了递归方法生成功能强大的树形结构,同时通过相机动画使得最终的展示更加生动。设计上颇具灵活性,可通过调整 DEPTH
和 CHILDREN_PER_VERTEX
属性轻松实现不同规模的树。