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]: