上传文件至 /
数学动画们
This commit is contained in:
29
camera.py
Normal file
29
camera.py
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
from manim import *
|
||||||
|
|
||||||
|
class MoveCameraToCorner(Scene):
|
||||||
|
def construct(self):
|
||||||
|
# 创建坐标轴
|
||||||
|
axes = Axes(
|
||||||
|
x_range=[0, 10, 1],
|
||||||
|
y_range=[0, 10, 1],
|
||||||
|
x_length=6,
|
||||||
|
y_length=6,
|
||||||
|
axis_config={"include_numbers": True},
|
||||||
|
)
|
||||||
|
self.add(axes)
|
||||||
|
|
||||||
|
# 等待一会儿观察默认位置
|
||||||
|
self.wait(1)
|
||||||
|
|
||||||
|
# 将相机移到让原点在左下角的位置,并缩放
|
||||||
|
self.camera.frame.save_state() # 保存初始状态(可选)
|
||||||
|
self.camera.frame.move_to(axes.c2p(5, 5)) # 把坐标系中心移到画面中心
|
||||||
|
self.camera.frame.shift(LEFT * 5.5 + DOWN * 3.2) # 向左下移动
|
||||||
|
self.camera.frame.scale(0.5) # 缩小画面,相当于放大坐标轴
|
||||||
|
|
||||||
|
self.wait(1) # 等待动画前静止
|
||||||
|
|
||||||
|
# 动画执行移动和缩放
|
||||||
|
self.play(self.camera.frame.animate.move_to(axes.c2p(5, 5)).shift(LEFT * 5.5 + DOWN * 3.2).scale(0.5), run_time=3)
|
||||||
|
|
||||||
|
self.wait(2)
|
||||||
48
cartasin.py
Normal file
48
cartasin.py
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
from manim import *
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
class CartesianPlaneScene(Scene):
|
||||||
|
def construct(self):
|
||||||
|
# 一、创建坐标平面,先隐藏网格和数字
|
||||||
|
plane = NumberPlane(
|
||||||
|
x_range=[-5, 5, 1],
|
||||||
|
y_range=[-3, 3, 1],
|
||||||
|
background_line_style={
|
||||||
|
"stroke_color": GREY,
|
||||||
|
"stroke_width": 1,
|
||||||
|
"stroke_opacity": 1,
|
||||||
|
},
|
||||||
|
axis_config={
|
||||||
|
"include_tip": True,
|
||||||
|
"tip_length": 0.15,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
# 生成坐标数字,但先透明
|
||||||
|
plane.add_coordinates()
|
||||||
|
plane.background_lines.set_opacity(0)
|
||||||
|
plane.coordinate_labels.set_opacity(0)
|
||||||
|
|
||||||
|
# 二、动画绘制 X 轴和 Y 轴
|
||||||
|
self.play(
|
||||||
|
Create(plane.x_axis, run_time=2),
|
||||||
|
Create(plane.y_axis, run_time=2),
|
||||||
|
)
|
||||||
|
self.wait(1)
|
||||||
|
|
||||||
|
# 三、写出刻度数字
|
||||||
|
self.play(
|
||||||
|
FadeIn(plane.coordinate_labels, shift=DOWN*0.2),
|
||||||
|
run_time=2
|
||||||
|
)
|
||||||
|
self.wait(1)
|
||||||
|
|
||||||
|
# 四、绘制网格线
|
||||||
|
self.play(
|
||||||
|
Create(plane.background_lines, run_time=3),
|
||||||
|
)
|
||||||
|
self.wait(1)
|
||||||
|
|
||||||
|
# 五、突出原点
|
||||||
|
origin_dot = Dot(plane.c2p(0, 0), color=RED)
|
||||||
|
self.play(FadeIn(origin_dot), run_time=1)
|
||||||
|
self.wait(2)
|
||||||
54
simple_scene.py
Normal file
54
simple_scene.py
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
from manim import *
|
||||||
|
|
||||||
|
class OpeningManim(Scene):
|
||||||
|
def construct(self):
|
||||||
|
title = Tex(r"This is some \LaTeX")
|
||||||
|
basel = MathTex(r"\sum_{n=1}^\infty \frac{1}{n^2} = \frac{\pi^2}{6}")
|
||||||
|
VGroup(title, basel).arrange(DOWN)
|
||||||
|
self.play(
|
||||||
|
Write(title),
|
||||||
|
FadeIn(basel, shift=DOWN),
|
||||||
|
)
|
||||||
|
self.wait()
|
||||||
|
|
||||||
|
transform_title = Tex("That was a transform")
|
||||||
|
transform_title.to_corner(UP + LEFT)
|
||||||
|
self.play(
|
||||||
|
Transform(title, transform_title),
|
||||||
|
LaggedStart(*[FadeOut(obj, shift=DOWN) for obj in basel]),
|
||||||
|
)
|
||||||
|
self.wait()
|
||||||
|
|
||||||
|
grid = NumberPlane()
|
||||||
|
grid_title = Tex("This is a grid", font_size=72)
|
||||||
|
grid_title.move_to(transform_title)
|
||||||
|
|
||||||
|
self.add(grid, grid_title) # Make sure title is on top of grid
|
||||||
|
self.play(
|
||||||
|
FadeOut(title),
|
||||||
|
FadeIn(grid_title, shift=UP),
|
||||||
|
Create(grid, run_time=3, lag_ratio=0.1),
|
||||||
|
)
|
||||||
|
self.wait()
|
||||||
|
|
||||||
|
grid_transform_title = Tex(
|
||||||
|
r"That was a non-linear function \\ applied to the grid"
|
||||||
|
)
|
||||||
|
grid_transform_title.move_to(grid_title, UL)
|
||||||
|
grid.prepare_for_nonlinear_transform()
|
||||||
|
self.play(
|
||||||
|
grid.animate.apply_function(
|
||||||
|
lambda p: p
|
||||||
|
+ np.array(
|
||||||
|
[
|
||||||
|
np.sin(p[1]),
|
||||||
|
np.sin(p[0]),
|
||||||
|
0,
|
||||||
|
]
|
||||||
|
)
|
||||||
|
),
|
||||||
|
run_time=3,
|
||||||
|
)
|
||||||
|
self.wait()
|
||||||
|
self.play(Transform(grid_title, grid_transform_title))
|
||||||
|
self.wait()
|
||||||
183
study.py
Normal file
183
study.py
Normal file
@@ -0,0 +1,183 @@
|
|||||||
|
from manim import *
|
||||||
|
import math
|
||||||
|
|
||||||
|
class FadeInExample(MovingCameraScene):
|
||||||
|
def construct(self):
|
||||||
|
# —— 1. 文本淡入淡出(原样保留)—— #
|
||||||
|
self.wait(0.5)
|
||||||
|
tex = Tex("Inverse ", "Proportion ", "Function").scale(1)
|
||||||
|
self.play(Write(tex), run_time=2)
|
||||||
|
self.wait(1)
|
||||||
|
self.play(
|
||||||
|
AnimationGroup(
|
||||||
|
FadeOut(tex[0], shift=DOWN),
|
||||||
|
FadeOut(tex[1], shift=DOWN),
|
||||||
|
lag_ratio=0.09
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self.play(tex[2].animate.to_corner(UL))
|
||||||
|
self.wait(0.3)
|
||||||
|
|
||||||
|
# —— 2. 定义坐标系 & 函数(原样保留)—— #
|
||||||
|
axes = Axes(
|
||||||
|
x_range=[-6, 8, 1],
|
||||||
|
y_range=[-3, 5, 1],
|
||||||
|
x_length=13,
|
||||||
|
y_length=6,
|
||||||
|
axis_config={
|
||||||
|
"include_tip": False,
|
||||||
|
"numbers_to_include": [],
|
||||||
|
"color": WHITE
|
||||||
|
}
|
||||||
|
).add_coordinates()
|
||||||
|
labels = axes.get_axis_labels()
|
||||||
|
func1 = axes.plot(lambda x: 1/x, x_range=[0.1, 11], color=YELLOW)
|
||||||
|
func2 = axes.plot(lambda x: 1/x, x_range=[-25, -0.1], color=YELLOW)
|
||||||
|
credits = Tex("Made with Manim by David", font_size=24)
|
||||||
|
|
||||||
|
# —— 3. 播放坐标系 & 函数动画(原样保留)—— #
|
||||||
|
self.add(credits.to_corner(DR))
|
||||||
|
self.play(
|
||||||
|
Create(axes, run_time=3, lag_ratio=0.1),
|
||||||
|
Write(credits, run_time=1),
|
||||||
|
)
|
||||||
|
self.add(labels)
|
||||||
|
self.play(Write(labels))
|
||||||
|
self.play(Create(func1, run_time=3), Create(func2, run_time=1))
|
||||||
|
|
||||||
|
# —— 4. 相机缩放前的公式高亮(原样保留)—— #
|
||||||
|
equation = MathTex("y", "=", r"\frac{1}{x}")
|
||||||
|
equation.move_to(UR)
|
||||||
|
self.play(Write(equation), run_time=1)
|
||||||
|
self.wait(0.5)
|
||||||
|
rect = SurroundingRectangle(equation[0], color=YELLOW)
|
||||||
|
self.play(Create(rect), run_time=0.6)
|
||||||
|
self.wait(0.5)
|
||||||
|
new_equation = MathTex(r"f(x)", "=", r"\frac{1}{x}")
|
||||||
|
new_equation.move_to(equation)
|
||||||
|
new_rect = SurroundingRectangle(new_equation[0], color=YELLOW)
|
||||||
|
self.play(
|
||||||
|
Transform(equation, new_equation),
|
||||||
|
Transform(rect, new_rect),
|
||||||
|
run_time=1
|
||||||
|
)
|
||||||
|
self.play(FadeOut(rect), run_time=0.5)
|
||||||
|
|
||||||
|
# —— 5. 相机移动与缩放(原样保留)—— #
|
||||||
|
self.camera.frame.save_state()
|
||||||
|
center = axes.c2p(
|
||||||
|
(axes.x_range[0] + axes.x_range[1]) / 2,
|
||||||
|
(axes.y_range[0] + axes.y_range[1]) / 2
|
||||||
|
)
|
||||||
|
shift_vec = RIGHT * 1.6 + UP * 0.7
|
||||||
|
scale_factor = 0.6
|
||||||
|
self.play(
|
||||||
|
self.camera.frame.animate
|
||||||
|
.move_to(center)
|
||||||
|
.shift(shift_vec)
|
||||||
|
.scale(scale_factor),
|
||||||
|
run_time=1.4
|
||||||
|
)
|
||||||
|
self.remove(credits)
|
||||||
|
self.add(credits.to_corner(DR))
|
||||||
|
self.play(Write(credits), run_time=1)
|
||||||
|
|
||||||
|
# —— 6. 新增积分区域动画(核心修复)—— #
|
||||||
|
# ValueTracker 跟踪 x(初始值设为 e)
|
||||||
|
t = ValueTracker(math.e)
|
||||||
|
|
||||||
|
# dot:始终在 (t, 1/t) 上
|
||||||
|
dot = Dot().set_z_index(10)
|
||||||
|
dot.add_updater(lambda m: m.move_to(
|
||||||
|
axes.c2p(t.get_value(), 1 / t.get_value())
|
||||||
|
))
|
||||||
|
|
||||||
|
# 动态积分区域
|
||||||
|
integral = always_redraw(lambda: axes.get_area(
|
||||||
|
func1,
|
||||||
|
x_range=[1, t.get_value()],
|
||||||
|
color=BLUE,
|
||||||
|
opacity=0.5
|
||||||
|
))
|
||||||
|
integral_border = always_redraw(lambda: axes.plot(
|
||||||
|
lambda x: 1/x,
|
||||||
|
x_range=[1, t.get_value()],
|
||||||
|
color=YELLOW,
|
||||||
|
stroke_width=2
|
||||||
|
))
|
||||||
|
|
||||||
|
# 创建动态文本函数
|
||||||
|
def create_text():
|
||||||
|
x_val = t.get_value()
|
||||||
|
area_val = math.log(x_val)
|
||||||
|
return VGroup(
|
||||||
|
MathTex(f"x = {x_val:.2f}"),
|
||||||
|
MathTex(f"A = {area_val:.2f}")
|
||||||
|
).arrange(DOWN, aligned_edge=LEFT)
|
||||||
|
|
||||||
|
# 动态文本,并添加 updater
|
||||||
|
dynamic_text = create_text()
|
||||||
|
dynamic_text.next_to(dot, UR, buff=0.3)
|
||||||
|
def update_text(group):
|
||||||
|
x_val = t.get_value()
|
||||||
|
area_val = math.log(x_val)
|
||||||
|
group[0].become(MathTex(f"x = {x_val:.2f}"))
|
||||||
|
group[1].become(MathTex(f"A = {area_val:.2f}"))
|
||||||
|
group.arrange(DOWN, aligned_edge=LEFT)
|
||||||
|
group.next_to(dot, UP + RIGHT * 5, buff=0.3)
|
||||||
|
dynamic_text.add_updater(update_text)
|
||||||
|
|
||||||
|
# 添加并播放
|
||||||
|
self.add(dot, integral, integral_border)
|
||||||
|
self.play(Create(integral), Create(integral_border), run_time=2)
|
||||||
|
|
||||||
|
# 切换到动态文本
|
||||||
|
self.add(dynamic_text)
|
||||||
|
self.play(Write(dynamic_text), run_time=2)
|
||||||
|
|
||||||
|
# x 在 e±0.5 之间滑动
|
||||||
|
self.play(t.animate.set_value(math.e + 0.5), run_time=1)
|
||||||
|
self.play(t.animate.set_value(math.e - 0.5), run_time=1)
|
||||||
|
self.play(t.animate.set_value(math.e), run_time=1)
|
||||||
|
self.wait(1)
|
||||||
|
|
||||||
|
# —— 7. 转换为积分形式并高亮(原样保留)—— #
|
||||||
|
integral_eq = MathTex(
|
||||||
|
r"\int_{1}^{x} \frac{1}{x}\,dx = 1"
|
||||||
|
).move_to(ORIGIN).shift(RIGHT * 1.3 + UP)
|
||||||
|
|
||||||
|
def highlight(mobj):
|
||||||
|
return Circumscribe(
|
||||||
|
mobj,
|
||||||
|
color=YELLOW,
|
||||||
|
time_width=2,
|
||||||
|
run_time=1.5,
|
||||||
|
fade_out=True
|
||||||
|
)
|
||||||
|
|
||||||
|
def sync_hl():
|
||||||
|
return (
|
||||||
|
highlight(integral_eq[0][5]), # x
|
||||||
|
highlight(integral_eq[0][-1]), # 1
|
||||||
|
highlight(dynamic_text[0][-1]),# 动态 x
|
||||||
|
highlight(dynamic_text[1][-1]) # 动态 A
|
||||||
|
)
|
||||||
|
|
||||||
|
self.play(Transform(equation, integral_eq), run_time=1.5)
|
||||||
|
self.play(sync_hl(), run_time=2)
|
||||||
|
|
||||||
|
final_eq = MathTex(
|
||||||
|
r"\int_{1}^{e} \frac{1}{x}\,dx = 1"
|
||||||
|
).move_to(integral_eq)
|
||||||
|
self.play(
|
||||||
|
Transform(equation, final_eq),
|
||||||
|
highlight(final_eq[0][5]),
|
||||||
|
highlight(dynamic_text[0][-1]),
|
||||||
|
run_time=2
|
||||||
|
)
|
||||||
|
self.play(
|
||||||
|
Indicate(final_eq[0][5], color=YELLOW),
|
||||||
|
Indicate(dynamic_text[0][-1], color=YELLOW),
|
||||||
|
run_time=1.5
|
||||||
|
)
|
||||||
|
self.wait(1)
|
||||||
166
study_backup2.py
Normal file
166
study_backup2.py
Normal file
@@ -0,0 +1,166 @@
|
|||||||
|
from manim import *
|
||||||
|
import math
|
||||||
|
|
||||||
|
class FadeInExample(MovingCameraScene):
|
||||||
|
def construct(self):
|
||||||
|
# —— 1. 文本淡入淡出(略) —— #
|
||||||
|
self.wait(0.5)
|
||||||
|
tex = Tex("Inverse ", "Proportion ", "Function").scale(1)
|
||||||
|
self.play(Write(tex), run_time=2)
|
||||||
|
self.wait(1)
|
||||||
|
self.play(
|
||||||
|
AnimationGroup(
|
||||||
|
FadeOut(tex[0], shift=DOWN),
|
||||||
|
FadeOut(tex[1], shift=DOWN),
|
||||||
|
lag_ratio=0.09
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self.play(tex[2].animate.to_corner(UL))
|
||||||
|
self.wait(0.3)
|
||||||
|
|
||||||
|
# —— 2. 定义坐标系 & 函数 —— #
|
||||||
|
axes = Axes(
|
||||||
|
x_range=[-6, 8, 1],
|
||||||
|
y_range=[-3, 5, 1],
|
||||||
|
x_length=13,
|
||||||
|
y_length=6,
|
||||||
|
axis_config={
|
||||||
|
"include_tip": False,
|
||||||
|
"numbers_to_include": [],
|
||||||
|
"color": WHITE
|
||||||
|
}
|
||||||
|
).add_coordinates()
|
||||||
|
labels = axes.get_axis_labels()
|
||||||
|
func1 = axes.plot(lambda x: 1/x, x_range=[0.1, 11], color=YELLOW)
|
||||||
|
func2 = axes.plot(lambda x: 1/x, x_range=[-25, -0.1], color=YELLOW)
|
||||||
|
credits = Tex("Made with Manim by David", font_size=24)
|
||||||
|
|
||||||
|
# —— 3. 播放坐标系 & 函数动画 —— #
|
||||||
|
self.add(credits.to_corner(DR))
|
||||||
|
self.play(
|
||||||
|
Create(axes, run_time=3, lag_ratio=0.1),
|
||||||
|
Write(credits, run_time=1),
|
||||||
|
)
|
||||||
|
self.add(labels)
|
||||||
|
self.play(Write(labels))
|
||||||
|
self.play(Create(func1, run_time=3), Create(func2, run_time=1))
|
||||||
|
|
||||||
|
# —— 4. 相机缩放前的公式高亮(略) —— #
|
||||||
|
equation = MathTex("y", "=", r"\frac{1}{x}")
|
||||||
|
equation.move_to(UR)
|
||||||
|
self.play(Write(equation), run_time=1)
|
||||||
|
self.wait(0.5)
|
||||||
|
rect = SurroundingRectangle(equation[0], color=YELLOW)
|
||||||
|
self.play(Create(rect), run_time=0.6)
|
||||||
|
self.wait(0.5)
|
||||||
|
new_equation = MathTex(r"f(x)", "=", r"\frac{1}{x}")
|
||||||
|
new_equation.move_to(equation)
|
||||||
|
new_rect = SurroundingRectangle(new_equation[0], color=YELLOW)
|
||||||
|
self.play(
|
||||||
|
Transform(equation, new_equation),
|
||||||
|
Transform(rect, new_rect),
|
||||||
|
run_time=1
|
||||||
|
)
|
||||||
|
self.play(FadeOut(rect), run_time=0.5)
|
||||||
|
|
||||||
|
# —— 5. 相机移动与缩放 —— #
|
||||||
|
self.camera.frame.save_state()
|
||||||
|
center = axes.c2p(
|
||||||
|
(axes.x_range[0] + axes.x_range[1]) / 2,
|
||||||
|
(axes.y_range[0] + axes.y_range[1]) / 2
|
||||||
|
)
|
||||||
|
shift_vec = RIGHT * 1.6 + UP * 0.7
|
||||||
|
scale_factor = 0.6
|
||||||
|
self.play(
|
||||||
|
self.camera.frame.animate
|
||||||
|
.move_to(center)
|
||||||
|
.shift(shift_vec)
|
||||||
|
.scale(scale_factor),
|
||||||
|
run_time=1.4
|
||||||
|
|
||||||
|
)
|
||||||
|
self.remove(credits)
|
||||||
|
self.add(credits.to_corner(DR))
|
||||||
|
self.play(Write(credits), run_time=1)
|
||||||
|
self.wait(0.3)
|
||||||
|
|
||||||
|
# —— 6. 新增积分区域动画 —— #
|
||||||
|
# ValueTracker 跟踪 x(初始值设为 e)
|
||||||
|
t = ValueTracker(math.e)
|
||||||
|
|
||||||
|
# 点 updater:始终在 (t, 1/t) 上
|
||||||
|
dot = Dot().set_z_index(10)
|
||||||
|
dot.add_updater(lambda d: d.move_to(
|
||||||
|
axes.c2p(t.get_value(), 1 / t.get_value())
|
||||||
|
))
|
||||||
|
|
||||||
|
# 动态多边形:积分区域从 x=1 到 current_x
|
||||||
|
def make_polygon():
|
||||||
|
x = t.get_value()
|
||||||
|
y = 1 / x
|
||||||
|
# 顶点为 (1,0), (x,0), (x, y), (1, 1)
|
||||||
|
p0 = axes.c2p(1, 0)
|
||||||
|
p1 = axes.c2p(x, 0)
|
||||||
|
p2 = axes.c2p(x, y)
|
||||||
|
p3 = axes.c2p(1, 1)
|
||||||
|
poly = Polygon(p0, p1, p2, p3)
|
||||||
|
poly.set_fill(BLUE, opacity=0.5)
|
||||||
|
poly.set_stroke(YELLOW, width=2)
|
||||||
|
return poly
|
||||||
|
polygon = always_redraw(make_polygon)
|
||||||
|
|
||||||
|
# 实时显示面积(积分面积)
|
||||||
|
area_text = always_redraw(lambda: MathTex(
|
||||||
|
rf"x = {t.get_value():.2f}",
|
||||||
|
rf"\text{{Area}} = \ln(x) = {math.log(t.get_value()):.2f}"
|
||||||
|
).arrange(DOWN).scale(0.6).next_to(dot, RIGHT).shift(UP*1.5))
|
||||||
|
|
||||||
|
# 添加元素到场景
|
||||||
|
self.add(dot, polygon)
|
||||||
|
self.play(
|
||||||
|
Create(polygon),
|
||||||
|
run_time = 1.5
|
||||||
|
)
|
||||||
|
|
||||||
|
self.add(area_text)
|
||||||
|
self.play(
|
||||||
|
Write(area_text),
|
||||||
|
run_time = 3
|
||||||
|
)
|
||||||
|
|
||||||
|
# 动画:x 在 e±0.5 之间滑动,最后停在 e
|
||||||
|
self.play(t.animate.set_value(math.e + 0.5), run_time=1)
|
||||||
|
self.play(t.animate.set_value(math.e - 0.5), run_time=1)
|
||||||
|
self.play(t.animate.set_value(math.e), run_time=1)
|
||||||
|
self.wait(1)
|
||||||
|
|
||||||
|
# —— 7. 转换为积分形式并高亮 x —— #
|
||||||
|
self.play(
|
||||||
|
Transform(equation, MathTex(
|
||||||
|
r"\int_{1}^{x} \frac{1}{t}\,dt = \ln(x)"
|
||||||
|
).move_to(RIGHT * 1.3 + UP)),
|
||||||
|
run_time=1.5
|
||||||
|
)
|
||||||
|
|
||||||
|
# 高亮 x
|
||||||
|
highlight_rect = SurroundingRectangle(equation[-2][1], color=YELLOW)
|
||||||
|
self.play(Create(highlight_rect), run_time=0.6)
|
||||||
|
self.wait(0.5)
|
||||||
|
|
||||||
|
# 将 x 替换为 e
|
||||||
|
self.play(
|
||||||
|
Transform(equation, MathTex(
|
||||||
|
r"\int_{1}^{e} \frac{1}{t}\,dt = 1"
|
||||||
|
).move_to(equation)),
|
||||||
|
run_time=1.5
|
||||||
|
)
|
||||||
|
self.wait(0.5)
|
||||||
|
|
||||||
|
# 清除并添加 x = e
|
||||||
|
self.play(
|
||||||
|
Transform(equation, MathTex("x = e").move_to(equation)),
|
||||||
|
FadeOut(highlight_rect, shift=DOWN),
|
||||||
|
FadeOut(area_text, shift=DOWN), # 同时移除面积文本
|
||||||
|
run_time=1
|
||||||
|
)
|
||||||
|
self.wait(1)
|
||||||
Reference in New Issue
Block a user