mirror of
https://github.com/3b1b/manim.git
synced 2025-07-28 12:32:36 +08:00
Added example scenes for graphing and using CoordinateSystems
This commit is contained in:
@ -67,48 +67,6 @@ class OpeningManimExample(Scene):
|
|||||||
self.wait(2)
|
self.wait(2)
|
||||||
|
|
||||||
|
|
||||||
class InteractiveDevlopment(Scene):
|
|
||||||
def construct(self):
|
|
||||||
circle = Circle()
|
|
||||||
circle.set_fill(BLUE, opacity=0.5)
|
|
||||||
circle.set_stroke(BLUE_E, width=4)
|
|
||||||
square = Square()
|
|
||||||
|
|
||||||
self.play(ShowCreation(square))
|
|
||||||
self.wait()
|
|
||||||
|
|
||||||
# This opens an iPython termnial where you can keep writing
|
|
||||||
# lines as if they were part of this construct method
|
|
||||||
self.embed()
|
|
||||||
# Try copying and pasting some of the lines below into
|
|
||||||
# the interactive shell
|
|
||||||
self.play(ReplacementTransform(square, circle))
|
|
||||||
self.wait()
|
|
||||||
self.play(circle.stretch, 4, 0)
|
|
||||||
self.play(Rotate(circle, 90 * DEGREES))
|
|
||||||
self.play(circle.shift, 2 * RIGHT, circle.scale, 0.25)
|
|
||||||
|
|
||||||
text = Text("""
|
|
||||||
In general, using the interactive shell
|
|
||||||
is very helpful when developing new scenes
|
|
||||||
""")
|
|
||||||
self.play(Write(text))
|
|
||||||
|
|
||||||
# In the interactive shell, you can just type
|
|
||||||
# play, add, remove, clear, wait, save_state and restore,
|
|
||||||
# instead of self.play, self.add, self.remove, etc.
|
|
||||||
|
|
||||||
# To interact with the window, type touch(). You can then
|
|
||||||
# scroll in the window, or zoom by holding down 'z' while scrolling,
|
|
||||||
# and change camera perspective by holding down 'd' while moving
|
|
||||||
# the mouse. Press 'r' to reset to the standard camera position.
|
|
||||||
# Press 'q' to stop interacting with the window and go back to
|
|
||||||
# typing new commands into the shell.
|
|
||||||
|
|
||||||
# In principle you can customize a scene
|
|
||||||
always(circle.move_to, self.mouse_point)
|
|
||||||
|
|
||||||
|
|
||||||
class AnimatingMethods(Scene):
|
class AnimatingMethods(Scene):
|
||||||
def construct(self):
|
def construct(self):
|
||||||
grid = Tex(r"\pi").get_grid(10, 10, height=4)
|
grid = Tex(r"\pi").get_grid(10, 10, height=4)
|
||||||
@ -121,7 +79,10 @@ class AnimatingMethods(Scene):
|
|||||||
# to the left, but the following line animates that motion.
|
# to the left, but the following line animates that motion.
|
||||||
self.play(grid.shift, 2 * LEFT)
|
self.play(grid.shift, 2 * LEFT)
|
||||||
# The same applies for any method, including those setting colors.
|
# The same applies for any method, including those setting colors.
|
||||||
|
self.play(grid.set_color, YELLOW)
|
||||||
|
self.wait()
|
||||||
self.play(grid.set_submobject_colors_by_gradient, BLUE, GREEN)
|
self.play(grid.set_submobject_colors_by_gradient, BLUE, GREEN)
|
||||||
|
self.wait()
|
||||||
self.play(grid.set_height, TAU - MED_SMALL_BUFF)
|
self.play(grid.set_height, TAU - MED_SMALL_BUFF)
|
||||||
self.wait()
|
self.wait()
|
||||||
|
|
||||||
@ -361,6 +322,166 @@ class UpdatersExample(Scene):
|
|||||||
self.wait(4 * PI)
|
self.wait(4 * PI)
|
||||||
|
|
||||||
|
|
||||||
|
class GraphExample(Scene):
|
||||||
|
def construct(self):
|
||||||
|
axes = Axes((-3, 10), (-1, 8))
|
||||||
|
axes.add_coordinate_labels()
|
||||||
|
|
||||||
|
self.play(Write(axes, lag_ratio=0.01, run_time=1))
|
||||||
|
|
||||||
|
# Axes.get_graph will return the graph of a function
|
||||||
|
sin_graph = axes.get_graph(
|
||||||
|
lambda x: 2 * math.sin(x),
|
||||||
|
color=BLUE,
|
||||||
|
)
|
||||||
|
# By default, it draws it so as to somewhat smoothly interpolate
|
||||||
|
# between sampled points (x, f(x)). If the graph is meant to have
|
||||||
|
# a corner, though, you can set use_smoothing to False
|
||||||
|
relu_graph = axes.get_graph(
|
||||||
|
lambda x: max(x, 0),
|
||||||
|
use_smoothing=False,
|
||||||
|
color=YELLOW,
|
||||||
|
)
|
||||||
|
# For discontinuous functions, you can specify the point of
|
||||||
|
# discontinuity so that it does not try to draw over the gap.
|
||||||
|
step_graph = axes.get_graph(
|
||||||
|
lambda x: 2.0 if x > 3 else 1.0,
|
||||||
|
discontinuities=[3],
|
||||||
|
color=GREEN,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Axes.get_graph_label takes in either a string or a mobject.
|
||||||
|
# If it's a string, it treats it as a LaTeX expression. By default
|
||||||
|
# it places the label next to the graph near the right side, and
|
||||||
|
# has it match the color of the graph
|
||||||
|
sin_label = axes.get_graph_label(sin_graph, "\\sin(x)")
|
||||||
|
relu_label = axes.get_graph_label(relu_graph, Text("ReLU"))
|
||||||
|
step_label = axes.get_graph_label(step_graph, Text("Step"), x=4)
|
||||||
|
|
||||||
|
self.play(
|
||||||
|
ShowCreation(sin_graph),
|
||||||
|
FadeIn(sin_label, RIGHT),
|
||||||
|
)
|
||||||
|
self.wait(2)
|
||||||
|
self.play(
|
||||||
|
ReplacementTransform(sin_graph, relu_graph),
|
||||||
|
FadeTransform(sin_label, relu_label),
|
||||||
|
)
|
||||||
|
self.wait()
|
||||||
|
self.play(
|
||||||
|
ReplacementTransform(relu_graph, step_graph),
|
||||||
|
FadeTransform(relu_label, step_label),
|
||||||
|
)
|
||||||
|
self.wait()
|
||||||
|
|
||||||
|
parabola = axes.get_graph(lambda x: 0.25 * x**2)
|
||||||
|
parabola.set_stroke(BLUE)
|
||||||
|
self.play(
|
||||||
|
FadeOut(step_graph),
|
||||||
|
FadeOut(step_label),
|
||||||
|
ShowCreation(parabola)
|
||||||
|
)
|
||||||
|
self.wait()
|
||||||
|
|
||||||
|
# You can use axes.input_to_graph_point, abbreviated
|
||||||
|
# to axes.i2gp, to find a particular point on a graph
|
||||||
|
dot = Dot(color=RED)
|
||||||
|
dot.move_to(axes.i2gp(2, parabola))
|
||||||
|
self.play(FadeIn(dot, scale=0.5))
|
||||||
|
|
||||||
|
# A value tracker lets us animate a parameter, usually
|
||||||
|
# with the intent of having other mobjects update based
|
||||||
|
# on the parameter
|
||||||
|
x_tracker = ValueTracker(2)
|
||||||
|
f_always(
|
||||||
|
dot.move_to,
|
||||||
|
lambda: axes.i2gp(x_tracker.get_value(), parabola)
|
||||||
|
)
|
||||||
|
|
||||||
|
self.play(x_tracker.set_value, 4, run_time=3)
|
||||||
|
self.play(x_tracker.set_value, -2, run_time=3)
|
||||||
|
self.wait()
|
||||||
|
|
||||||
|
|
||||||
|
class CoordinateSystemExample(Scene):
|
||||||
|
def construct(self):
|
||||||
|
axes = Axes(
|
||||||
|
# x-axis ranges from -1 to 10, with a default step size of 1
|
||||||
|
x_range=(-1, 10),
|
||||||
|
# y-axis ranges from -2 to 10 with a step size of 0.5
|
||||||
|
y_range=(-2, 2, 0.5),
|
||||||
|
# The axes will be stretched so as to match the specified
|
||||||
|
# height and width
|
||||||
|
height=6,
|
||||||
|
width=10,
|
||||||
|
# Axes is made of two NumberLine mobjects. You can specify
|
||||||
|
# their configuration with axis_config
|
||||||
|
axis_config={
|
||||||
|
"stroke_color": GREY_A,
|
||||||
|
"stroke_width": 2,
|
||||||
|
},
|
||||||
|
# Alternatively, you can specify configuration for just one
|
||||||
|
# of them, like this.
|
||||||
|
y_axis_config={
|
||||||
|
"include_tip": False,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
# Keyword arguments of add_coordinate_labels can be used to
|
||||||
|
# configure the DecimalNumber mobjects which it creates and
|
||||||
|
# adds to the axes
|
||||||
|
axes.add_coordinate_labels(
|
||||||
|
font_size=20,
|
||||||
|
num_decimal_places=1,
|
||||||
|
)
|
||||||
|
self.add(axes)
|
||||||
|
|
||||||
|
# Axes descends from the CoordinateSystem class, meaning
|
||||||
|
# you can call call axes.coords_to_point, abbreviated to
|
||||||
|
# axes.c2p, to associate a set of coordinates with a point,
|
||||||
|
# like so:
|
||||||
|
dot = Dot(color=RED)
|
||||||
|
dot.move_to(axes.c2p(0, 0))
|
||||||
|
self.play(FadeIn(dot, scale=0.5))
|
||||||
|
self.play(dot.move_to, axes.c2p(3, 2))
|
||||||
|
self.wait()
|
||||||
|
self.play(dot.move_to, axes.c2p(5, 0.5))
|
||||||
|
self.wait()
|
||||||
|
|
||||||
|
# Similarly, you can call axes.point_to_coords, or axes.p2c
|
||||||
|
# print(axes.p2c(dot.get_center()))
|
||||||
|
|
||||||
|
# We can draw lines from the axes to better mark the coordinates
|
||||||
|
# of a given point.
|
||||||
|
# Here, the always_redraw command means that on each new frame
|
||||||
|
# the lines will be redrawn
|
||||||
|
h_line = always_redraw(lambda: axes.get_h_line(dot.get_left()))
|
||||||
|
v_line = always_redraw(lambda: axes.get_v_line(dot.get_bottom()))
|
||||||
|
|
||||||
|
self.play(
|
||||||
|
ShowCreation(h_line),
|
||||||
|
ShowCreation(v_line),
|
||||||
|
)
|
||||||
|
self.play(dot.move_to, axes.c2p(3, -2))
|
||||||
|
self.wait()
|
||||||
|
self.play(dot.move_to, axes.c2p(1, 1))
|
||||||
|
self.wait()
|
||||||
|
|
||||||
|
# If we tie the dot to a particular set of coordinates, notice
|
||||||
|
# that as we move the axes around it respects the coordinate
|
||||||
|
# system defined by them.
|
||||||
|
f_always(dot.move_to, lambda: axes.c2p(1, 1))
|
||||||
|
self.play(
|
||||||
|
axes.scale, 0.75,
|
||||||
|
axes.to_corner, UL,
|
||||||
|
run_time=2,
|
||||||
|
)
|
||||||
|
self.wait()
|
||||||
|
self.play(FadeOut(VGroup(axes, dot, h_line, v_line)))
|
||||||
|
|
||||||
|
# Other coordinate systems you can play around with include
|
||||||
|
# ThreeDAxes, NumberPlane, and ComplexPlane.
|
||||||
|
|
||||||
|
|
||||||
class SurfaceExample(Scene):
|
class SurfaceExample(Scene):
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
"camera_class": ThreeDCamera,
|
"camera_class": ThreeDCamera,
|
||||||
@ -452,6 +573,52 @@ class SurfaceExample(Scene):
|
|||||||
self.wait()
|
self.wait()
|
||||||
|
|
||||||
|
|
||||||
|
class InteractiveDevlopment(Scene):
|
||||||
|
def construct(self):
|
||||||
|
circle = Circle()
|
||||||
|
circle.set_fill(BLUE, opacity=0.5)
|
||||||
|
circle.set_stroke(BLUE_E, width=4)
|
||||||
|
square = Square()
|
||||||
|
|
||||||
|
self.play(ShowCreation(square))
|
||||||
|
self.wait()
|
||||||
|
|
||||||
|
# This opens an iPython termnial where you can keep writing
|
||||||
|
# lines as if they were part of this construct method.
|
||||||
|
# In particular, 'square', 'circle' and 'self' will all be
|
||||||
|
# part of the local namespace in that terminal.
|
||||||
|
self.embed()
|
||||||
|
|
||||||
|
# Try copying and pasting some of the lines below into
|
||||||
|
# the interactive shell
|
||||||
|
self.play(ReplacementTransform(square, circle))
|
||||||
|
self.wait()
|
||||||
|
self.play(circle.stretch, 4, 0)
|
||||||
|
self.play(Rotate(circle, 90 * DEGREES))
|
||||||
|
self.play(circle.shift, 2 * RIGHT, circle.scale, 0.25)
|
||||||
|
|
||||||
|
text = Text("""
|
||||||
|
In general, using the interactive shell
|
||||||
|
is very helpful when developing new scenes
|
||||||
|
""")
|
||||||
|
self.play(Write(text))
|
||||||
|
|
||||||
|
# In the interactive shell, you can just type
|
||||||
|
# play, add, remove, clear, wait, save_state and restore,
|
||||||
|
# instead of self.play, self.add, self.remove, etc.
|
||||||
|
|
||||||
|
# To interact with the window, type touch(). You can then
|
||||||
|
# scroll in the window, or zoom by holding down 'z' while scrolling,
|
||||||
|
# and change camera perspective by holding down 'd' while moving
|
||||||
|
# the mouse. Press 'r' to reset to the standard camera position.
|
||||||
|
# Press 'q' to stop interacting with the window and go back to
|
||||||
|
# typing new commands into the shell.
|
||||||
|
|
||||||
|
# In principle you can customize a scene to be responsive to
|
||||||
|
# mouse and keyboard interactions
|
||||||
|
always(circle.move_to, self.mouse_point)
|
||||||
|
|
||||||
|
|
||||||
class ControlsExample(Scene):
|
class ControlsExample(Scene):
|
||||||
def setup(self):
|
def setup(self):
|
||||||
self.textbox = Textbox()
|
self.textbox = Textbox()
|
||||||
|
Reference in New Issue
Block a user