I can't figure out how to get an animated title working on a FuncAnimation plot (that uses blit). Based on http://jakevdp.github.io/blog/2012/08/18/matplotlib-animation-tutorial/ and Python/Matplotlib - Quickly Updating Text on Axes, I've built an animation, but the text parts just won't animate. Simplified example:
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import numpy as np
vls = np.linspace(0,2*2*np.pi,100)
fig=plt.figure()
img, = plt.plot(np.sin(vls))
ax = plt.axes()
ax.set_xlim([0,2*2*np.pi])
#ttl = ax.set_title('',animated=True)
ttl = ax.text(.5, 1.005, '', transform = ax.transAxes)
def init():
ttl.set_text('')
img.set_data([0],[0])
return img, ttl
def func(n):
ttl.set_text(str(n))
img.set_data(vls,np.sin(vls+.02*n*2*np.pi))
return img, ttl
ani = animation.FuncAnimation(fig,func,init_func=init,frames=50,interval=30,blit=True)
plt.show()
If blit=True
is removed, the text shows up, but it slows way down. It seems to fail with plt.title
, ax.set_title
, and ax.text
.
Edit: I found out why the second example in the first link worked; the text was inside the img
part. If you make the above 1.005
a .99
, you'll see what I mean. There probably is a way to do this with a bounding box, somehow...
Animations in Matplotlib can be made by using the Animation class in two ways: By calling a function over and over: It uses a predefined function which when ran again and again creates an animation. By using fixed objects: Some animated artistic objects when combined with others yield an animation scene.
You can create animations in Python by calling a plot function inside of a loop (usually a for-loop). The main tools for making animations in Python is the matplotlib. animation. Animation base class, which provides a framework around which the animation functionality is built.
A table can be added to Axes using matplotlib. pyplot. table(). We can plot the table by taking columns on the x-axis and the y-axis for values.
See Animating matplotlib axes/ticks and python matplotlib blit to axes or sides of the figure?
So, the problem is that in the guts of animation
where the blit backgrounds are actually saved (line 792 of animation.py), it grabs what is in the axes bounding box. This makes sense when you have multiple axes being independently animated. In your case you only have one axes
to worry about and we want to animate stuff outside of the axes bounding box. With a bit of monkey patching, a level of tolerance for reaching into the guts of mpl and poking around a bit, and acceptance of the quickest and dirtyest solution we can solve your problem as such:
import matplotlib
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import numpy as np
def _blit_draw(self, artists, bg_cache):
# Handles blitted drawing, which renders only the artists given instead
# of the entire figure.
updated_ax = []
for a in artists:
# If we haven't cached the background for this axes object, do
# so now. This might not always be reliable, but it's an attempt
# to automate the process.
if a.axes not in bg_cache:
# bg_cache[a.axes] = a.figure.canvas.copy_from_bbox(a.axes.bbox)
# change here
bg_cache[a.axes] = a.figure.canvas.copy_from_bbox(a.axes.figure.bbox)
a.axes.draw_artist(a)
updated_ax.append(a.axes)
# After rendering all the needed artists, blit each axes individually.
for ax in set(updated_ax):
# and here
# ax.figure.canvas.blit(ax.bbox)
ax.figure.canvas.blit(ax.figure.bbox)
# MONKEY PATCH!!
matplotlib.animation.Animation._blit_draw = _blit_draw
vls = np.linspace(0,2*2*np.pi,100)
fig=plt.figure()
img, = plt.plot(np.sin(vls))
ax = plt.axes()
ax.set_xlim([0,2*2*np.pi])
#ttl = ax.set_title('',animated=True)
ttl = ax.text(.5, 1.05, '', transform = ax.transAxes, va='center')
def init():
ttl.set_text('')
img.set_data([0],[0])
return img, ttl
def func(n):
ttl.set_text(str(n))
img.set_data(vls,np.sin(vls+.02*n*2*np.pi))
return img, ttl
ani = animation.FuncAnimation(fig,func,init_func=init,frames=50,interval=30,blit=True)
plt.show()
Note that this may not work as expected if you have more than one axes in your figure. A much better solution is to expand the axes.bbox
just enough to capture your title + axis tick labels. I suspect there is code someplace in mpl to do that, but I don't know where it is off the top of my head.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With