mirror of
https://github.com/3b1b/manim.git
synced 2025-07-28 04:23:16 +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)
|
||||
|
||||
|
||||
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):
|
||||
def construct(self):
|
||||
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.
|
||||
self.play(grid.shift, 2 * LEFT)
|
||||
# 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.wait()
|
||||
self.play(grid.set_height, TAU - MED_SMALL_BUFF)
|
||||
self.wait()
|
||||
|
||||
@ -361,6 +322,166 @@ class UpdatersExample(Scene):
|
||||
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):
|
||||
CONFIG = {
|
||||
"camera_class": ThreeDCamera,
|
||||
@ -452,6 +573,52 @@ class SurfaceExample(Scene):
|
||||
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):
|
||||
def setup(self):
|
||||
self.textbox = Textbox()
|
||||
|
Reference in New Issue
Block a user