3. Animations¶
Latest update : 13.6.2021
There are a wide range of possibilities to animate your mobjects that all work a bit differently. Here is a broad overview so that you can choose the animation stategy that fits best for your project. This chapter will cover ValueTrackers
, Updaters
, self.play Transformations
the mobject.animate
syntax and mobject.become
syntax.
[1]:
from manim import *
Manim Community v0.9.0
[2]:
#ignore this cell, only for setup
params= "-v WARNING --progress_bar None -r 500,200 --disable_caching Example"
NO = Cross(Square(), stroke_color = RED_D, stroke_width = 38).scale(0.9).to_edge(LEFT, buff=1)
YES = SVGMobject("good.svg").to_edge(LEFT, buff=1)
BEST = YES.copy()
BEST.add(Star(color= YELLOW, fill_opacity=1).scale(0.5).move_to(BEST).shift(0.5*DOWN+0.5*RIGHT));
Simple Replacements¶
[3]:
%%manim $params
class Example(Scene):
def construct(self):
dot= Dot(color= YELLOW, radius=0.5)
self.add(dot)
self.wait()
dot.scale(2)
self.wait()
dot.scale(2)
self.wait(2)
[4]:
%%manim $params
class Example(Scene):
def construct(self):
dot= Dot(color= YELLOW, radius=0.5)
square= Square(side_length=4,color= BLUE, fill_opacity=1)
triangle= Triangle(radius=3,color= ORANGE, fill_opacity=1).shift(DOWN*0.5)
self.add(dot)
self.wait()
dot.become(square)
self.wait()
dot.become(triangle)
self.wait()
Using .animate Syntax¶
[5]:
%%manim $params
class Example(Scene):
def construct(self):
dot= Dot(color= YELLOW, radius=0.5)
self.play(dot.animate.scale(2))
[6]:
%%manim $params
class Example(Scene):
def construct(self):
dot= Dot(color= YELLOW, radius=0.5)
self.play(dot.animate.shift(2*RIGHT))
[7]:
%%manim $params
class Example(Scene):
def construct(self):
dot= Dot(color= YELLOW, radius=0.5)
self.play(dot.animate.set_color(BLUE))
[8]:
%%manim $params
class Example(Scene):
def construct(self):
dot= Dot(color= YELLOW, radius=0.5)
self.play(dot.animate.shift(2*RIGHT).scale(2))
[9]:
%%manim $params
class Example(Scene):
def construct(self):
dot= Dot(color= YELLOW, radius=0.5)
self.play(dot.animate.shift(2*RIGHT).scale(2).set_color(BLUE))
Updaters¶
They are very diverse! And they can be used with and without a “dt” parameter
[10]:
%%manim $params
class Example(Scene):
def construct(self):
dot = Dot(color= GREEN, radius=0.7)
self.add(dot)
def foo(mob,dt):
mob.shift(2*RIGHT*dt)
dot.add_updater(foo)
self.wait(3)
[11]:
%%manim $params
class Example(Scene):
def construct(self):
dot = Dot(color= GREEN, radius=0.7)
self.add(dot)
dot.add_updater(lambda x,dt: x.shift(2*RIGHT*dt))
self.wait(3)
[12]:
%%manim $params
class Example(Scene): # when there is no dt parameter, the updater does not work
def construct(self):
dot = Dot(color= GREEN, radius=0.7)
self.add(dot,NO)
dot.add_updater(lambda x : x.shift(2*RIGHT*0.1))
self.wait(3)
Note: Not using the “dt” parameter will make your animation framerate dependent, but this can be solved using ValueTracker, which can be seen in the next section
Updaters + ValueTrackers¶
[13]:
%%manim $params
class Example(Scene):
def construct(self):
tracker= ValueTracker(0)
dot = Dot(color= GREEN, radius=0.7)
self.add(dot)
def foo(mob):
mob.move_to(RIGHT*tracker.get_value())
dot.add_updater(foo)
self.play(tracker.animate.set_value(2), rate_func= linear)
Note: now you can also use rate functions:
[14]:
%%manim $params
class Example(Scene):
def construct(self):
tracker= ValueTracker(0)
dot = Dot(color= GREEN, radius=0.7)
self.add(dot)
def foo(mob):
mob.move_to(RIGHT*tracker.get_value())
dot.add_updater(foo)
self.play(tracker.animate.set_value(2), rate_func= smooth)
[15]:
%%manim $params
class Example(Scene):
def construct(self):
tracker= ValueTracker(0.5)
dot = Dot(color= GREEN, radius=0.7)
self.add(dot)
def foo(mob):
mob.move_to(RIGHT*tracker.get_value())
dot.add_updater(foo)
self.play(tracker.animate.set_value(2.2), rate_func= smooth)
self.play(tracker.animate.increment_value(1), rate_func= smooth)
self.play(tracker.animate.increment_value(-1), rate_func= smooth)
self.play(tracker.animate.set_value(0.5), rate_func= linear)
[16]:
%%manim $params
#one can now also add additional properties to mobjects, in this case a counter.
class Example(Scene):
def construct(self):
tracker= ValueTracker(0)
dot = Dot(color= GREEN, radius=0.7)
self.add(dot)
dot.counter=0
def foo(mob):
mob.move_to(RIGHT*tracker.get_value())
if mob.counter == 20:
mob.set_color(random_bright_color())
mob.counter = 0
mob.counter += 1
dot.add_updater(foo)
self.play(tracker.animate.set_value(2), rate_func= linear, run_time=3)
Transformations¶
[17]:
%%manim $params
class Example(Scene):
def construct(self):
d= Dot(color= YELLOW, radius=0.5)
d2= d.copy().shift(2*RIGHT)
self.play(Transform(d, d2))
Does and Donts¶
Note that when you choose to work with updaters, your script might depend on the frame rate.
[18]:
%%manim $params
class Example(Scene):
def construct(self):
print(f"{config.frame_rate = }fps")
dotred= Dot(color= RED, radius=0.5).shift(UP)
dotgreen = Dot(color= GREEN, radius=0.5)
dotgreen.next_to(dotred,DOWN)
self.add(dotgreen,dotred)
DIR= 2*RIGHT
dotgreen.add_updater(lambda x,dt: x.shift(DIR*dt))
dotred.add_updater(lambda x,dt: x.shift(DIR*1/60))
self.wait(3)
config.frame_rate = 60fps
[19]:
params5fps = "-v WARNING --progress_bar None --frame_rate=5 -r 500,200 --disable_caching Example"
[20]:
%%manim $params5fps
class Example(Scene):
def construct(self):
print(f"{config.frame_rate = }fps")
dotred= Dot(color= RED, radius=0.5).shift(UP)
dotgreen = Dot(color= GREEN, radius=0.5)
dotgreen.next_to(dotred,DOWN)
self.add(dotgreen,dotred)
DIR= 2*RIGHT
dotgreen.add_updater(lambda x,dt: x.shift(DIR*dt))
dotred.add_updater(lambda x,dt: x.shift(DIR*1/60))
self.wait(3)
config.frame_rate = 5.0fps
Rotation animation¶
There are multiple ways to rotate a square, but not all will result in that animation that you might have expected.
[21]:
%%manim $params
class Example(Scene):
def construct(self, **kwargs):
s1= Square().set_color(YELLOW)
self.add(s1, BEST)
self.play(Rotate(s1, angle=PI/2))
[22]:
%%manim $params
class Example(Scene):
def construct(self, **kwargs):
s2= Square().set_color(PURPLE)
self.add(s2, NO)
self.play(s2.animate.rotate(PI/2))
[23]:
%%manim $params
class Example(Scene):
def construct(self, **kwargs):
theta_track= ValueTracker(0)
s3= Square().set_color(ORANGE)
self.add(s3, YES)
s3.previous_angle=0
def pref(x):
x.previous_angle=theta_track.get_value()
s3.add_updater(lambda x: x.rotate(theta_track.get_value()-s3.previous_angle))
s3.add_updater(pref)
self.play(theta_track.animate.increment_value(PI/2))
[24]:
#not yet implemented
#class Example(Scene):
# def construct(self, **kwargs):
#s3b= Square().set_color(YELLOW)
#self.add(s3b)
#theta_track= DeltaValueTracker(0)
#s3b.add_updater(lambda x: x.rotate(theta_track.get_delta_value()))
#self.play(theta_track.animate.set_value(90*DEGREES))
[25]:
%%manim $params
# NOT WORKING!, BAD PRACTICE.
class Example(Scene):
def construct(self, **kwargs):
s4= Square().set_color(GREEN)
self.add(s4, NO)
theta_track= ValueTracker(0)
s4.add_updater(lambda x: x.rotate(theta_track.get_value()))
self.play(theta_track.animate.increment_value(PI/2))
[26]:
%%manim $params
class Example(Scene):
def construct(self, **kwargs):
s6= Square().set_color(PINK)
self.add(s6, YES)
s6.add_updater(lambda x, dt: x.rotate(dt*PI/2))
self.wait(1)
Known bugs¶
Bug with updaters that do not have a dt¶
[27]:
%%manim $params
class Example(Scene):
def construct(self):
dot = Dot(color= GREEN, radius=0.7)
self.add(dot,NO)
#dot.add_updater(lambda x,dt : x)
dot.add_updater(lambda x : x.shift(2*RIGHT*1/config.frame_rate))
self.wait(3)
[28]:
%%manim $params
class Example(Scene):
def construct(self):
dot = Dot(color= GREEN, radius=0.7)
self.add(dot,YES)
dot.add_updater(lambda x,dt : x) #adding this line will make the updater continiously watch
dot.add_updater(lambda x : x.shift(2*RIGHT*1/config.frame_rate))
self.wait(3)
Bugs with updater in ZoomedScene¶
[29]:
%%manim $params
class Example(ZoomedScene):
def __init__(self, **kwargs):
ZoomedScene.__init__(
self,
zoom_factor=0.3,
zoomed_display_height=4,
zoomed_display_width=4,
image_frame_stroke_width=20,
zoomed_camera_config={
"default_frame_stroke_width": 3,
},
**kwargs
)
def construct(self):
d= Dot()
self.add(d)
imgo =Square().scale(0.3).set_color(RED)
self.add(imgo)
#imgo.add_updater(lambda x: x) # COMMENTED OUT
self.activate_zooming(animate=True)
self.play(self.zoomed_camera.frame.animate.shift(0.5 * (LEFT+UP*0.8)))
self.play(self.zoomed_camera.frame.animate.shift(0.5 * (RIGHT+DOWN*2.8)))
[30]:
%%manim $params
class Example(ZoomedScene):
def __init__(self, **kwargs):
ZoomedScene.__init__(
self,
zoom_factor=0.3,
zoomed_display_height=4,
zoomed_display_width=4,
image_frame_stroke_width=20,
zoomed_camera_config={
"default_frame_stroke_width": 3,
},
**kwargs
)
def construct(self):
d= Dot()
self.add(d)
imgo =Square().scale(0.3).set_color(RED)
self.add(imgo)
imgo.add_updater(lambda x: x) # INCLUDED
self.activate_zooming(animate=True)
self.play(self.zoomed_camera.frame.animate.shift(0.5 * (LEFT+UP*0.8)))
self.play(self.zoomed_camera.frame.animate.shift(0.5 * (RIGHT+DOWN*2.8)))
[ ]: