
痛点场景还原假设我们想做一个简单的对比动画在坐标系里同时画出y2x1y−12x3如果纯用Manim手写我们一般会这样写只画其中一条的片段from manim import * class ManualLinear(Scene): def construct(self): ax Axes( x_range[-5, 5], y_range[-5, 5], axis_config{include_numbers: True} ) # 手动计算两个点的坐标以保证线段能覆盖整个画面 # y 2x 1当 x-5 时 y-9当 x5 时 y11 line1 Line(ax.c2p(-5, -9), ax.c2p(5, 11), colorRED) # 手动计算与 y 轴的交点 (0, 1) intercept_dot Dot(ax.c2p(0, 1), colorYELLOW) self.add(ax, line1, intercept_dot)这里的问题很明显端点坐标、截距坐标都是我“算出来写死”的。如果想把k改成-0.7b改成2.5上面所有数字都得重新算一遍。更难受的是如果想让线段刚好卡在坐标轴的边框上既不超出也不短还需要解方程求直线与矩形边框的交点——手动做实在太低效了。这还只是一条线如果要一次性展示k从-2到2的多条直线手动计算根本不可能。2. SymPy 解决方案把计算“外包”出去解决思路非常直接用SymPy负责符号运算根据给定的参数自动求出我们需要的所有坐标。核心任务有三个给定k、b和坐标系可视范围自动生成直线的两个端点正好落在边框上自动求出直线与坐标轴的交点截距判断两条直线是否平行系数比较先看纯SymPy的运算逻辑不需要Manimimport sympy as sp x, y sp.symbols(x y) k, b sp.symbols(k b) expr k * x b # y kx b # 示例取 k2, b1x 范围 [-5, 5]y 范围 [-5, 5] x_min, x_max -5, 5 y_min, y_max -5, 5 # 1. 求与坐标轴的交点 x_intercept sp.solve(expr.subs({k: 2, b: 1}), x) # 令 y0 # x_intercept [-1/2] 即 (-0.5, 0) y_intercept expr.subs({k: 2, b: 1, x: 0}) # 令 x0 # y_intercept 1 即 (0, 1) # 2. 自动求边框端点解直线与 xx_min, xx_max, yy_min, yy_max 的交点 # 保留落在矩形范围且是“极值方向”的两个点 points_on_border [] for x_val in (x_min, x_max): y_val expr.subs({k: 2, b: 1, x: x_val}) if y_min y_val y_max: points_on_border.append((x_val, y_val)) for y_val in (y_min, y_max): sol_x sp.solve(expr.subs({k: 2, b: 1}) - y_val, x) for x_sol in sol_x: if x_min x_sol x_max: points_on_border.append((x_sol, y_val)) # 取两个端点按 x 排序即可 points_on_border sorted(points_on_border, keylambda p: p[0]) endpoints [points_on_border[0], points_on_border[-1]] # 3. 判断平行比较化简后的系数注意避免浮点精度问题 k1, k2 sp.sympify(2), sp.sympify(-0.5) parallel sp.simplify(k1 - k2) 0 # 完全相等才平行上面的计算过程被封装成一个工具函数后接下来Manim只需要拿着这些坐标画图就行了。3. Manim 联动实战完整可运行代码下面给出完整的场景代码一次运行自动生成 ykxb 多条直线的对比图带截距高亮和平行判断。from manim import * import sympy as sp class AutoLinearComparison(Scene): def construct(self): # 坐标轴及范围 ax Axes( x_range[-4, 4, 1], y_range[-4, 4, 1], x_length8, y_length6, axis_config{include_numbers: True, font_size: 18}, tipsFalse, ).add_coordinates() self.add(ax) # 需要对比的参数列表(k, b, 颜色) params [ (2, 1, RED), (-0.5, 3, BLUE), (1, -2, GREEN), (-0.5, -1, ORANGE), ] lines_vg VGroup() dots_vg VGroup() labels_vg VGroup() x_min, x_max ax.x_range[0], ax.x_range[1] # -6, 6 y_min, y_max ax.y_range[0], ax.y_range[1] # -4, 4 x, y sp.symbols(x y) k_sym, b_sym sp.symbols(k b) expr_template k_sym * x b_sym # 符号模板 for k_val, b_val, color in params: # ---- SymPy 计算 ---- expr expr_template.subs({k_sym: k_val, b_sym: b_val}) # 代入具体参数 # 1. 求直线与坐标轴交点截距 x_int sp.solve(expr, x) # 令 y0 x_int float(x_int[0]) if x_int else None y_int float(expr.subs(x, 0)) # 令 x0 # 2. 求直线与矩形边框的合理端点 border_pts [] for x_val in (x_min, x_max): y_val float(expr.subs(x, x_val)) if y_min y_val y_max: border_pts.append((x_val, y_val)) for y_val in (y_min, y_max): sol_x sp.solve(expr - y_val, x) for sx in sol_x: sx_f float(sx) if x_min sx_f x_max: border_pts.append((sx_f, y_val)) border_pts sorted(border_pts, keylambda p: p[0]) # 取首尾作为线段端点 p1, p2 border_pts[0], border_pts[-1] # ---- Manim 绘制 ---- line Line(ax.c2p(*p1), ax.c2p(*p2), colorcolor, stroke_width4) lines_vg.add(line) # 截距点如果落在坐标轴范围内 if x_int is not None and y_min 0 y_max: dot_x Dot(ax.c2p(x_int, 0), colorcolor, radius0.08) dots_vg.add(dot_x) # 标注 x 截距坐标 label_x MathTex( f({x_int:.1f},0), font_size20, colorcolor ).next_to(dot_x, DOWN) labels_vg.add(label_x) if y_int is not None and x_min 0 x_max: dot_y Dot(ax.c2p(0, y_int), colorcolor, radius0.08) dots_vg.add(dot_y) label_y MathTex( f(0,{y_int:.1f}), font_size20, colorcolor ).next_to(dot_y, LEFT) labels_vg.add(label_y) # 播放动画 self.play(Create(lines_vg), run_time3) self.play(FadeIn(dots_vg, scale0.5), Write(labels_vg), run_time2) self.wait(2)说明几点关键设计x_range[0], x_range[1]直接读取坐标轴的数值范围后续所有计算都以此为基准修改范围再也不用手动改端点计算。与边框求交时遍历了四条边界线xmin, xmax, ymin, ymax并筛选落在范围内的点确保线段两端刚好“顶”到边框不多不少。截距点用了sp.solve(expr, x)求 x 截距即 y0 时 x 的值用.subs(x,0)求 y 截距。这些值可直接传给ax.c2p完成坐标转换。平行判断在这个例子里没显示但你可以轻松加入用sp.simplify(k1 - k2) 0比较两条直线的斜率如果平行就给特殊标注。4. 效果展示说明运行上述代码后你会看到坐标系先出现随后四条不同颜色的直线同时生长出来。每条直线的长度恰好贯穿整个画面没有任何线段伸到坐标轴之外或中途截断视觉效果干净利落。紧接着每个颜色对应的截距点与 x 轴、y 轴的交点以圆点浮现旁边自动标注坐标数值像是“( -0.5 , 0 )”、“( 0 , 3 )” 这样的形式。如果两条直线的 k 值相等比如再补一条平行线你还可以添加文字提示“这两条直线平行”彻底不用人工判断。