GraphingMovement
这个开始再坐标轴上画函数图像以及移动
from manim import *
class GraphingMovement(Scene):
def construct(self):
axes = Axes(
x_range=[0,5,1], # x 轴范围:从 0 到 5,刻度间隔为 1
y_range=[0,3,1], # y 轴范围:从 0 到 3,刻度间隔为 1
x_length=5, # x 轴长度为 5(单位为 Manim 默认单位)
y_length=3, # y 轴长度为 3(单位为 Manim 默认单位)
axis_config={
"include_tip": True, # 坐标轴末端添加箭头
"numbers_to_exclude":[0] # 排除坐标轴上显示的数字 0
}
).add_coordinates() # 添加坐标轴上的刻度值标签
axes.to_edge(UR) # 将坐标轴移动到画布的右上角 (UP+RIGHT 方向)
axes_labels = axes.get_axis_labels(x_label="x", y_label="f(x)") #使用 get_axis_labels 方法为 x 轴和 y 轴添加标签,分别命名为 "x" 和 "f(x)"。
# 使用 plot 方法绘制函数图像,函数为 y = sqrt(x)(即 lambda x: x**0.5),定义域为 [0, 4],颜色为红色(RED)。
graph = axes.plot(lambda x: x**0.5, x_range=[0, 4], color=RED)
graphing_stuff = VGroup(axes, axes_labels, graph)
self.play(DrawBorderThenFill(axes),Write(axes_labels))
self.play(Create(graph))
self.play(graphing_stuff.animate.shift(DOWN*4))
self.play(axes.animate.shift(LEFT*3),run_time = 3)
这段代码看起来没有什么难度,但是这一行里面
graph = axes.plot(lambda x: x**0.5, x_range=[0, 4], color=RED)
我学习的时候发现我用Brian Amedee的代码再我的本地环境里面跑不起来
当时Brian Amedee的代码为
graph = axes.get_graph(lambda x: x**0.5, x_range=[0, 4], color=RED)
后面才发现这和manim的版本有关,大家也可以试一下这两个方法有什么区别
这个动画首先是向下移动这个整体,然后再单独想左移动坐标轴,那么如果我在一次移动这个整体,也就是再代码的最后加一行
self.play(graphing_stuff.animate.shift(LEFT*4))
会出现什么效果呢,感兴趣的小伙伴可以试一下
我在按照Brian Amedee视频中的例子学习的时候,现在有意识地先看效果图,然后先自己看看能不能自己写出来,出不出来的地方然后在看代码怎么写的
老规矩先上视频
Graphing
首先我们可以先看到效果图,这个效果图首先时先出现坐标轴,然后再出现函数和函数式,最后再出现函数里面的面积,根据manim里面的三元素,上述的坐标轴,函数,面积其实都是我们需要创建的Object,那我们怎么创建呢
我现在把注释标注在代码里
from manim import *
class Graphing(Scene):
def construct(self):
# 创建坐标系和函数
my_plane = NumberPlane(x_range = [-6,6],x_length = 5,
y_range = [-10,10],y_length = 5 )
my_plane.add_coordinates() # 给坐标轴标上数字
my_plane.shift(RIGHT*3)
# 创建函数和面积
my_function = my_plane.plot(lambda x: 0.1*(x-5)*x*(x-5),x_range = [-5,5] ,color = BLUE)
# 面积
area = my_plane.get_area(graph= my_function,x_range = [-5,5],color = [BLUE,YELLOW])
label = MathTex("f(x) = 0.1(x-5)x(x-5)").next_to(my_plane,UP,buff=0.2)
horiz_line = Line(
start=my_plane.c2p(0,my_function.underlying_function(-2)),
end=my_plane.c2p(-2,my_function.underlying_function(-2)),
stroke_color = YELLOW,stroke_width = 10
)
self.play(DrawBorderThenFill(my_plane))
self.play(Create(my_function),Write(label))
self.play(FadeIn(area) , runTime = 4)
self.play(Create(horiz_line),run_time = 3)
首先我们先看这一句,只一句就是创建函数这个Object
my_function = my_plane.plot(lambda x: 0.1*(x-5)*x*(x-5),x_range = [-5,5] ,color = BLUE)
参数 | 说明 |
---|---|
lambda x: 0.1*(x-5)x(x-5) | 在my_plane坐标轴上描绘函数 |
x_range = [-5,5] | x的定义域【-5,5】 |
color = BLUE | 颜色 |
然后就是创建我们想要的函数面积
area = my_plane.get_area(graph= my_function,x_range = [-5,5],color = [BLUE,YELLOW])
参数 | 说明 |
---|---|
graph= my_function | 目标函数 |
x_range = [-5,5] | x的定义域【-5,5】 |
color = BLUE | 颜色 |
然后就是一个水平与x轴的说水平线
horiz_line = Line(
start=my_plane.c2p(0,my_function.underlying_function(-2)),
end=my_plane.c2p(-2,my_function.underlying_function(-2)),
stroke_color = YELLOW,stroke_width = 10
)
horiz_line = Line(...)
Line
是图形绘制库中用于创建线段对象的类。horiz_line
是创建的线段对象的变量名,通过这个变量可以对该线段进行后续的操作,比如添加到场景中显示、修改其属性等。start=my_plane.c2p(0, my_function.underlying_function(-2))
start
是 Line
类的一个参数,用于指定线段的起点。my_plane
是一个表示平面的对象,它应该有一个 c2p
方法。c2p
方法的作用是将笛卡尔坐标(x
, y
)转换为该平面上的实际坐标。my_function
是一个函数对象,my_function.underlying_function(-2)
表示调用 my_function
的底层函数,并传入参数 -2
,得到函数在 x = -2
处的函数值。my_plane.c2p(0, my_function.underlying_function(-2))
表示将笛卡尔坐标 (0, my_function.underlying_function(-2))
转换为平面 my_plane
上的实际坐标,作为线段的起点。end=my_plane.c2p(-2, my_function.underlying_function(-2))
end
是 Line
类的一个参数,用于指定线段的终点。my_plane.c2p
方法将笛卡尔坐标 (-2, my_function.underlying_function(-2))
转换为平面 my_plane
上的实际坐标,作为线段的终点。stroke_color = YELLOW
stroke_color
是 Line
类的一个参数,用于指定线段的颜色。YELLOW
是一个预定义的颜色常量,代表黄色。stroke_width = 10
stroke_width
是 Line
类的一个参数,用于指定线段的宽度。这里将线段的宽度设置为 10。Graphing
from manim import *
class Graphing(Scene):
def construct(self):
my_plane = NumberPlane(x_range=[-6,6],x_length= 5,
y_range = [-10,10],y_length = 5)
my_plane.add_coordinates()
my_plane.shift(RIGHT*3)
# 添加函数
my_function = my_plane.plot(lambda x: 0.1*x*(x-5)*(x+5),
x_range=[-6,6],color = GREEN_B)
# 添加阴影面积
area1 = my_plane.get_riemann_rectangles(my_function,x_range=[-5,5],color=[RED,GREEN_B],
dx=0.1,stroke_width=0,
stroke_color=RED,fill_opacity=0.7).shift(LEFT*6)
area = my_plane.get_area(graph = my_function,x_range = [-5,5],color = [BLUE,YELLOW,RED])
label = MathTex("f(x) = 0.1x(x-5)(x+5)").next_to(my_plane,UP,buff=0.2)
horiz_line = Line(
start = my_plane.c2p(0,my_function.underlying_function(-2)),
end = my_plane.c2p(-2,my_function.underlying_function(-2)),
stroke_color = GREEN_B,stroke_width = 10
)
self.play(DrawBorderThenFill(my_plane))
self.play(Create(my_function),Write(label))
self.play(FadeIn(area))
self.play(Create(horiz_line))
group = VGroup(my_plane,my_function,label,horiz_line).copy().shift(LEFT*6)
self.play(FadeIn(group))
self.play(FadeIn(area1))
CoordinateSystem
from manim import *
class CoordinateSystem(Scene):
def construct(self):
plane = NumberPlane(
x_range = [-4,4,1],x_length=4,
y_range = [0,20,5],y_length=4,
background_line_style = {"stroke_color": GREY, "stroke_width": 0.5, "stroke_opacity": 0.5}
).add_coordinates()
plane.shift(LEFT*3+DOWN*1.5)
plane_graph = plane.plot(lambda x: x**2, x_range = [-4,4],color=RED)
plane_graph_area = plane.get_riemann_rectangles(
plane_graph,
x_range = [-4,4],
dx = 0.5,
stroke_width = 0,
stroke_color = GREY,
fill_opacity = 0.5,
color = GREY
)
axes = Axes(x_range = [-4,4,1],x_length=4,
y_range=[-20,20,5],y_length = 4).add_coordinates()
axes.shift(RIGHT*3+DOWN*1.5)
axes_graph = axes.plot(lambda x: 2*x,x_range = [-4,4],color=RED)
v_line = axes.get_vertical_lines_to_graph(
graph=axes_graph,
x_range=[-3,3],
num_lines=12
)
self.play(Write(plane),Create(axes))
self.play(Create(plane_graph),Create(axes_graph),run_time = 1)
self.add(plane_graph_area,v_line)
学习前三个案例相信你第四个一定能看懂
Tute2
from manim import *
import numpy as np
class Tute2(Scene):
def construct(self):
e = ValueTracker(0.01)
plane = PolarPlane(radius_max=3).add_coordinates()
plane.shift(LEFT * 2)
graph1 = always_redraw(
lambda: ParametricFunction(
lambda t: plane.polar_to_point(2 * np.sin(3 * t), t),
t_range=[0, e.get_value()],
color=GREEN
)
)
dot1 = always_redraw(
lambda: Dot(fill_color=GREEN, fill_opacity=0.8).move_to(graph1.get_end())
)
axes = Axes(
x_range=[0, 4, 1],
x_length=3,
y_range=[-3, 3, 1],
y_length=3
).shift(RIGHT * 4)
axes.add_coordinates()
graph2 = always_redraw(
lambda: axes.plot(
lambda x: 2 * np.sin(3 * x),
x_range=[0, e.get_value()],
use_smoothing=False
).set_color(GREEN)
)
dot2 = always_redraw(
lambda: Dot(fill_color=GREEN, fill_opacity=0.8)
.scale(0.8)
.move_to(axes.c2p(e.get_value(), 2 * np.sin(3 * e.get_value())))
)
title = MathTex("f(\\theta) = 2\\sin(3\\theta)", color=GREEN).next_to(axes, UP, buff=0.2)
# 分别添加 Mobject
# self.add(plane, axes, title)
# 播放 LaggedStart 动画
self.play(LaggedStart(Write(plane), Create(axes), Write(title), run_time=3, lag_ratio=0.5))
self.add(graph1, graph2, dot1, dot2)
self.play(e.animate.set_value(PI), run_time=10, rate_func=linear)
self.wait()
e = ValueTracker(0.01)
ValueTracker
是 manim
中的一个类,用于跟踪一个数值的变化。这里创建了一个初始值为 0.01
的值跟踪器 e
,后续会通过改变 e
的值来控制函数的绘制过程。plane = PolarPlane(radius_max=3).add_coordinates()
plane.shift(LEFT * 2)
PolarPlane(radius_max=3)
:创建一个极坐标平面,最大半径为 3
。add_coordinates()
:为极坐标平面添加坐标。plane.shift(LEFT * 2)
:将极坐标平面向左移动 2
个单位。graph1 = always_redraw(
lambda: ParametricFunction(
lambda t: plane.polar_to_point(2 * np.sin(3 * t), t),
t_range=[0, e.get_value()],
color=GREEN
)
)
always_redraw
:这是 manim
中的一个函数,用于创建一个始终重新绘制的 Mobject。当 e
的值发生变化时,graph1
会自动重新绘制。
ParametricFunction
:用于创建参数化函数图像。
lambda t: plane.polar_to_point(2 * np.sin(3 * t), t)
:定义参数化函数,将极坐标 ((r = 2\sin(3\theta), \theta)) 转换为平面上的点。t_range=[0, e.get_value()]
:指定参数 t
的范围,从 0
到 e
的当前值。color=GREEN
:设置图像的颜色为绿色。dot1 = always_redraw(
lambda: Dot(fill_color=GREEN, fill_opacity=0.8).move_to(graph1.get_end())
)
Dot
:创建一个点。fill_color=GREEN
:设置点的填充颜色为绿色。fill_opacity=0.8
:设置点的填充透明度为 0.8
。move_to(graph1.get_end())
:将点移动到 graph1
的末端。axes = Axes(
x_range=[0, 4, 1],
x_length=3,
y_range=[-3, 3, 1],
y_length=3
).shift(RIGHT * 4)
axes.add_coordinates()
Axes
:创建一个直角坐标系。
x_range=[0, 4, 1]
:指定 x 轴的范围从 0
到 4
,刻度间隔为 1
。x_length=3
:指定 x 轴的长度为 3
。y_range=[-3, 3, 1]
:指定 y 轴的范围从 -3
到 3
,刻度间隔为 1
。y_length=3
:指定 y 轴的长度为 3
。axes.shift(RIGHT * 4)
:将直角坐标系向右移动 4
个单位。
axes.add_coordinates()
:为直角坐标系添加坐标。
graph2 = always_redraw(
lambda: axes.plot(
lambda x: 2 * np.sin(3 * x),
x_range=[0, e.get_value()],
use_smoothing=False
).set_color(GREEN)
)
axes.plot
:在直角坐标系上绘制函数图像。
lambda x: 2 * np.sin(3 * x)
:定义函数 (y = 2\sin(3x))。x_range=[0, e.get_value()]
:指定 x 的范围从 0
到 e
的当前值。use_smoothing=False
:不使用平滑处理。set_color(GREEN)
:设置图像的颜色为绿色。
dot2 = always_redraw(
lambda: Dot(fill_color=GREEN, fill_opacity=0.8)
.scale(0.8)
.move_to(axes.c2p(e.get_value(), 2 * np.sin(3 * e.get_value())))
)
Dot
:创建一个点。fill_color=GREEN
:设置点的填充颜色为绿色。fill_opacity=0.8
:设置点的填充透明度为 0.8
。.scale(0.8)
:将点的大小缩小为原来的 0.8
倍。move_to(axes.c2p(e.get_value(), 2 * np.sin(3 * e.get_value())))
:将点移动到直角坐标系中 ((e, 2\sin(3e))) 的位置。title = MathTex("f(\\theta) = 2\\sin(3\\theta)", color=GREEN).next_to(axes, UP, buff=0.2)
MathTex
:创建一个数学公式对象。"f(\\theta) = 2\\sin(3\\theta)"
:定义数学公式。color=GREEN
:设置公式的颜色为绿色。next_to(axes, UP, buff=0.2)
:将标题放置在直角坐标系的上方,距离为 0.2
。self.play(LaggedStart(Write(plane), Create(axes), Write(title), run_time=3, lag_ratio=0.5))
self.play
:播放动画。
LaggedStart
:用于创建一个延迟开始的动画序列。
Write(plane)
:以书写的方式显示极坐标平面。Create(axes)
:创建直角坐标系。Write(title)
:以书写的方式显示标题。run_time=3
:动画的总时长为 3
秒。lag_ratio=0.5
:每个动画之间的延迟比例为 0.5
。self.add(graph1, graph2, dot1, dot2)
self.add
:将 graph1
、graph2
、dot1
和 dot2
添加到场景中。self.play(e.animate.set_value(PI), run_time=10, rate_func=linear)
e.animate.set_value(PI)
:将 e
的值从当前值动画地设置为 PI
。run_time=10
:动画的时长为 10
秒。rate_func=linear
:使用线性的动画速率函数。