The result is:
In this page, an animation of cycloid is generated using ArtistAnimation function of matplotlib.animation.
The animation of cycloid is already generated in "Draw cycloid animation using matplotlib.animation.FuncAnimation".
Here, an altanative way for drawing animations that is matplotlib.animation.ArtistAnimation is used.
I think ArtistAnimation is easier to understand and write the code than FucAnimation.
In [1]:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
In [2]:
# Config to put the animation on the jupyter notebook
plt.rcParams['animation.html'] = 'html5'
The documents of the matplotlib.animation.ArtistAnimation
In [3]:
animation.ArtistAnimation?
Init signature: animation.ArtistAnimation(fig, artists, *args, **kwargs)
Docstring:
Animation using a fixed set of `Artist` objects.
Before creating an instance, all plotting should have taken place
and the relevant artists saved.
Parameters
----------
fig : matplotlib.figure.Figure
The figure object that is used to get draw, resize, and any
other needed events.
artists : list
Each list entry a collection of artists that represent what
needs to be enabled on each frame. These will be disabled for
other frames.
interval : number, optional
Delay between frames in milliseconds. Defaults to 200.
repeat_delay : number, optional
If the animation in repeated, adds a delay in milliseconds
before repeating the animation. Defaults to `None`.
repeat : bool, optional
Controls whether the animation should repeat when the sequence
of frames is completed. Defaults to `True`.
blit : bool, optional
Controls whether blitting is used to optimize drawing. Defaults
to `False`.
File: ****/lib/site-packages/matplotlib/animation.py
Type: type
In [4]:
animation.ArtistAnimation??
Init signature: animation.ArtistAnimation(fig, artists, *args, **kwargs)
Source:
class ArtistAnimation(TimedAnimation):
'''Animation using a fixed set of `Artist` objects.
Before creating an instance, all plotting should have taken place
and the relevant artists saved.
Parameters
----------
fig : matplotlib.figure.Figure
The figure object that is used to get draw, resize, and any
other needed events.
artists : list
Each list entry a collection of artists that represent what
needs to be enabled on each frame. These will be disabled for
other frames.
interval : number, optional
Delay between frames in milliseconds. Defaults to 200.
repeat_delay : number, optional
If the animation in repeated, adds a delay in milliseconds
before repeating the animation. Defaults to `None`.
repeat : bool, optional
Controls whether the animation should repeat when the sequence
of frames is completed. Defaults to `True`.
blit : bool, optional
Controls whether blitting is used to optimize drawing. Defaults
to `False`.
'''
def __init__(self, fig, artists, *args, **kwargs):
# Internal list of artists drawn in the most recent frame.
self._drawn_artists = []
# Use the list of artists as the framedata, which will be iterated
# over by the machinery.
self._framedata = artists
TimedAnimation.__init__(self, fig, *args, **kwargs)
def _init_draw(self):
# Make all the artists involved in *any* frame invisible
figs = set()
for f in self.new_frame_seq():
for artist in f:
artist.set_visible(False)
artist.set_animated(self._blit)
# Assemble a list of unique figures that need flushing
if artist.get_figure() not in figs:
figs.add(artist.get_figure())
# Flush the needed figures
for fig in figs:
fig.canvas.draw_idle()
def _pre_draw(self, framedata, blit):
'''
Clears artists from the last frame.
'''
if blit:
# Let blit handle clearing
self._blit_clear(self._drawn_artists, self._blit_cache)
else:
# Otherwise, make all the artists from the previous frame invisible
for artist in self._drawn_artists:
artist.set_visible(False)
def _draw_frame(self, artists):
# Save the artists that were passed in as framedata for the other
# steps (esp. blitting) to use.
self._drawn_artists = artists
# Make all the artists from the current frame visible
for artist in artists:
artist.set_visible(True)
File: ****/lib/site-packages/matplotlib/animation.py
Type: type
In [5]:
# radius of the circle
R = 1
In [6]:
def circle(a, b, r):
# (a,b): the center of the circle
# r: the radius of the circle
# T: The number of the segments
T = 100
x, y = [0]*T, [0]*T
for i,theta in enumerate(np.linspace(0,2*np.pi,T)):
x[i] = a + r*np.cos(theta)
y[i] = b + r*np.sin(theta)
return x, y
# Calculate the cycloid line
thetas = np.linspace(0,4*np.pi,100)
cycloid_x = R*(thetas-np.sin(thetas))
cycloid_y = R*(1-np.cos(thetas))
cycloid_c = R*thetas
In [7]:
fig = plt.figure()
lns = []
trans = plt.axes().transAxes
for i in range(len(thetas)):
x,y = circle(cycloid_c[i], R, R)
ln1, = plt.plot(x, y, 'g-', lw=2)
ln2, = plt.plot(cycloid_x[:i+1] ,cycloid_y[:i+1], 'r-', lw=2)
ln3, = plt.plot(cycloid_x[i], cycloid_y[i], 'bo', markersize=4)
ln4, = plt.plot([cycloid_c[i], cycloid_x[i]], [R,cycloid_y[i]], 'y-', lw=2)
tx1 = plt.text(0.05, 0.8, r'$\theta$ = %.2f $\pi$' % (thetas[i]/np.pi), transform=trans)
lns.append([ln1,ln2,ln3,ln4,tx1])
plt.xlim(0,15)
plt.ylim(0,3)
plt.xlabel('x')
plt.ylabel('y')
plt.grid()
plt.axes().set_aspect('equal')
The data structure is like this.
In [8]:
lns[:5]
Out[8]:
Then create animation
In [9]:
ani = animation.ArtistAnimation(fig, lns, interval=50)
In [10]:
ani.save('cycloid_ArtistAnimation.mp4',writer='ffmpeg')
ani.save('cycloid_ArtistAnimation.gif',writer='imagemagick')
In [11]:
ani
Out[11]:
