多元微积分可视化

梯度和方向导数的关系

围绕梯度和方向导数的关系,观察梯度、方向导数、等值面之间的关系与推理路径。

打开原视频

gradient_concept.py
1from manim import *2import numpy as np3 4config.tex_template = TexTemplateLibrary.ctex5config.tex_template.add_to_preamble(r"\setCJKmainfont{STSong}")6 7class GradientConcept(ThreeDScene):8    def create_derivative_value_tracker(self):9        """创建方向导数值的显示区域"""10        tracker = VGroup()11        # 将显示区域放在右侧12        tracker.arrange(DOWN, buff=0.1)13        tracker.to_edge(RIGHT, buff=0.5)14        return tracker15 16    def construct(self):17        # 创建标题18        title = Text(19            "方向导数与梯度",20            font="STSong",21            font_size=4822        )23        24        # 显示标题25        self.add_fixed_in_frame_mobjects(title)26        self.play(Write(title))27        self.wait(2)28        29        # 淡出标题30        self.play(FadeOut(title))31        32        # 创建3D坐标系33        self.axes = ThreeDAxes(34            x_range=[-1, 1, 0.5],35            y_range=[-1, 1, 0.5],36            z_range=[0, 2, 0.5],37            x_length=4,  # 缩小坐标轴长度38            y_length=4,39            z_length=3,40            axis_config={"color": GREY, "include_ticks": False}41        )42        43        # 创建函数曲面 z = -x² - y² + 244        surface = Surface(45            lambda u, v: self.axes.c2p(u, v, -u**2 - v**2 + 2),  # 降低最高点46            u_range=[-1, 1],47            v_range=[-1, 1],48            resolution=(30, 30),49            checkerboard_colors=[BLUE_D, BLUE_E],50            fill_opacity=0.651        )52        53        # 设置初始视角54        self.set_camera_orientation(phi=60*DEGREES, theta=-45*DEGREES)55        self.add(self.axes, surface)56        57        # 选择基准点 P(0.5,0.5,0)58        P = [0.5, 0.5, 0]59        P_surface = [0.5, 0.5, 1.5]  # z = -0.5² - 0.5² + 2 = 1.560        point_P = Dot3D(self.axes.c2p(*P), color=RED, radius=0.05)  # 缩小点的大小61        point_P_surface = Dot3D(self.axes.c2p(*P_surface), color=RED)62        63        # 显示基准点64        self.play(65            Create(point_P),66            Create(point_P_surface),67            Create(Line(68                self.axes.c2p(*P),69                self.axes.c2p(*P_surface),70                color=YELLOW71            ))72        )73        74        # 创建多个方向的切线75        angles = np.linspace(0, 2*np.pi, 8)  # 8个不同方向76        directions = []77        tangent_lines = []78        direction_vectors = []  # 存储底面上的方向向量79        80        for angle in angles:81            # 计算方向向量82            direction = [np.cos(angle), np.sin(angle), 0]83            directions.append(direction)84            85            # 计算方向导数86            directional_derivative = -2*P[0]*direction[0] - 2*P[1]*direction[1]87            88            # 创建切线和方向向量89            tangent = self.create_tangent_line(90                P_surface,91                direction,92                directional_derivative,93                length=294            )95            direction_vector = Arrow3D(96                start=self.axes.c2p(*P),97                end=self.axes.c2p(*(np.array(P) + 0.3*np.array(direction))),  # 缩放方向向量长度98                color=RED,99                thickness=0.03  # 稍细一些100            )101            tangent_lines.append(tangent)102            direction_vectors.append(direction_vector)103        104        # 逐个显示不同方向的切线和方向向量105        for tangent, vector in zip(tangent_lines, direction_vectors):106            self.play(107                Create(tangent),108                Create(vector),109                run_time=1110            )111            self.wait(0.5)112        113        # 创建说明文字114        explanation = Text(115            "不同方向的切线斜率表示\n沿不同方向的方向导数值",116            font="STSong",117            line_spacing=1.5118        ).scale(0.5)119        explanation.to_edge(RIGHT, buff=0.5).to_edge(UP, buff=1)120        self.add_fixed_in_frame_mobjects(explanation)121        self.play(Write(explanation))122        self.wait(1)123        124        # 创建方向导数计算公式125        formula = MathTex(126            "\\frac{\\partial f}{\\partial l} = ",127            "\\frac{\\partial f}{\\partial x}\\cos\\theta + ",128            "\\frac{\\partial f}{\\partial y}\\sin\\theta"129        ).scale(0.6)130        formula.to_edge(RIGHT, buff=0.5).shift(UP)131        self.add_fixed_in_frame_mobjects(formula)132        self.play(Write(formula))133        self.wait(1)134        135        # 计算梯度向量136        gradient = [2*P[0], 2*P[1], 0]137        gradient_arrow = Arrow3D(138            start=self.axes.c2p(*P),139            end=self.axes.c2p(*(np.array(P) + 0.5*np.array(gradient))),140            color=YELLOW,141            thickness=0.05142        )143        144        # 突出显示最大方向导数(梯度方向)145        self.play(146            Create(gradient_arrow),147            *[tangent.animate.set_opacity(0.3) for tangent in tangent_lines],148            *[vector.animate.set_opacity(0.3) for vector in direction_vectors],149            run_time=2150        )151        152        # 添加梯度标签153        gradient_label = MathTex("\\text{grad }f").next_to(gradient_arrow, RIGHT)154        self.play(Write(gradient_label))155        156        # 显示结论157        conclusion = VGroup(158            Text(159                "方向导数最大的方向是梯度的方向",160                font="STSong",161                font_size=24162            ),163            Text(164                "方向导数的最大值是梯度的模",165                font="STSong",166                font_size=24167            )168        ).arrange(DOWN, buff=0.3).to_edge(DOWN, buff=0.5)169        self.add_fixed_in_frame_mobjects(conclusion)170        self.play(Write(conclusion))171        self.wait(2)172        173    def create_tangent_line(self, point, direction, derivative, length=2):174        """创建切线"""175        direction = np.array(direction)176        direction = direction / np.linalg.norm(direction)177        178        # 计算曲面上的切向量179        # 对于f(x,y)=-x²-y²+2, 在点(x₀,y₀)处180        x0, y0 = point[0], point[1]181        dx = -2*x0  # ∂f/∂x = -2x182        dy = -2*y0  # ∂f/∂y = -2y183        184        # 计算方向导数185        dir_derivative = dx*direction[0] + dy*direction[1]186        187        # 构造切向量 (注意z分量是方向导数)188        tangent = np.array([189            direction[0],190            direction[1],191            dir_derivative192        ])193        # 归一化切向量194        tangent = tangent / np.linalg.norm(tangent)195        196        # 创建射线(只向一个方向延伸)197        end = np.array(point) + length * tangent198        199        return Line(200            self.axes.c2p(*point),  # 从曲面上的点开始201            self.axes.c2p(*end),202            color=RED,203            stroke_width=3204        )205 206    def color_from_direction(self, direction, gradient):207        """根据方向与梯度的夹角确定颜色"""208        cos_theta = np.dot(direction[:2], gradient[:2]) / (209            np.linalg.norm(direction[:2])*np.linalg.norm(gradient[:2]))210        return interpolate_color(BLUE, RED, (cos_theta + 1)/2)

讲解

这个视频围绕「梯度和方向导数的关系」展开。画面把问题、图像和公式放在同一条理解路径中,让抽象关系先被看见。

开头先建立问题背景和主要对象,让观察从标题、坐标或第一组关系进入。

随后出现更具体的图像或公式提示,动画会把局部对象和整体结论联系起来。这里可以重点观察变量、曲线、区域或向量如何随镜头推进而变化。

核心公式可以写成:

grad f\text{grad }f

这类公式可以和画面中的符号一一对应。

观察路径

观察路径可以分三步:先锁定「梯度和方向导数的关系」中的核心对象,尤其留意梯度、方向导数、等值面之间的联系;再跟随画面中变量、图像或向量的变化;最后回到公式或结论,判断局部变化如何支撑整体关系。

本页可以从梯度、方向导数、等值面、向量场这些概念进入,继续沿相邻问题观察同一类数学结构。