Python

How to Create Animations Using Matplotlib and Python

Computer animation is a process in which a moving image is created from a sequence of frames.

 

An algorithm continuously changes the positions of the individual images. In the process, each frame must be deleted before it is then moved to a new position and displayed there. If the algorithm generates 24 new images in 1 second, for example, then the viewer is given the illusion of an almost fluid movement. Computer animations can be used to illustrate physical phenomena that are beyond human perception by slowing down fast processes or speeding up slow processes.

 

The from matplotlib.animation import FuncAnimation statement imports the FuncAnimation method.

 

The following method creates the ani object:

 

ani=FuncAnimation(fig, func, frames=None, init_func=None, fargs=None,

save_count=None, cache_frame_data=True)

 

Not all possible parameters are specified. Although this object is not needed in the animation program, it must be created; otherwise, the animation will not be executed, and only a static image will appear on the screen.

 

Note: You must store an animation in a variable, which means you should always create an explicit object. If you don’t, an implicitly created animation object will be subjected to an automatic garbage collection process, and the animation will be stopped.

 

You can create an implicit object by not assigning a variable to a method. The following console example creates an implicit object:

 

>>> import matplotlib.pyplot as plt

>>> from matplotlib.animation import FuncAnimation

>>> fig=plt.Figure()

>>> def func():pass

>>> FuncAnimation(fig,func) #no variable present

<matplotlib.animation.FuncAnimation object at 0x135e65c30>

 

The warning generated by this console program was not included in this case.

 

The second parameter (func) stands for the name of a custom Python function that is to be animated. This function is called without specifying a parameter. The other parameters will be discussed during the analysis of each program.

 

The examples selected for this purpose include the time-based shifting of a sine wave on the x-axis, the oblique throw, and the motion of a planet in an elliptical orbit.

 

A Simple Animation: Shifting a Sine Function

Below shows how to use the FuncAnimation() method to shift a sine wave in the direction of the x-axis.

 

01 #33_animation_sine.py

02 import numpy as np

03 import matplotlib.pyplot as plt

04 from matplotlib.animation import FuncAnimation

05

06 def f(x,k):

07    return np.sin(x-k/20)

08

09 def v(k):

10    y.set_data(x,f(x,k))

11    return y,

12

13 fig,ax=plt.subplots()

14 x=np.linspace(0,4*np.pi,200)

15 y, = ax.plot(x,f(x,0),'r-',lw=3)

16 #Animation

17 ani=FuncAnimation(fig,v,

18                   interval=20,

19                   #frames=200,

20                   blit=True,

21                   # save_count=50,

22                   # cache_frame_data=False

23                   )

24 plt.show()

 

The figure below shows a snapshot of the animation.

 

Snapshot of a Sine Wave

 

This program draws a sine curve that is moving on the screen in the x-direction. The direction of the movement can be changed by the sign in line 07. If the k parameter is negative, the curve moves from left to right. If the k parameter is positive, it moves from right to left.

 

The program consists of three parts: the v(k) function in line 09, the initialization part in line 15, and the animation in line 17.

 

To perform an animation, the matplotlib.animation module must be imported (line 4). In lines 06 and 07, the sine function sin(x-k/20) with variables x and k is defined. The x variable changes the angle, while the k variable causes the movement of the sine function on the x-axis.

 

In line 09, the most important function for the animation is defined, namely, v(k). The y.set_data(x,f(x,k)) method in line 10 changes the value k for the shift on the x-axis at each function call of v(k) in line 17. The y object returned in line 11 must be terminated with a comma because the return value must be a tuple. If you omit the comma, an error message will display.

 

Line 13 creates the fig and ax objects. The fig object is needed for the animation in line 17. The ax object is used to access the plot method.

 

In line 14, the linspace(0,4*np.pi,200) NumPy function stores 200 values in the x variable for the range from 0 to 4π. When the y object is initialized in line 15, the 200 values for the x angles and for k=0 are stored in this object. Thus, the y object contains a static image for two sine waves. The y object must be followed by a comma again, otherwise the animation will not be executed.

 

In line 17, the following method performs the animation:

 

