切线之美:SymPy与Manim联手打造直观导数动画

作者:袖梨 2026-05-21

在Manim中制作导数定义动画时,如何避免繁琐的手动计算?本文将介绍如何利用SymPy实现自动化符号运算,轻松呈现割线逼近切线的动态过程。

切线的魔法:用 SymPy 和 Manim 轻松搞定导数动画

这个经典场景需要绘制曲线和割线,通过让割线上一个点无限逼近另一个点,最终形成切线。其核心在于计算割线斜率(f(x+h) - f(x))/h,并观察当h趋近于0时的变化。

虽然原理简单,但手动推导极限、逐帧计算坐标不仅耗时,还容易出错。以函数f(x)=x³-2x+1在x=1处的切线动画为例,我们需要解决以下问题:

  1. 定义割线:确定两点P(1, f(1))和Q(1+h, f(1+h))的位置。
  2. 计算斜率:求解斜率表达式slope = (f(1+h) - f(1))/h。
  3. 求极限:当h→0时,确定斜率的极限值f'(1)。
  4. 动态更新:在动画中让h从1逐渐减小到0.01,实时计算Q点坐标和割线斜率。

手动处理这些步骤需要展开(1+h)³-2(1+h)+1等复杂表达式,对于更复杂的函数如f(x)=sin(x²)几乎不可行。这就是我们需要SymPy的原因——实现动态、精准的自动化符号计算。

SymPy 解决方案:让计算机做数学

SymPy能完美处理符号运算,其核心函数包括:

  1. diff(f, x):自动求导函数
  2. limit(expr, h, 0):计算极限值

以下代码展示了SymPy的强大功能:

from sympy import symbols, diff, limit# 定义符号变量
x = symbols('x')# 定义函数
f = x**3 - 2*x + 1# 自动求导
f_prime = diff(f, x)
print(f"导函数 f'(x) = {f_prime}") # 输出: 3*x**2 - 2# 计算x=1处的导数
slope_at_1 = f_prime.subs(x, 1)
print(f"x=1处斜率 = {slope_at_1}") # 输出: 1# 验证极限
secant_slope_expr = (f.subs(x, 1+h) - f.subs(x, 1)) / h
limit_slope = limit(secant_slope_expr, h, 0)
print(f"极限斜率 = {limit_slope}") # 输出: 1

Manim 联动实战:让切线"动"起来

将SymPy集成到Manim动画中,使用ValueTracker控制h值的变化:

from manim import *
from sympy import symbols, lambdify, diffclass DerivativeAnimation(Scene):
    def construct(self):
        # SymPy计算部分
        x_sym = symbols("x")
        f_sym = x_sym**3 - 2*x_sym + 1
        f = lambdify(x_sym, f_sym, "numpy")        
        f_prime_sym = diff(f_sym, x_sym)
        exact_k = float(f_prime_sym.subs(x_sym, 1)) # 精确导数        # Manim可视化
        ax = Axes(x_range=[-2, 3], y_range=[-3, 5])
        graph = ax.plot(f, color=YELLOW)
        p_point = Dot(ax.c2p(1, f(1)), color=RED)        # 动态割线
        h_tracker = ValueTracker(1)
        def get_secant_line():
            h_val = h_tracker.get_value()
            x_q = 1 + h_val
            k = (f(x_q) - f(1)) / h_val
            return ax.plot(
                lambda x: k * (x - 1) + f(1),
                color=GREEN, x_range=[0, x_q + 1]
            )        secant_line = always_redraw(get_secant_line)        # 精确切线
        tangent_line = ax.plot(
            lambda x: exact_k * (x - 1) + f(1),
            color=PURPLE, x_range=[-0.5, 2.5]
        )        # 动画流程
        self.play(Create(ax), Create(graph), Create(p_point))
        self.play(Create(secant_line))
        self.play(
            h_tracker.animate.set_value(0.001),
            run_time=5,
            rate_func=rate_functions.ease_in_out_quad
        )
        self.play(Create(tang

相关文章

精彩推荐