Manim 坐标系与函数图像:Axes、NumberPlane 完全指南
Everything about plotting in Manim CE: build a coordinate system with Axes (x_range, y_range, lengths, per-axis configs), draw curves with axes.plot(), decorate with add_coordinates() and get_graph_label, fill areas with get_area(), and visualize integration with get_riemann_rectangles(). NumberPlane gives the faded grid look of 3Blue1Brown videos. Parametric curves use plot_parametric_curve, polar graphs plot_polar_graph, and ImplicitFunction draws level sets like circles without solving for y. The key mental model: axes are Mobjects, and coords_to_point / point_to_coords convert between math space and screen space — every annotation (dots, dashed lines, labels) should be placed through this bridge. Includes a runnable tour scene with a sine curve, tangent dot, and Riemann rectangles.
核心心智模型:数学坐标 → 屏幕坐标
Manim 画面本身用"屏幕坐标”(中心是原点,左右各约 7 个单位、上下各约 4 个单位)。Axes 负责在屏幕上开一个窗口,把数学坐标映射进去。所有标注点都必须先过 axes.coords_to_point(x, y)(简写 axes.c2p)这座桥:
axes = Axes(x_range=[-3, 3, 1], y_range=[-2, 2, 1], x_length=9, y_length=5)
dot = Dot(axes.c2p(2, 1)) # 数学点 (2,1) 处画点, 而不是屏幕 (2,1)
一、创建坐标系并画第一条曲线
from manim import *
class PlotTour(Scene):
def construct(self):
axes = Axes(
x_range=[-4, 4, 1], y_range=[-2, 2, 1],
x_length=9, y_length=4.5,
x_axis_config={"include_numbers": True},
y_axis_config={"include_numbers": True},
axis_config={"color": GREY_B, "stroke_width": 2},
)
curve = axes.plot(lambda x: np.sin(x), x_range=[-4, 4], color=BLUE)
label = axes.get_graph_label(curve, "sin(x)", x_val=3, direction=UR)
self.play(Create(axes), run_time=2)
self.play(Create(curve), Write(label))
self.wait()
x_range=[起, 止, 步长]— 步长控制刻度密度x_axis_config / y_axis_config— 单独配置两根轴(0.18+ 语法,旧的axis_config已弃用)include_numbers— 轴上标数字;axes.add_coordinates()是等效的链式写法
二、面积与积分可视化
微积分教学是 Manim 的主场,两个 API 覆盖 90% 场景:
curve = axes.plot(lambda x: np.sin(x), x_range=[0, np.pi], color=BLUE)
# 1) 填充面积
area = axes.get_area(curve, x_range=[0, np.pi], color=TEAL, opacity=0.5)
# 2) 黎曼矩形逼近
rects = axes.get_riemann_rectangles(
curve, x_range=[0, np.pi], dx=0.4, input_sample_type="left",
color=[TEAL, BLUE_D], stroke_width=0.5)
self.play(Create(curve))
self.play(DrawBorderThenFill(area))
self.play(FadeOut(area))
self.play(Create(rects))
self.wait()
配合 ValueTracker 让 dx 动起来(矩形越来越细逼近曲边梯形),是复刻系列第一期的核心手法。
三、曲线上的动点与辅助线
t = ValueTracker(0)
dot = always_redraw(
lambda: Dot(axes.c2p(t.get_value(), np.sin(t.get_value())),
color=YELLOW))
vline = always_redraw(
lambda: DashedLine(
axes.c2p(t.get_value(), 0),
axes.c2p(t.get_value(), np.sin(t.get_value())),
stroke_opacity=0.6))
self.add(axes, curve, vline, dot)
self.play(t.animate.set_value(6), run_time=4, rate_func=linear)
always_redraw 每帧重建对象,是"跟随"效果的标准解,原理见Updater 与 ValueTracker。
四、NumberPlane:3b1b 风格的网格
plane = NumberPlane(
x_range=[-6, 6, 1], y_range=[-4, 4, 1],
background_line_style={"stroke_color": BLUE_D, "stroke_width": 1.5},
faded_line_ratio=3) # 每 3 条细线夹 1 条粗线
NumberPlane 继承自 Axes,坐标函数照用。画变换动画(网格扭曲、矩阵作用)时它是标配,见线性变换复刻。
五、参数方程、极坐标与隐函数
# 参数方程: 心形线
polar = axes.plot_polar_graph(
lambda t: 2 + np.cos(t), t_range=[0, 2 * np.pi], color=PINK)
# 参数曲线
epi = axes.plot_parametric_curve(
lambda t: np.array([np.cos(3*t), np.sin(5*t), 0]),
t_range=[0, 2 * np.pi], color=TEAL)
# 隐函数: 不用解 y 也能画圆
circle = ImplicitFunction(
lambda x, y: x**2 + y**2 - 4, color=YELLOW)
六、常见坑
- 曲线画到轴外:plot 的 x_range 超过了 Axes 的 x_range 不会被裁剪,会溢出画面,两者要对齐。
- 函数只接受标量:plot 的 lambda 收到的是单个 x 值,别在里面用 np 数组操作。
- 标签重叠:
get_graph_label的direction参数(UR/UP/RIGHT…)微调位置。