ani=FuncAnimation(fig,v,interval=20,blit=True)

 

Notice that an explicit ani object must be created (line 17), although it is not used in the program. The identifier of this object is freely selectable. If you do not create an explicit object, then the animation will not be executed. This object has the task of controlling an internal counter (timer) that accesses the explicitly created animation object ani. If this is missing, then the implicit animation object will be collected by the automatic memory management functionality (garbage collection) as data garbage, and the animation will be stopped. A static image will appear on the monitor.

 

The first parameter (fig) sets the properties of the drawing area in which the animation will take place.

 

As the second parameter, the FuncAnimation() method expects the custom animation function v(k), which must be called without the k argument.

 

The interval parameter determines the delay (in milliseconds) with which the individual images are to be generated. The standard value is 200 ms. The larger this value, the greater the pauses between the generation of new images. The animation no longer runs as “smoothly” and shows clear signs of “bucking.”

 

The frames=200 parameter sets the number of frames to be drawn. This parameter is not needed in this animation and will be explained in more detail in later examples.

 

The blit parameter specifies whether blitting should be used to optimize dynamic drawing. The default value is False. Blitting means the fast copying and moving of the object to be moved. If blit=True, only the areas of the image that have changed will be redrawn. The animations should run more or less “smoothly” due to blitting. If you comment out this parameter, however, you’ll notice that hardly any change is perceptible. You can learn more about blitting at https://matplotlib.org/stable/tutorials/advanced/blitting.html.

 

The save_count parameter sets the number of frames to be stored in the cache. This parameter is used only if no value is assigned to the frames parameter.

 

The cache_frame_data parameter prevents a memory overflow from occurring in the cache. The default value is True. If the frames parameter is not assigned a value, you should set cache_frame_data=False as of Matplotlib version 3.7. Otherwise, the Python interpreter will issue the following warning:

 

UserWarning: frames=None which we can infer the length of, did not pass an

explicit *save_count* and passed cache_frame_data=True. To avoid a possibly

unbounded cache, frame data caching has been disabled. To suppress this warning

either pass `cache_frame_data=False` or `save_count=MAX_FRAMES`.

