Reputation: 340
I am using Python 3.6.3 with matplotlib 2.1.0 and what I want to achieve is to be able to remove some contours which are plotted prior to animation using contour() function. The contour plot needs to be visible at the start of the animation and only be removed once the user presses a key. The difficulty is that I need to use blitting for the animation. Yet, blitting restores the original canvas, such that even if removing the contour it still stays visible in the blitted background.
Here is the code that shows the problem:
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from numpy import mgrid, sin, cos, pi
def keypress(event):
if event.key == "delete":
for c in cs.collections: c.remove() # this doesn't work
cs.set_alpha(0.0) # this doesn't work either
phi = pi/2
def animate(i):
global phi
line.set_data([[0.0, sin(phi)], [0.0, cos(phi)]])
phi += 0.01
return line,
x,p = mgrid[-2:2:100*1j,-2:2:100*1j]
fig,ax = plt.subplots(1, 1, figsize=(19.2,10.8), dpi=100)
ax.set_xlim([-2,2])
ax.set_ylim([-2,2])
line, = ax.plot([], [], 'o-', lw=2, color='b')
cs = ax.contour(x, p, x**2 + p**2, levels=2, linewidths=0.8, colors='r')
fig.canvas.mpl_connect('key_press_event', keypress)
ani = animation.FuncAnimation(fig, animate, blit=True, interval=0, frames=2000)
plt.show()
If it is impossible to remove the contour, then at least I should be able to make it invisible or transparent, but I couldn't find a way to do this either. Please help! :)
Upvotes: 1
Views: 2290
Reputation: 339400
It is not easily possible to change anything in the canvas during an animation with blit=True
(the whole point of blitting is that the background does not change). While without the use of blit, there should not be any problem removing the lines or setting it invisible, blitting will always restore the original canvas background, even if some artist has been removed from it.
What we need to do is hence interrupt the animation after the artist removal, redraw the canvas, take a new snapshot of the background and restart the animation with a new background. While this in itself would be rather cumbersome, a possible solution is to mimic a resize event of the canvas, which would trigger exactly the described procedure. This is done in the following code.
(Note that this is working correctly with the Qt
backend, while some problems appear using Tk
, at least in version 2.1 of matplotlib.)
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from numpy import mgrid, sin, cos, pi
phi = pi/2.
def keypress(event):
if event.key == "delete":
try:
for c in cs.collections:
c.remove()
except ValueError:
pass
ani._handle_resize()
ani._end_redraw(None)
def animate(i):
global phi
line.set_data([[0.0, sin(phi)], [0.0, cos(phi)]])
phi += 0.01
return line,
x,p = mgrid[-2:2:100*1j,-2:2:100*1j]
fig,ax = plt.subplots(1, 1, figsize=(8,6), dpi=100)
ax.set_xlim([-2,2])
ax.set_ylim([-2,2])
line, = ax.plot([], [], 'o-', lw=2, color='b')
cs = ax.contour(x, p, x**2 + p**2, levels=2, linewidths=2, colors='r')
fig.canvas.mpl_connect('key_press_event', keypress)
ani = animation.FuncAnimation(fig, animate,
blit=True, interval=1, frames=2000)
plt.show()
Upvotes: 2