diff --git a/docs/example.py b/docs/example.py index b3c78ca0..279f0703 100644 --- a/docs/example.py +++ b/docs/example.py @@ -12,11 +12,11 @@ class SquareToCircle(Scene): self.play(ReplacementTransform(square, circle)) self.wait() # Try typing the following lines - # self.play(circle.stretch, 4, {"dim": 0}) + # self.play(circle.animate.stretch(4, dim=0)) # self.play(Rotate(circle, TAU / 4)) - # self.play(circle.shift, 2 * RIGHT, circle.scale, 0.25) + # self.play(circle.animate.shift(2 * RIGHT), circle.animate.scale(0.25)) # circle.insert_n_curves(10) - # self.play(circle.apply_complex_function, lambda z: z**2) + # self.play(circle.animate.apply_complex_function(lambda z: z**2)) class SquareToCircleEmbed(Scene): def construct(self): @@ -26,12 +26,12 @@ class SquareToCircleEmbed(Scene): self.add(circle) self.wait() - self.play(circle.stretch, 4, {"dim": 0}) + self.play(circle.animate.stretch(4, dim=0)) self.wait(1.5) self.play(Rotate(circle, TAU / 4)) self.wait(1.5) - self.play(circle.shift, 2 * RIGHT, circle.scale, 0.25) + self.play(circle.animate.shift(2 * RIGHT), circle.animate.scale(0.25)) self.wait(1.5) circle.insert_n_curves(10) - self.play(circle.apply_complex_function, lambda z: z**2) + self.play(circle.animate.apply_complex_function(lambda z: z**2)) self.wait(2) diff --git a/docs/source/_static/example_scenes/AnimatingMethods.mp4 b/docs/source/_static/example_scenes/AnimatingMethods.mp4 index 3f8e9668..e94a27fc 100644 Binary files a/docs/source/_static/example_scenes/AnimatingMethods.mp4 and b/docs/source/_static/example_scenes/AnimatingMethods.mp4 differ diff --git a/docs/source/getting_started/example_scenes.rst b/docs/source/getting_started/example_scenes.rst index e33efd0b..ce34eb32 100644 --- a/docs/source/getting_started/example_scenes.rst +++ b/docs/source/getting_started/example_scenes.rst @@ -1,8 +1,8 @@ Example Scenes ============== -After understanding the previous knowledge, we can understand more scenes. -Many example scenes are given in ``example_scenes.py``, let's start with +After understanding the previous knowledge, we can understand more scenes. +Many example scenes are given in ``example_scenes.py``, let's start with the simplest and one by one. SquareToCircle @@ -19,7 +19,7 @@ SquareToCircle circle.set_fill(BLUE, opacity=0.5) circle.set_stroke(BLUE_E, width=4) square = Square() - + self.play(ShowCreation(square)) self.wait() self.play(ReplacementTransform(square, circle)) @@ -39,40 +39,52 @@ AnimatingMethods grid = Tex(r"\pi").get_grid(10, 10, height=4) self.add(grid) - # If you pass in a mobject method to the scene's "play" function, - # it will apply an animation interpolating between the mobject's - # initial state and whatever happens when you apply that method. - # For example, calling grid.shift(2 * LEFT) would shift it two units - # to the left, but the following line animates that motion. - self.play(grid.shift, 2 * LEFT) + # 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. + # The same applies for any method, including those setting colors. - self.play(grid.set_submobject_colors_by_gradient, BLUE, GREEN) - self.play(grid.set_height, TAU - MED_SMALL_BUFF) + 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)) self.wait() # The method Mobject.apply_complex_function lets you apply arbitrary # complex functions, treating the points defining the mobject as # complex numbers. - self.play(grid.apply_complex_function, np.exp, run_time=5) + self.play(grid.animate.apply_complex_function(np.exp), run_time=5) self.wait() # Even more generally, you could apply Mobject.apply_function, # which takes in functions form R^3 to R^3 self.play( - grid.apply_function, - lambda p: [ - p[0] + 0.5 * math.sin(p[1]), - p[1] + 0.5 * math.sin(p[0]), - p[2] - ], + grid.animate.apply_function( + lambda p: [ + p[0] + 0.5 * math.sin(p[1]), + p[1] + 0.5 * math.sin(p[0]), + p[2] + ] + ), run_time=5, ) self.wait() -The new usage in this scene is ``.get_grid()`` and ``self.play(mob.method, args)``. +The new usage in this scene is ``.get_grid()`` and ``self.play(mob.animate.method(args))``. - ``.get_grid()`` method will return a new mobject containing multiple copies of this one arranged in a grid. -- ``self.play(mob.method, args)`` animate the method, and the details are in the comments above. +- ``self.play(mob.animate.method(args))`` animates the method, and the details are in the comments above. TextExample ----------- @@ -291,18 +303,18 @@ UpdatersExample # Notice that the brace and label track with the square self.play( - square.scale, 2, + square.animate.scale(2), rate_func=there_and_back, run_time=2, ) self.wait() self.play( - square.set_width, 5, {"stretch": True}, + square.set_width(5, stretch=True), run_time=3, ) self.wait() self.play( - square.set_width, 2, + square.animate.set_width(2), run_time=3 ) self.wait() @@ -318,7 +330,7 @@ UpdatersExample ) self.wait(4 * PI) -The new classes and usage in this scene are ``always_redraw()``, ``DecimalNumber``, ``.to_edge()``, +The new classes and usage in this scene are ``always_redraw()``, ``DecimalNumber``, ``.to_edge()``, ``.center()``, ``always()``, ``f_always()``, ``.set_y()`` and ``.add_updater()``. - ``always_redraw()`` function create a new mobject every frame. @@ -400,8 +412,8 @@ SurfaceExample self.play( Transform(surface, surfaces[2]), # Move camera frame during the transition - frame.increment_phi, -10 * DEGREES, - frame.increment_theta, -20 * DEGREES, + frame.animate.increment_phi(-10 * DEGREES), + frame.animate.increment_theta(-20 * DEGREES), run_time=3 ) # Add ambient rotation @@ -416,8 +428,8 @@ SurfaceExample light = self.camera.light_source self.add(light) light.save_state() - self.play(light.move_to, 3 * IN, run_time=5) - self.play(light.shift, 10 * OUT, run_time=5) + self.play(light.animate.move_to(3 * IN), run_time=5) + self.play(light.animate.shift(10 * OUT), run_time=5) drag_text = Text("Try moving the mouse while pressing d or s") drag_text.move_to(light_text) @@ -426,7 +438,7 @@ SurfaceExample self.play(FadeTransform(light_text, drag_text)) self.wait() -This scene shows an example of using a three-dimensional surface, and +This scene shows an example of using a three-dimensional surface, and 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. @@ -467,7 +479,7 @@ OpeningManimExample FadeTransform(intro_words, linear_transform_words) ) self.wait() - self.play(grid.apply_matrix, matrix, run_time=3) + self.play(grid.animate.apply_matrix(matrix), run_time=3) self.wait() # Complex map @@ -491,12 +503,12 @@ OpeningManimExample ) self.wait() self.play( - moving_c_grid.apply_complex_function, lambda z: z**2, + moving_c_grid.animate.apply_complex_function(lambda z: z**2), run_time=6, ) self.wait(2) This scene is a comprehensive application of a two-dimensional scene. -After seeing these scenes, you have already understood part of the +After seeing these scenes, you have already understood part of the usage of manim. For more examples, see `the video code of 3b1b `_. diff --git a/docs/source/getting_started/quickstart.rst b/docs/source/getting_started/quickstart.rst index 4299b24b..7127adfd 100644 --- a/docs/source/getting_started/quickstart.rst +++ b/docs/source/getting_started/quickstart.rst @@ -1,10 +1,10 @@ Quick Start =========== -After installing the manim environment according to the instructions on the +After installing the manim environment according to the instructions on the :doc:`installation` page, you can try to make a scene yourself from scratch. -First, create a new ``.py`` file (such as ``start.py``) according to the following +First, create a new ``.py`` file (such as ``start.py``) according to the following directory structure: .. code-block:: text @@ -45,7 +45,7 @@ A window will pop up on the screen. And then you can : - scroll the middle mouse button to move the screen up and down - hold down the :kbd:`z` on the keyboard while scrolling the middle mouse button to zoom the screen - hold down the :kbd:`s` key on the keyboard and move the mouse to pan the screen -- hold down the :kbd:`d` key on the keyboard and move the mouse to change the three-dimensional perspective. +- hold down the :kbd:`d` key on the keyboard and move the mouse to change the three-dimensional perspective. Finally, you can close the window and exit the program by pressing :kbd:`q`. @@ -55,8 +55,8 @@ Run this command again: python manim.py start.py SquareToCircle -os -At this time, no window will pop up. When the program is finished, this rendered -image will be automatically opened (saved in the subdirectory ``images/`` of the same +At this time, no window will pop up. When the program is finished, this rendered +image will be automatically opened (saved in the subdirectory ``images/`` of the same level directory of ``start.py`` by default): .. image:: ../_static/quickstart/SquareToCircle.png @@ -67,36 +67,36 @@ Make an image Next, let's take a detailed look at what each row does. -**Line 1**: +**Line 1**: .. code-block:: python - + from manimlib.imports import * - + This will import all the classes that may be used when using manim. **Line 3**: .. code-block:: python - + class SquareToCircle(Scene): -Create a :class:`Scene` subclass ``SquareToCircle``, which will be +Create a :class:`Scene` subclass ``SquareToCircle``, which will be the scene you write and render. **Line 4**: .. code-block:: python - + def construct(self): -Write the ``construct()`` method, the content of which will determine +Write the ``construct()`` method, the content of which will determine how to create the mobjects in the screen and what operations need to be performed. **Line 5**: .. code-block:: python - + circle = Circle() Create a circle (an instance of the :class:`Circle` class), called ``circle`` @@ -104,7 +104,7 @@ Create a circle (an instance of the :class:`Circle` class), called ``circle`` **Line 6~7**: .. code-block:: python - + circle.set_fill(BLUE, opacity=0.5) circle.set_stroke(BLUE_E, width=4) @@ -116,7 +116,7 @@ Set the circle style by calling the circle's method. **Line 9**: .. code-block:: python - + self.add(circle) Add this circle to the screen through the ``.add()`` method of :class:`Scene`. @@ -137,7 +137,7 @@ Let's change some codes and add some animations to make videos instead of just p circle.set_fill(BLUE, opacity=0.5) circle.set_stroke(BLUE_E, width=4) square = Square() - + self.play(ShowCreation(square)) self.wait() self.play(ReplacementTransform(square, circle)) @@ -149,51 +149,51 @@ Run this command this time: python manim.py start.py SquareToCircle -The pop-up window will play animations of drawing a square and transforming +The pop-up window will play animations of drawing a square and transforming it into a circle. If you want to save this video, run: .. code-block:: sh - + python manim.py start.py SquareToCircle -ow -This time there will be no pop-up window, but the video file (saved in the subdirectory -``videos/`` of the same level directory of ``start.py`` by default) will be automatically +This time there will be no pop-up window, but the video file (saved in the subdirectory +``videos/`` of the same level directory of ``start.py`` by default) will be automatically opened after the operation is over: .. raw:: html -Let's take a look at the code this time. The first 7 lines are the same as the previous -ones, and the 8th line is similar to the 5th line, which creates an instance of the +Let's take a look at the code this time. The first 7 lines are the same as the previous +ones, and the 8th line is similar to the 5th line, which creates an instance of the :class:`Square` class and named it ``square``. **Line 10**: .. code-block:: python - + self.play(ShowCreation(square)) An animation is played through :class:`Scene`'s ``.play()`` method. :class:`ShowCreation` -is an animation that shows the process of creating a given mobject. +is an animation that shows the process of creating a given mobject. ``self.play(ShowCreation(square))`` is to play the animation of creating ``square``. **Line 11**: .. code-block:: python - + self.wait() -Use :class:`Scene`'s ``.wait()`` method to pause (default 1s), you can pass in +Use :class:`Scene`'s ``.wait()`` method to pause (default 1s), you can pass in parameters to indicate the pause time (for example, ``self.wait(3)`` means pause for 3s). **Line 12**: .. code-block:: python - + self.play(ReplacementTransform(square, circle)) -Play the animation that transforms ``square`` into ``circle``. +Play the animation that transforms ``square`` into ``circle``. ``ReplacementTransform(A, B)`` means to transform A into B's pattern and replace A with B. **Line 13**: Same as line 11, pause for 1s. @@ -202,34 +202,34 @@ Play the animation that transforms ``square`` into ``circle``. Enable interaction ------------------ -Interaction is a new feature of the new version. You can add the following line +Interaction is a new feature of the new version. You can add the following line at the end of the code to enable interaction: .. code-block:: python self.embed() -Then run ``python manim.py start.py SquareToCircle``. +Then run ``python manim.py start.py SquareToCircle``. -After the previous animation is executed, the ipython terminal will be opened on -the command line. After that, you can continue to write code in it, and the statement -you entered will be executed immediately after pressing :kbd:`Enter`. +After the previous animation is executed, the ipython terminal will be opened on +the command line. After that, you can continue to write code in it, and the statement +you entered will be executed immediately after pressing :kbd:`Enter`. -For example: input the following lines (without comment lines) into it respectively +For example: input the following lines (without comment lines) into it respectively (``self.play`` can be abbreviated as ``play`` in this mode): .. code-block:: python # Stretched 4 times in the vertical direction - play(circle.stretch, 4, {"dim": 0}) + play(circle.animate.stretch(4, dim=0})) # Rotate the ellipse 90° play(Rotate(circle, TAU / 4)) # Move 2 units to the right and shrink to 1/4 of the original - play(circle.shift, 2 * RIGHT, circle.scale, 0.25) + play(circle.animate.shift(2 * RIGHT), circle.animate.scale(0.25)) # Insert 10 curves into circle for non-linear transformation (no animation will play) circle.insert_n_curves(10) # Apply a complex transformation of f(z)=z^2 to all points on the circle - play(circle.apply_complex_function, lambda z: z**2) + play(circle.animate.apply_complex_function(lambda z: z**2)) # Close the window and exit the program exit() @@ -239,8 +239,8 @@ You will get an animation similar to the following: -If you want to enter the interactive mode directly, you don't have to write an -empty scene containing only ``self.embed()``, you can directly run the following command +If you want to enter the interactive mode directly, you don't have to write an +empty scene containing only ``self.embed()``, you can directly run the following command (this will enter the ipython terminal while the window pops up): .. code-block:: sh @@ -250,7 +250,7 @@ empty scene containing only ``self.embed()``, you can directly run the following You succeeded! -------------- -After reading the above content, you already know how to use manim. -Below you can see some examples, in the :doc:`example_scenes` page. +After reading the above content, you already know how to use manim. +Below you can see some examples, in the :doc:`example_scenes` page. But before that, you'd better have a look at the :doc:`configuration` of manim. diff --git a/example_scenes.py b/example_scenes.py index e22e94c9..b7a1afcb 100644 --- a/example_scenes.py +++ b/example_scenes.py @@ -37,7 +37,7 @@ class OpeningManimExample(Scene): FadeTransform(intro_words, linear_transform_words) ) self.wait() - self.play(grid.apply_matrix, matrix, run_time=3) + self.play(grid.animate.apply_matrix(matrix), run_time=3) self.wait() # Complex map @@ -61,7 +61,7 @@ class OpeningManimExample(Scene): ) self.wait() self.play( - moving_c_grid.apply_complex_function, lambda z: z**2, + moving_c_grid.animate.apply_complex_function(lambda z: z**2), run_time=6, ) self.wait(2) @@ -72,35 +72,44 @@ class AnimatingMethods(Scene): grid = Tex(r"\pi").get_grid(10, 10, height=4) self.add(grid) - # If you pass in a mobject method to the scene's "play" function, - # it will apply an animation interpolating between the mobject's - # initial state and whatever happens when you apply that method. - # For example, calling grid.shift(2 * LEFT) would shift it two units - # to the left, but the following line animates that motion. - self.play(grid.shift, 2 * LEFT) + # 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. + # The same applies for any method, including those setting colors. - self.play(grid.set_color, YELLOW) + self.play(grid.animate.set_color(YELLOW)) self.wait() - self.play(grid.set_submobject_colors_by_gradient, BLUE, GREEN) + self.play(grid.animate.set_submobject_colors_by_gradient(BLUE, GREEN)) self.wait() - self.play(grid.set_height, TAU - MED_SMALL_BUFF) + self.play(grid.animate.set_height(TAU - MED_SMALL_BUFF)) self.wait() # The method Mobject.apply_complex_function lets you apply arbitrary # complex functions, treating the points defining the mobject as # complex numbers. - self.play(grid.apply_complex_function, np.exp, run_time=5) + self.play(grid.animate.apply_complex_function(np.exp), run_time=5) self.wait() # Even more generally, you could apply Mobject.apply_function, # which takes in functions form R^3 to R^3 self.play( - grid.apply_function, - lambda p: [ - p[0] + 0.5 * math.sin(p[1]), - p[1] + 0.5 * math.sin(p[0]), - p[2] - ], + grid.animate.apply_function( + lambda p: [ + p[0] + 0.5 * math.sin(p[1]), + p[1] + 0.5 * math.sin(p[0]), + p[2] + ] + ), run_time=5, ) self.wait() @@ -294,18 +303,18 @@ class UpdatersExample(Scene): # Notice that the brace and label track with the square self.play( - square.scale, 2, + square.animate.scale(2), rate_func=there_and_back, run_time=2, ) self.wait() self.play( - square.set_width, 5, {"stretch": True}, + square.set_width(5, stretch=True), run_time=3, ) self.wait() self.play( - square.set_width, 2, + square.animate.set_width(2), run_time=3 ) self.wait() @@ -398,8 +407,8 @@ class GraphExample(Scene): 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.play(x_tracker.animate.set_value(4), run_time=3) + self.play(x_tracker.animate.set_value(-2), run_time=3) self.wait() @@ -442,9 +451,9 @@ class CoordinateSystemExample(Scene): 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.play(dot.animate.move_to(axes.c2p(3, 2))) self.wait() - self.play(dot.move_to, axes.c2p(5, 0.5)) + self.play(dot.animate.move_to(axes.c2p(5, 0.5))) self.wait() # Similarly, you can call axes.point_to_coords, or axes.p2c @@ -461,9 +470,9 @@ class CoordinateSystemExample(Scene): ShowCreation(h_line), ShowCreation(v_line), ) - self.play(dot.move_to, axes.c2p(3, -2)) + self.play(dot.animate.move_to(axes.c2p(3, -2))) self.wait() - self.play(dot.move_to, axes.c2p(1, 1)) + self.play(dot.animate.move_to(axes.c2p(1, 1))) self.wait() # If we tie the dot to a particular set of coordinates, notice @@ -471,8 +480,8 @@ class CoordinateSystemExample(Scene): # system defined by them. f_always(dot.move_to, lambda: axes.c2p(1, 1)) self.play( - axes.scale, 0.75, - axes.to_corner, UL, + axes.animate.scale(0.75), + axes.animate.to_corner(UL), run_time=2, ) self.wait() @@ -546,8 +555,8 @@ class SurfaceExample(Scene): self.play( Transform(surface, surfaces[2]), # Move camera frame during the transition - frame.increment_phi, -10 * DEGREES, - frame.increment_theta, -20 * DEGREES, + frame.animate.increment_phi(-10 * DEGREES), + frame.animate.increment_theta(-20 * DEGREES), run_time=3 ) # Add ambient rotation @@ -562,8 +571,8 @@ class SurfaceExample(Scene): light = self.camera.light_source self.add(light) light.save_state() - self.play(light.move_to, 3 * IN, run_time=5) - self.play(light.shift, 10 * OUT, run_time=5) + self.play(light.animate.move_to(3 * IN), run_time=5) + self.play(light.animate.shift(10 * OUT), run_time=5) drag_text = Text("Try moving the mouse while pressing d or s") drag_text.move_to(light_text) @@ -593,9 +602,9 @@ class InteractiveDevlopment(Scene): # the interactive shell self.play(ReplacementTransform(square, circle)) self.wait() - self.play(circle.stretch, 4, 0) + self.play(circle.animate.stretch(4, 0)) self.play(Rotate(circle, 90 * DEGREES)) - self.play(circle.shift, 2 * RIGHT, circle.scale, 0.25) + self.play(circle.animate.shift(2 * RIGHT, circle.scale, 0.25)) text = Text(""" In general, using the interactive shell