2021-01-25 19:53:44 +08:00
Example Scenes
==============
2021-01-24 23:22:11 +08:00
2021-02-10 09:10:31 -06:00
After understanding the previous knowledge, we can understand more scenes.
Many example scenes are given in `` example_scenes.py `` , let's start with
2021-01-26 20:52:17 +08:00
the simplest and one by one.
2021-02-10 11:02:18 +08:00
InteractiveDevlopment
---------------------
2021-01-26 20:52:17 +08:00
2021-02-10 11:02:18 +08:00
.. manim-example :: InteractiveDevlopment
:media: ../_static/example_scenes/InteractiveDevlopment.mp4
2021-01-26 20:52:17 +08:00
from manimlib.imports import *
2021-02-10 11:02:18 +08:00
class InteractiveDevlopment(Scene):
2021-01-26 20:52:17 +08:00
def construct(self):
circle = Circle()
circle.set_fill(BLUE, opacity=0.5)
circle.set_stroke(BLUE_E, width=4)
square = Square()
2021-02-10 09:10:31 -06:00
2021-01-26 20:52:17 +08:00
self.play(ShowCreation(square))
self.wait()
2021-02-10 11:02:18 +08:00
# 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
2021-01-26 20:52:17 +08:00
self.play(ReplacementTransform(square, circle))
self.wait()
2021-02-10 09:40:16 -06:00
self.play(circle.animate.stretch(4, 0))
2021-02-10 11:02:18 +08:00
self.play(Rotate(circle, 90 * DEGREES))
2021-02-10 15:38:31 -06:00
self.play(circle.animate.shift(2 * RIGHT), circle.animate.scale(0.25))
2021-02-10 11:02:18 +08:00
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)
2021-01-26 20:52:17 +08:00
2021-02-10 11:02:18 +08:00
This scene is similar to what we wrote in :doc: `quickstart` .
And how to interact has been written in the comments.
No more explanation here.
2021-01-26 20:52:17 +08:00
2021-01-31 22:03:53 +08:00
AnimatingMethods
----------------
2021-01-26 20:52:17 +08:00
2021-01-31 22:03:53 +08:00
.. manim-example :: AnimatingMethods
:media: ../_static/example_scenes/AnimatingMethods.mp4
2021-01-24 23:22:11 +08:00
2021-01-31 22:03:53 +08:00
class AnimatingMethods(Scene):
def construct(self):
grid = Tex(r"\pi").get_grid(10, 10, height=4)
self.add(grid)
2021-02-10 09:10:31 -06:00
# You can animate the application of mobject methods with the
# ".animate" syntax:
self.play(grid.animate.shift(LEFT))
# Alternatively, you can use the older syntax by passing the
# method and then the arguments to the scene's "play" function:
self.play(grid.shift, LEFT)
# Both of those will interpolate between the mobject's initial
# state and whatever happens when you apply that method.
# For this example, calling grid.shift(LEFT) would shift the
# grid one unit to the left, but both of the previous calls to
# "self.play" animate that motion.
2021-01-31 22:03:53 +08:00
# The same applies for any method, including those setting colors.
2021-02-10 09:10:31 -06:00
self.play(grid.animate.set_color(YELLOW))
self.wait()
self.play(grid.animate.set_submobject_colors_by_gradient(BLUE, GREEN))
self.wait()
self.play(grid.animate.set_height(TAU - MED_SMALL_BUFF))
2021-01-31 22:03:53 +08:00
self.wait()
# The method Mobject.apply_complex_function lets you apply arbitrary
# complex functions, treating the points defining the mobject as
# complex numbers.
2021-02-10 09:10:31 -06:00
self.play(grid.animate.apply_complex_function(np.exp), run_time=5)
2021-01-31 22:03:53 +08:00
self.wait()
# Even more generally, you could apply Mobject.apply_function,
# which takes in functions form R^3 to R^3
self.play(
2021-02-10 09:10:31 -06:00
grid.animate.apply_function(
lambda p: [
p[0] + 0.5 * math.sin(p[1]),
p[1] + 0.5 * math.sin(p[0]),
p[2]
]
),
2021-01-31 22:03:53 +08:00
run_time=5,
)
self.wait()
2021-02-10 09:10:31 -06:00
The new usage in this scene is `` .get_grid() `` and `` self.play(mob.animate.method(args)) `` .
2021-01-26 20:52:17 +08:00
2021-01-31 22:03:53 +08:00
- `` .get_grid() `` method will return a new mobject containing multiple copies of this one arranged in a grid.
2021-02-10 09:10:31 -06:00
- `` self.play(mob.animate.method(args)) `` animates the method, and the details are in the comments above.
2021-01-26 20:52:17 +08:00
TextExample
-----------
.. manim-example :: TextExample
2021-01-31 22:03:53 +08:00
:media: ../_static/example_scenes/TextExample.mp4
2021-01-26 20:52:17 +08:00
class TextExample(Scene):
def construct(self):
text = Text("Here is a text", font="Consolas", font_size=90)
difference = Text(
"""
The most important difference between Text and TexText is that\n
you can change the font more easily, but can't use the LaTeX grammar
""",
font="Arial", font_size=24,
t2c={"Text": BLUE, "TexText": BLUE, "LaTeX": ORANGE}
)
VGroup(text, difference).arrange(DOWN, buff=1)
self.play(Write(text))
self.play(FadeIn(difference, UP))
self.wait(3)
fonts = Text(
"And you can also set the font according to different words",
font="Arial",
t2f={"font": "Consolas", "words": "Consolas"},
t2c={"font": BLUE, "words": GREEN}
)
slant = Text(
"And the same as slant and weight",
font="Consolas",
t2s={"slant": ITALIC},
t2w={"weight": BOLD},
t2c={"slant": ORANGE, "weight": RED}
)
VGroup(fonts, slant).arrange(DOWN, buff=0.8)
self.play(FadeOut(text), FadeOut(difference, shift=DOWN))
self.play(Write(fonts))
self.wait()
self.play(Write(slant))
self.wait()
The new classes in this scene are `` Text `` , `` VGroup `` , `` Write `` , `` FadeIn `` and `` FadeOut `` .
- `` Text `` can create text, define fonts, etc. The usage ais clearly reflected in the above examples.
- `` VGroup `` can put multiple `` VMobject `` together as a whole. In the example, the `` .arrange() `` method is called to arrange the sub-mobjects in sequence downward (`` DOWN `` ), and the spacing is `` buff `` .
- `` Write `` is an animation that shows similar writing effects.
- `` FadeIn `` fades the object in, the second parameter indicates the direction of the fade in.
- `` FadeOut `` fades out the object, the second parameter indicates the direction of the fade out.
TexTransformExample
-------------------
.. manim-example :: TexTransformExample
2021-01-31 22:03:53 +08:00
:media: ../_static/example_scenes/TexTransformExample.mp4
2021-01-26 20:52:17 +08:00
class TexTransformExample(Scene):
def construct(self):
2021-01-30 22:20:37 -08:00
to_isolate = ["B", "C", "=", "(", ")"]
2021-01-26 20:52:17 +08:00
lines = VGroup(
2021-01-30 22:20:37 -08:00
# Surrounding substrings with double braces
# will ensure that those parts are separated
# out in the Tex. For example, here the
# Tex will have 5 submobjects, corresponding
# to the strings [A^2, +, B^2, =, C^2]
2021-01-26 20:52:17 +08:00
Tex("{{A^2}} + {{B^2}} = {{C^2}}"),
Tex("{{A^2}} = {{C^2}} - {{B^2}}"),
2021-01-30 22:20:37 -08:00
# Alternatively, you can pass in the keyword argument
# "isolate" with a list of strings that should be out as
# their own submobject. So both lines below are equivalent
# to what you'd get by wrapping every instance of "B", "C"
# "=", "(" and ")" with double braces
Tex("{{A^2}} = (C + B)(C - B)", isolate=to_isolate),
Tex("A = \\sqrt{(C + B)(C - B)}", isolate=to_isolate)
2021-01-26 20:52:17 +08:00
)
lines.arrange(DOWN, buff=LARGE_BUFF)
for line in lines:
line.set_color_by_tex_to_color_map({
"A": BLUE,
"B": TEAL,
"C": GREEN,
})
play_kw = {"run_time": 2}
self.add(lines[0])
2021-01-30 22:20:37 -08:00
# The animation TransformMatchingTex will line up parts
# of the source and target which have matching tex strings.
# Here, giving it a little path_arc makes each part sort of
# rotate into their final positions, which feels appropriate
# for the idea of rearranging an equation
2021-01-26 20:52:17 +08:00
self.play(
TransformMatchingTex(
lines[0].copy(), lines[1],
path_arc=90 * DEGREES,
),
**play_kw
)
self.wait()
2021-01-30 22:20:37 -08:00
# Now, we could try this again on the next line...
2021-01-26 20:52:17 +08:00
self.play(
TransformMatchingTex(lines[1].copy(), lines[2]),
**play_kw
)
self.wait()
2021-01-30 22:20:37 -08:00
# ...and this looks nice enough, but since there's no tex
# in lines[2] which matches "C^2" or "B^2", those terms fade
# out to nothing while the C and B terms fade in from nothing.
# If, however, we want the C^2 to go to C, and B^2 to go to B,
# we can specify that with a key map.
2021-01-26 20:52:17 +08:00
self.play(FadeOut(lines[2]))
self.play(
TransformMatchingTex(
lines[1].copy(), lines[2],
key_map={
"C^2": "C",
"B^2": "B",
}
),
**play_kw
)
self.wait()
2021-01-30 22:20:37 -08:00
# And to finish off, a simple TransformMatchingShapes would work
# just fine. But perhaps we want that exponent on A^2 to transform into
# the square root symbol. At the moment, lines[2] treats the expression
# A^2 as a unit, so we might create a new version of the same line which
# separates out just the A. This way, when TransformMatchingTex lines up
# all matching parts, the only mismatch will be between the "^2" from
# new_line2 and the "\sqrt" from the final line. By passing in,
# transform_mismatches=True, it will transform this "^2" part into
# the "\sqrt" part.
new_line2 = Tex("{{A}}^2 = (C + B)(C - B)", isolate=to_isolate)
new_line2.replace(lines[2])
new_line2.match_style(lines[2])
2021-01-26 20:52:17 +08:00
self.play(
TransformMatchingTex(
2021-01-30 22:20:37 -08:00
new_line2, lines[3],
transform_mismatches=True,
2021-01-26 20:52:17 +08:00
),
**play_kw
)
self.wait(3)
self.play(FadeOut(lines, RIGHT))
2021-01-30 22:20:37 -08:00
# Alternatively, if you don't want to think about breaking up
# the tex strings deliberately, you can TransformMatchingShapes,
# which will try to line up all pieces of a source mobject with
# those of a target, regardless of the submobject hierarchy in
# each one, according to whether those pieces have the same
# shape (as best it can).
source = Text("the morse code", height=1)
target = Text("here come dots", height=1)
2021-01-26 20:52:17 +08:00
self.play(Write(source))
self.wait()
kw = {"run_time": 3, "path_arc": PI / 2}
self.play(TransformMatchingShapes(source, target, **kw))
self.wait()
self.play(TransformMatchingShapes(target, source, **kw))
self.wait()
The new classes in this scene are `` Tex `` , `` TexText `` , `` TransformMatchingTex ``
and `` TransformMatchingShapes `` .
- `` Tex `` uses LaTeX to create mathematical formulas.
- `` TexText `` uses LaTeX to create text.
- `` TransformMatchingTeX `` automatically transforms sub-objects according to the similarities and differences of tex in `` Tex `` .
- `` TransformMatchingShapes `` automatically transform sub-objects directly based on the similarities and differences of the object point sets.
UpdatersExample
---------------
.. manim-example :: UpdatersExample
2021-01-31 22:03:53 +08:00
:media: ../_static/example_scenes/UpdatersExample.mp4
2021-01-26 20:52:17 +08:00
class UpdatersExample(Scene):
def construct(self):
square = Square()
2021-01-30 22:20:37 -08:00
square.set_fill(BLUE_E, 1)
# On all all frames, the constructor Brace(square, UP) will
# be called, and the mobject brace will set its data to match
# that of the newly constructed object
brace = always_redraw(Brace, square, UP)
text, number = label = VGroup(
Text("Width = "),
DecimalNumber(
0,
show_ellipsis=True,
num_decimal_places=2,
include_sign=True,
)
)
label.arrange(RIGHT)
# This ensures that the method deicmal.next_to(square)
# is called on every frame
always(label.next_to, brace, UP)
# You could also write the following equivalent line
# label.add_updater(lambda m: m.next_to(brace, UP))
# If the argument itself might change, you can use f_always,
# for which the arguments following the initial Mobject method
# should be functions returning arguments to that method.
# The following line ensures thst decimal.set_value(square.get_y())
# is called every frame
f_always(number.set_value, square.get_width)
# You could also write the following equivalent line
# number.add_updater(lambda m: m.set_value(square.get_width()))
self.add(square, brace, label)
# Notice that the brace and label track with the square
2021-01-26 20:52:17 +08:00
self.play(
2021-02-10 09:10:31 -06:00
square.animate.scale(2),
2021-01-30 22:20:37 -08:00
rate_func=there_and_back,
run_time=2,
)
self.wait()
self.play(
2021-02-10 09:10:31 -06:00
square.set_width(5, stretch=True),
2021-01-26 20:52:17 +08:00
run_time=3,
)
2021-01-30 22:20:37 -08:00
self.wait()
self.play(
2021-02-10 09:10:31 -06:00
square.animate.set_width(2),
2021-01-30 22:20:37 -08:00
run_time=3
)
2021-01-26 20:52:17 +08:00
self.wait()
2021-01-30 22:20:37 -08:00
# In general, you can alway call Mobject.add_updater, and pass in
# a function that you want to be called on every frame. The function
# should take in either one argument, the mobject, or two arguments,
# the mobject and the amount of time since the last frame.
2021-01-26 20:52:17 +08:00
now = self.time
2021-01-30 22:20:37 -08:00
w0 = square.get_width()
2021-01-26 20:52:17 +08:00
square.add_updater(
2021-01-30 22:20:37 -08:00
lambda m: m.set_width(w0 * math.cos(self.time - now))
2021-01-26 20:52:17 +08:00
)
2021-01-30 22:20:37 -08:00
self.wait(4 * PI)
2021-01-26 20:52:17 +08:00
2021-02-10 09:10:31 -06:00
The new classes and usage in this scene are `` always_redraw() `` , `` DecimalNumber `` , `` .to_edge() `` ,
2021-01-31 22:03:53 +08:00
`` .center() `` , `` always() `` , `` f_always() `` , `` .set_y() `` and `` .add_updater() `` .
2021-01-26 20:52:17 +08:00
2021-01-31 22:03:53 +08:00
- `` always_redraw() `` function create a new mobject every frame.
- `` DecimalNumber `` is a variable number, speed it up by breaking it into `` Text `` characters.
2021-01-26 20:52:17 +08:00
- `` .to_edge() `` means to place the object on the edge of the screen.
- `` .center() `` means to place the object in the center of the screen.
- `` always(f, x) `` means that a certain function (`` f(x) `` ) is executed every frame.
- `` f_always(f, g) `` is similar to `` always `` , executed `` f(g()) `` every frame.
- `` .set_y() `` means to set the ordinate of the object on the screen.
- `` .add_updater() `` sets an update function for the object. For example: `` mob1.add_updater(lambda mob: mob.next_to(mob2)) `` means `` mob1.next_to(mob2) `` is executed every frame.
2021-02-10 11:02:18 +08:00
CoordinateSystemExample
-----------------------
.. manim-example :: CoordinateSystemExample
:media: ../_static/example_scenes/CoordinateSystemExample.mp4
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))
2021-02-10 09:40:16 -06:00
self.play(dot.animate.move_to(axes.c2p(3, 2)))
2021-02-10 11:02:18 +08:00
self.wait()
2021-02-10 09:40:16 -06:00
self.play(dot.animate.move_to(axes.c2p(5, 0.5)))
2021-02-10 11:02:18 +08:00
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),
)
2021-02-10 09:40:16 -06:00
self.play(dot.animate.move_to(axes.c2p(3, -2)))
2021-02-10 11:02:18 +08:00
self.wait()
2021-02-10 09:40:16 -06:00
self.play(dot.animate.move_to(axes.c2p(1, 1)))
2021-02-10 11:02:18 +08:00
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(
2021-02-10 09:40:16 -06:00
axes.animate.scale(0.75),
axes.animate.to_corner(UL),
2021-02-10 11:02:18 +08:00
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.
GraphExample
------------
.. manim-example :: GraphExample
:media: ../_static/example_scenes/GraphExample.mp4
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)
)
2021-02-10 09:40:16 -06:00
self.play(x_tracker.animate.set_value(4), run_time=3)
self.play(x_tracker.animate.set_value(-2), run_time=3)
2021-02-10 11:02:18 +08:00
self.wait()
2021-01-26 20:52:17 +08:00
SurfaceExample
--------------
.. manim-example :: SurfaceExample
2021-01-31 22:03:53 +08:00
:media: ../_static/example_scenes/SurfaceExample.mp4
2021-01-26 20:52:17 +08:00
class SurfaceExample(Scene):
CONFIG = {
"camera_class": ThreeDCamera,
}
def construct(self):
surface_text = Text("For 3d scenes, try using surfaces")
surface_text.fix_in_frame()
surface_text.to_edge(UP)
self.add(surface_text)
self.wait(0.1)
torus1 = Torus(r1=1, r2=1)
torus2 = Torus(r1=3, r2=1)
sphere = Sphere(radius=3, resolution=torus1.resolution)
# You can texture a surface with up to two images, which will
# be interpreted as the side towards the light, and away from
# the light. These can be either urls, or paths to a local file
# in whatever you've set as the image directory in
# the custom_defaults.yml file
# day_texture = "EarthTextureMap"
# night_texture = "NightEarthTextureMap"
day_texture = "https://upload.wikimedia.org/wikipedia/commons/thumb/4/4d/Whole_world_-_land_and_oceans.jpg/1280px-Whole_world_-_land_and_oceans.jpg"
night_texture = "https://upload.wikimedia.org/wikipedia/commons/thumb/b/ba/The_earth_at_night.jpg/1280px-The_earth_at_night.jpg"
surfaces = [
TexturedSurface(surface, day_texture, night_texture)
for surface in [sphere, torus1, torus2]
]
for mob in surfaces:
mob.shift(IN)
mob.mesh = SurfaceMesh(mob)
mob.mesh.set_stroke(BLUE, 1, opacity=0.5)
# Set perspective
frame = self.camera.frame
frame.set_euler_angles(
theta=-30 * DEGREES,
phi=70 * DEGREES,
)
surface = surfaces[0]
self.play(
FadeIn(surface),
ShowCreation(surface.mesh, lag_ratio=0.01, run_time=3),
)
for mob in surfaces:
mob.add(mob.mesh)
surface.save_state()
self.play(Rotate(surface, PI / 2), run_time=2)
for mob in surfaces[1:]:
mob.rotate(PI / 2)
self.play(
Transform(surface, surfaces[1]),
run_time=3
)
self.play(
Transform(surface, surfaces[2]),
# Move camera frame during the transition
2021-02-10 09:10:31 -06:00
frame.animate.increment_phi(-10 * DEGREES),
frame.animate.increment_theta(-20 * DEGREES),
2021-01-26 20:52:17 +08:00
run_time=3
)
# Add ambient rotation
frame.add_updater(lambda m, dt: m.increment_theta(-0.1 * dt))
# Play around with where the light is
light_text = Text("You can move around the light source")
light_text.move_to(surface_text)
light_text.fix_in_frame()
self.play(FadeTransform(surface_text, light_text))
light = self.camera.light_source
self.add(light)
light.save_state()
2021-02-10 09:10:31 -06:00
self.play(light.animate.move_to(3 * IN), run_time=5)
self.play(light.animate.shift(10 * OUT), run_time=5)
2021-01-26 20:52:17 +08:00
drag_text = Text("Try moving the mouse while pressing d or s")
drag_text.move_to(light_text)
drag_text.fix_in_frame()
self.play(FadeTransform(light_text, drag_text))
self.wait()
2021-02-10 09:10:31 -06:00
This scene shows an example of using a three-dimensional surface, and
2021-01-26 20:52:17 +08:00
the related usage has been briefly described in the notes.
- `` .fix_in_frame() `` makes the object not change with the view angle of the screen, and is always displayed at a fixed position on the screen.
OpeningManimExample
-------------------
.. manim-example :: OpeningManimExample
2021-01-31 22:03:53 +08:00
:media: ../_static/example_scenes/OpeningManimExample.mp4
2021-01-26 20:52:17 +08:00
2021-02-05 15:27:48 -08:00
2021-01-26 20:52:17 +08:00
class OpeningManimExample(Scene):
def construct(self):
2021-02-05 15:27:48 -08:00
intro_words = Text("""
The original motivation for manim was to
better illustrate mathematical functions
as transformations.
""")
intro_words.to_edge(UP)
2021-01-26 20:52:17 +08:00
2021-02-05 15:27:48 -08:00
self.play(Write(intro_words))
self.wait(2)
2021-01-26 20:52:17 +08:00
2021-02-05 15:27:48 -08:00
# Linear transform
2021-01-26 20:52:17 +08:00
grid = NumberPlane((-10, 10), (-5, 5))
matrix = [[1, 1], [0, 1]]
2021-02-05 15:27:48 -08:00
linear_transform_words = VGroup(
2021-01-26 20:52:17 +08:00
Text("This is what the matrix"),
IntegerMatrix(matrix, include_background_rectangle=True),
Text("looks like")
)
2021-02-05 15:27:48 -08:00
linear_transform_words.arrange(RIGHT)
linear_transform_words.to_edge(UP)
linear_transform_words.set_stroke(BLACK, 10, background=True)
2021-01-26 20:52:17 +08:00
self.play(
2021-02-05 15:27:48 -08:00
ShowCreation(grid),
FadeTransform(intro_words, linear_transform_words)
2021-01-26 20:52:17 +08:00
)
2021-02-05 15:27:48 -08:00
self.wait()
2021-02-10 09:10:31 -06:00
self.play(grid.animate.apply_matrix(matrix), run_time=3)
2021-01-26 20:52:17 +08:00
self.wait()
2021-02-05 15:27:48 -08:00
# Complex map
c_grid = ComplexPlane()
moving_c_grid = c_grid.copy()
moving_c_grid.prepare_for_nonlinear_transform()
c_grid.set_stroke(BLUE_E, 1)
2021-02-06 11:06:38 -08:00
c_grid.add_coordinate_labels(font_size=24)
2021-02-05 15:27:48 -08:00
complex_map_words = TexText("""
Or thinking of the plane as $\\mathds{C}$,\\\\
this is the map $z \\rightarrow z^2$
""")
complex_map_words.to_corner(UR)
complex_map_words.set_stroke(BLACK, 5, background=True)
2021-01-26 20:52:17 +08:00
self.play(
2021-02-05 15:27:48 -08:00
FadeOut(grid),
Write(c_grid, run_time=3),
FadeIn(moving_c_grid),
FadeTransform(linear_transform_words, complex_map_words),
2021-01-26 20:52:17 +08:00
)
self.wait()
2021-02-05 15:27:48 -08:00
self.play(
2021-02-10 09:10:31 -06:00
moving_c_grid.animate.apply_complex_function(lambda z: z**2),
2021-02-05 15:27:48 -08:00
run_time=6,
)
self.wait(2)
2021-01-26 20:52:17 +08:00
This scene is a comprehensive application of a two-dimensional scene.
2021-02-10 09:10:31 -06:00
After seeing these scenes, you have already understood part of the
2021-01-26 20:52:17 +08:00
usage of manim. For more examples, see `the video code of 3b1b <https://github.com/3b1b/videos> `_ .