记录Manim渲染的显式函数示例

Manim库中,FunctionGraph类是一个核心组件,专门用于在坐标系中绘制函数图像。FunctionGraph的主要作用是将数学函数以直观的图形形式展示出来,使得复杂的数学概念更加容易理解。它广泛应用于数学教学、科学演示以及数据可视化等领域。下面是Manim 中的 FunctionGraph 详解

一、概念与适用场景

  1. FunctionGraph 用于在 Manim 中绘制显式函数 y = f(x) 的二维曲线,要求函数在给定区间内是单值的(每个 x 对应唯一 y)。
  2. 典型用途:数学教学(展示奇偶性、周期性、渐近线)、物理仿真(位移/速度-时间图)、工程应用(信号波形、控制响应)、算法演示(目标函数、损失函数)。
  3. 当函数可显式写成 y = f(x) 时优先使用;若方程以 F(x, y) = 0 给出,用 ImplicitFunction;若以参数 r(t) = (x(t), y(t)) 给出,用 **ParametricFunction。

二、常用参数与方法

  1. 主要参数
    1. function:可调用对象,形如 Callable[[float], float],如 lambda x: x+5
    2. x_range:定义域,支持 [xmin, xmax][xmin, xmax, step]
    3. color:曲线颜色,如 BLUE
    4. discontinuities:不连续点列表,如 [0] 用于处理跳跃间断。
    5. use_smoothing:是否平滑连接采样点,默认 True
    6. dt:采样步长(影响平滑度)。
    7. t_range:高级用法,用于参数化控制。
  2. 常用方法
    1. get_function():返回用于绘制的函数对象。
    2. get_point_from_function(x):给定 x 返回曲线上对应点坐标。
  3. 坐标系便捷方式
    • Axes 上可用 axes.get_graph(func, kwargs)直接生成曲线,并用 axes.get_graph_label(graph, label) 添加标签。

三、快速上手示例

示例 1:

绘制 y = sin(x) 与 y = cos(x)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
from manim import *
import numpy as np

class SinCosGraph(Scene):
def construct(self):
# 创建坐标轴
axes = Axes(
x_range=[-3*np.pi, 3*np.pi, np.pi/2],
y_range=[-1.5, 1.5, 0.5],
axis_config={"color": GREY_A},
x_length=10,
y_length=6,
)

# 添加坐标轴标签
axes_labels = axes.get_axis_labels(
x_label="x",
y_label="y"
)

# 创建函数图像
sin_func = FunctionGraph(
lambda t: np.sin(t),
x_range=[-2*np.pi, 2*np.pi], # 必须指定x范围
color=BLUE,
)
cos_func = FunctionGraph(
lambda t: np.cos(t),
x_range=[-2*np.pi, 2*np.pi], # 必须指定x范围
color=RED,
)

# 添加图例
sin_label = Text("sin(x)", color=BLUE).next_to(sin_func, UP, buff=0.1)
cos_label = Text("cos(x)", color=RED).next_to(cos_func, DOWN, buff=0.1)

# 播放动画
self.play(Create(axes), Write(axes_labels))
self.play(Create(sin_func), Write(sin_label))
self.play(Create(cos_func), Write(cos_label))
self.wait()

示例 2:

分段与间断(ReLU 与单位阶跃)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
from manim import *

class StepReluGraph(Scene):
def construct(self):
# 创建坐标系
axes = Axes(
x_range=(-1, 5, 1),
y_range=(-0.5, 3, 0.5),
axis_config={"color": BLUE}
)

# 创建 ReLU 函数
relu = axes.plot(
lambda x: max(x, 0),
x_range=[-1, 5],
color=YELLOW,
use_smoothing=False
)

# 创建阶跃函数 - 手动分段绘制
# 第一部分:x < 3 时 y = 1
step_part1 = axes.plot(
lambda x: 1.0,
x_range=[-1, 3],
color=GREEN,
use_smoothing=False
)

# 第二部分:x > 3 时 y = 2
step_part2 = axes.plot(
lambda x: 2.0,
x_range=[3, 5],
color=GREEN,
use_smoothing=False
)

# 在 x=3 处添加垂直线段(可选,表示跳跃)
vertical_line = Line(
axes.c2p(3, 1),
axes.c2p(3, 2),
color=GREEN
)

