动画通过一次函数 的实例,直观展示斜率公式从具体形式到抽象符号的演变过程。
核心思想
动画围绕三个核心概念层层递进:
动画结构
第一部分:基础建立
第二部分:几何可视化
第三部分:坐标差可视化
视觉设计亮点
- 颜色编码:红色表示 及相关元素,紫色表示 及相关元素
- 动画过渡:通过渐隐渐现和形状变换,平滑过渡不同表示形式
完整代码
from utils import *
classv4(Scene):
defconstruct(self):
DX_COLOR = RED
DY_COLOR = PURPLE
# ============ 1. 坐标轴和函数图形 ============
ax, ax_x_label, ax_y_label = axes_func() # 获取坐标轴及标签
f = f_func1(0.5, 2) # 定义函数 f(x) = 0.5x + 2
gr = ax.plot(f, x_range=[-1, 13], stroke_width=4, color=GREEN)
gr_label = MathTex("y = ax + b", color=GREEN).to_edge(UP, buff=1)
gr_label[0][2].set_color(YELLOW) # 高亮斜率 a
self.play(FadeIn(ax, ax_x_label, ax_y_label))
self.wait()
self.play(FadeIn(gr_label, gr))
self.wait()
# ============ 2. 将 'y = ax + b' 转变为斜率公式 ============
t1 = MathTex(r"a = \frac{y_2 - y_1}{x_2 - x_1}").move_to(gr_label).shift(DOWN * 0.05)
t1[0][0].set_color(YELLOW) # 高亮 a
t1[0][2:7].set_color(DY_COLOR) # y₂ - y₁ 紫色
t1[0][8:13].set_color(DX_COLOR) # x₂ - x₁ 红色
t2 = MathTex(r"a = \frac{\Delta y}{\Delta x}").move_to(t1).shift(UP * 0.1)
t2[0][0].set_color(YELLOW) # 高亮 a
t2[0][2:4].set_color(DY_COLOR) # Δy 紫色
t2[0][5:7].set_color(DX_COLOR) # Δx 红色
# 动画:将 gr_label 中的 a 变换为 t1 中的 a
self.play(ReplacementTransform(gr_label[0][2], t1[0][0]),
FadeOut(gr_label[0][0:2], gr_label[0][3:]),
FadeIn(t1[0][1])) # 显示等号
self.wait(2)
# ============ 3. 两点及其到坐标轴的线段 ============
x = ValueTracker(5.5)
dx = ValueTracker(2)
dot_1 = dot_func(ax, f, x.get_value())
dot_1_line = xy_line_func(ax, f, x.get_value())
dot_1_x_label = x_line_label_func(ax, f, x.get_value(), r"x_1")
dot_1_y_label = y_line_label_func(ax, f, x.get_value(), r"y_1")
dot_2 = dot_func(ax, f, x.get_value() + dx.get_value())
dot_2_line = xy_line_func(ax, f, x.get_value() + dx.get_value())
dot_2_x_label = x_line_label_func(ax, f, x.get_value() + dx.get_value(), r"x_2")
dot_2_y_label = y_line_label_func(ax, f, x.get_value() + dx.get_value(), r"y_2")
# 滞后动画:依次显示两点及其垂线
self.play(LaggedStart(
AnimationGroup(FadeIn(dot_1_line, dot_1_x_label, dot_1_y_label),
GrowFromCenter(dot_1)),
AnimationGroup(FadeIn(dot_2_line, dot_2_x_label, dot_2_y_label),
GrowFromCenter(dot_2)),
lag_ratio=0.4), run_time=2)
self.wait(2)
# ============ 4. 标记 Δx 和 Δy,显示文本说明 ============
delta_x_line = delta_x_line_func(ax, f, x.get_value(), dx.get_value())
delta_x_label_1 = delta_x_label_func(ax, f, x.get_value(), dx.get_value(),
r"x_2 - x_1")
delta_x_label_2 = delta_x_label_func(ax, f, x.get_value(), dx.get_value(),
r"\Delta x")
delta_y_line = delta_y_line_func(ax, f, x.get_value(), dx.get_value())
delta_y_label_1 = delta_y_label_func(ax, f, x.get_value(), dx.get_value(),
r"y_2 - y_1")
delta_y_label_2 = delta_y_label_func(ax, f, x.get_value(), dx.get_value(),
r"\Delta y")
# 给 x₂ - x₁ 标签添加黑色背景框
delta_x_label_1_sr = SurroundingRectangle(delta_x_label_1).set_color(
BLACK).set_stroke(width=0).set_opacity(0.8)
# 显示 y₂ - y₁
self.play(FadeIn(t1[0][2:8], delta_y_label_1), Create(delta_y_line))
self.wait(2)
# 显示 x₂ - x₁
self.play(FadeIn(t1[0][8:13], delta_x_label_1_sr, delta_x_label_1),
Create(delta_x_line))
self.wait(2)
# 变换为 Δy/Δx 表示
self.play(LaggedStart(
FadeOut(t1[0][2:7], delta_y_label_1),
FadeIn(t2[0][2:4], delta_y_label_2), # Δy
FadeOut(t1[0][8:13], delta_x_label_1_sr, delta_x_label_1),
AnimationGroup(
FadeIn(t2[0][5:7], delta_x_label_2), # Δx
ReplacementTransform(t1[0][7], t2[0][4]),# 减号变换
ReplacementTransform(t1[0][0:2], t2[0][0:2]), # a= 变换
), lag_ratio=0.5), run_time=7)
self.wait(2)
# 淡出所有元素
self.play(FadeOut(*self.mobjects))
self.wait(2)
%manim -ql -v WARNING v4