ani=FuncAnimation(fig,v,

 

You should test this program extensively by changing the individual parameters and closely observing the effects on the animation.

 

Animated Oblique Throw

The animated oblique throw shows the motion sequence of a ball thrown with a certain initial velocity at a certain throwing angle. For the determination of the drawing area, the throw distance and the climb height must be calculated.

 

 

This listing enables you to animate the motion sequence of the oblique throw.

 

01 #34_animation_throw.py

02 import numpy as np

03 import matplotlib.pyplot as plt

04 from matplotlib.animation import FuncAnimation

05 g=9.81

06 v0=10

07 throwing_angle=45

08 alpha=np.radians(throwing_angle)

09 tmax=2*v0*np.sin(alpha)/g

10 xmax=v0**2*np.sin(2*alpha)/g

11 ymax=v0**2*np.sin(alpha)**2/(2*g)

12 #Calculate trajectory

13 def throw(t):

14    x = v0*np.cos(alpha)*t

15    y = v0*np.sin(alpha)*t-0.5*g*t**2

16    ball.set_data([x],[y])

17    return ball,

18 #generate objects

19 fig,ax=plt.subplots()

20 ax.axis([0,xmax+0.5,0,ymax+0.5])

21 ball, = ax.plot([],[],'ro')

22 t=np.linspace(0,tmax,100)

23 ani=FuncAnimation(fig,throw,frames=t,interval=20,blit=True)

24 ax.set(xlabel="x in m",ylabel="y in m",title="Oblique throw")

25 plt.show()

 

Here is a snapshot of the animation of the oblique throw.

 

Snapshot of the Animation of the Oblique Throw

 

Of course, the animated throwing process cannot be shown in this book. For testing purposes, you can run the program with different initial velocities in line 06 and throwing angles in line 07.

 

The custom throw(t) function in lines 13 to 17 calculates the new positions of the x and y coordinates for each new function call by the FuncAnimation() method and stores them in the ball object. As of Matplotlib version 3.7, the x and y arguments must be enclosed in square brackets (line 16) because the set_data() method only accepts sequences as arguments. If you omit the brackets, the following warning appears: MatplotlibDeprecationWarning: Setting data with a non sequence type is deprecated since 3.7 and will be remove two minor releases later.

 

Line 21 initializes the ball object with an empty list for the plot method. The ro parameter causes the ball to be displayed as a red dot. If you insert the markersize='15' parameter, the diameter of the ball will increase.

 

The FuncAnimation() method in line 23 executes the animation. The frames parameter sets the number of frames to be displayed per second if the parameter is assigned an integer. In this animation, frames is assigned a sequence t from 0 to tmax out of 100 values, which guarantees an almost smooth display. If you were to assign an integer to the frames parameter, the ball would flash at a fixed position on the trajectory and not move.

 

Animated Planetary Orbit

Planets move in an elliptical orbit. The shape of an ellipse is described by the two axes a and b. The x-y components are described by the following parameter equations:

 

 

This listing enables you to animate the motion sequence of a planet around a star.

 

01 #35_animation_elipse.py

02 import numpy as np

03 import matplotlib as mlt

04 import matplotlib.pyplot as plt

05 from matplotlib.animation import FuncAnimation

06 #Data

07 r1,r2=0.5,0.25

08 a,b=8,4 #Ellipse axes

09 width=10

10 #Initialization

11 def init():

12    planet.center=(1,2)

13    ax.add_patch(planet)

14    return planet,

15 #Trajectory calculation

16 def trajectory(t):

17    x,y=a*np.cos(np.radians(t)),b*np.sin(np.radians(t))

18    planet.center=(x,y)

19    return planet,

20 #Graphics area

21 fig,ax=plt.subplots()

22 ax.axis([-width,width,-width,width])

23 planet= mlt.patches.Circle((0,0),radius=r2, color='blue')

24 star= mlt.patches.Circle((2.5,0),radius=r1, color='red')

25 ax.add_artist(star)

26 ani=FuncAnimation(fig,trajectory,

                   init_func=init,frames=360,interval=20,blit=True)

27 ax.set_aspect('equal')

28 ax.set(xlabel='x',ylabel='y',title='elliptical orbit')

29 plt.show()

 

Below is a snapshot of the animation of a planetary orbit.

 

Snapshot of the Animation of a Planetary Orbit

 

Basically, the program has the same structure as the animation of the throwing parabola. Line 08 defines the a and b axes of the elliptical orbit.

 

In lines 11 to 14, the init() function initializes the circular object planet created in line 23 for the x = 1 und y = 2 values (line 12) using the planet.center=(1,2) statement. These values are chosen arbitrarily. When the program starts, this placement cannot be perceived.

 

The custom trajectory(t) function in lines 16 to 19 contains the parameter equations of the ellipse. The coordinate data is calculated in line 17. The planet.center=(x,y) statement takes the coordinates of the orbit and stores them in the planet object.

 

The FuncAnimation() method in line 26 calls the trajectory function and the init function without parameters and creates the animation. In line 24, the star object is created, and in line 25, this object is added to the center of the drawing area using the add_artist(stern) method. Determining the number of frames is important. For example, you can test the program with frames=300. Then, after 300°, you’ll observe the jumping movement of the planet.

 

Editor’s note: This post has been adapted from a section of the book Python for Engineering and Scientific Computing by Veit Steinkamp.

Recommendation

Python for Engineering and Scientific Computing
Python for Engineering and Scientific Computing

It’s finally here—your guide to Python for engineers and scientists, by an engineer and scientist! Get to know your development environments and the key Python modules you’ll need: NumPy, SymPy, SciPy, Matplotlib, and VPython. Understand basic Python program structures and walk through practical exercises that start simple and increase in complexity as you work your way through the book. With information on statistical calculations, Boolean algebra, and interactive programming with Tkinter, this Python guide belongs on every scientist’s shelf!

Learn More
Rheinwerk Computing
by Rheinwerk Computing

Rheinwerk Computing is an imprint of Rheinwerk Publishing and publishes books by leading experts in the fields of programming, administration, security, analytics, and more.

Comments