# 添加标签
relu_label = axes.get_graph_label(relu, label="ReLU(x) = max(0, x)")
step_label = Text("阶跃函数", color=GREEN, font_size=24).next_to(step_part2, UP)

# 动画序列
self.play(Create(axes))
self.play(Create(relu))
self.play(Write(relu_label))
self.wait(0.5)

self.play(Create(step_part1))
self.play(Create(step_part2))
self.play(Create(vertical_line))
self.play(Write(step_label))
self.wait(2)

示例 3:

直接使用 FunctionGraph(不依赖 Axes)

1
2
3
4
5
6
7
8
9
from manim import *
import numpy as np

class DirectFunctionGraph(Scene):
def construct(self):
graph = FunctionGraph(lambda x: x**2, x_range=[-2, 2], color=BLUE)
self.play(Create(graph))
self.wait()

示例 4:

动态更新函数形态(Transform 驱动)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from manim import *
import numpy as np

class DynamicGraph(Scene):
def construct(self):
def f(x, t):
return np.sin(x + t)
g = FunctionGraph(lambda x: f(x, 0), color=TEAL)
self.play(Create(g))
self.wait(2)
for t in np.linspace(0, 2*np.pi, 30):
self.play(Transform(g, FunctionGraph(lambda x: f(x, t), color=TEAL)), run_time=0.1)
self.wait()

示例 5:

获取曲线上某点坐标

1
2
3
4
5
6
7
8
9
10
11
from manim import *
import numpy as np

class PointOnGraph(Scene):
def construct(self):
g = FunctionGraph(lambda x: x**2, x_range=[-2, 2], color=BLUE)
p = g.get_point_from_function(1.0) # (x, x^2) 在 x=1 处的点
dot = Dot(point=p, color=RED)
self.play(Create(g),Create(dot))
self.wait()

实例6:

sin函数图像的平移和缩小

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from manim import *
import numpy as np

class FunctionGraphExampleattr(Scene):

def construct(self):
"""函数的平移和缩放"""

# 绘制原始函数图像
func = FunctionGraph(
lambda t: np.sin(t),
color=BLUE,
x_range=[-2*np.pi, 2*np.pi], # 必须指定x范围
)

self.play(Create(func))
self.wait()
self.play(func.animate.move_to(UP))
self.wait()
self.play(func.animate.scale(0.5))
self.wait()

示例7:

创建复合函数的图像并缩小

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from manim import *
import numpy as np

class FunctionGraphComposite(Scene):

def construct(self):

# 绘制复合函数图像
composite_func = FunctionGraph(
lambda t: np.sin(t) + 0.5 * np.sin(7 * t) + (1 / 7) * np.sin(14 * t),
color=ORANGE,
)
self.play(Create(composite_func))
self.wait()
self.play(composite_func.animate.scale(0.5))
self.wait()

示例8:

创建一个动态变化的函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from manim import *
import numpy as np

class FunctionGraphdynamic(Scene):
def construct(self):
# 定义一个动态变化的函数
def dynamic_func(t, time):
return np.sin(t + time)

# 创建一个动态函数图像
dynamic_graph = FunctionGraph(
lambda t: dynamic_func(t, 0),
color=TEAL,
)
self.add(dynamic_graph)
# 动态更新函数图像
for time in range(10):
new_graph = FunctionGraph(
lambda t: dynamic_func(t, time),
color=TEAL,
)
self.play(Transform(dynamic_graph, new_graph))
self.wait()

四、常见问题与实用建议

  1. 函数必须是显式且单值;多值情形(如圆)应使用 ImplicitFunction,参数曲线使用 ParametricFunction
  2. 出现“断点”或“毛刺”时,优先检查定义域与不连续点设置;对分段函数或含绝对值的函数,显式给出 discontinuities 更稳妥。
  3. 分段线性(如 ReLU)或需要保留棱角的曲线,设置 use_smoothing=False 以避免曲线被插值“圆滑化”。
  4. 需要获取曲线上某点坐标进行标注或交互时,使用 get_point_from_function(x);需要在动画中替换函数形态时,用 Transform 在两条 FunctionGraph 间平滑过渡