我正在编写一个简单的代码来演示点源的振荡行为。我想用matplotlib.animation制作一个动画。
我有一个工作代码(见下文),但它依赖于预先计算所有帧的值并将它们保存在内存中。我一直在尝试使用生成器重新编写它,以便在需要时可以计算每个帧,如下例所示:
http://matplotlib.org/examples/animation/animate_decay.html
我已经设法使用此处给出的指导解决了一些问题:
http://matplotlib.1069221.n5.nabble.com/Matplotlib-1-1-0-animation-vs-contour-plots-td18703.html
但是现在我在更新我无能为力的动画时会得到KeyErrors:
Traceback (most recent call last):
File "/usr/lib/pymodules/python2.7/matplotlib/backend_bases.py", line 1092, in _on_timer
ret = func(*args, **kwargs)
File "/usr/lib/pymodules/python2.7/matplotlib/animation.py", line 315, in _step
still_going = Animation._step(self, *args)
File "/usr/lib/pymodules/python2.7/matplotlib/animation.py", line 177, in _step
self._draw_next_frame(framedata, self._blit)
File "/usr/lib/pymodules/python2.7/matplotlib/animation.py", line 195, in _draw_next_frame
self._pre_draw(framedata, blit)
File "/usr/lib/pymodules/python2.7/matplotlib/animation.py", line 208, in _pre_draw
self._blit_clear(self._drawn_artists, self._blit_cache)
File "/usr/lib/pymodules/python2.7/matplotlib/animation.py", line 248, in _blit_clear
a.figure.canvas.restore_region(bg_cache[a])
KeyError: <matplotlib.axes.PolarAxesSubplot object at 0x37e2290>
代码:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import types
class monopole(object):
def __init__(self):
"""
Construct by initialising the itnernal fields
"""
self.omega = 2000.0 # frequency
self.Q = 1.0 # strength
self.c = 1500. # speed of sound
self.rho = 1000. # density
self.k = self.omega/self.c # wavenumber
def getSources(self,thetaGrid,Rgrid,t):
"""
Calculates the monopole source values for the given time on the specified mesh
NOTE: the time-dependency here is exemplary, not a proper monopole formula
"""
return self.Q*self.rho*self.c*self.k/(4.*np.pi*Rgrid) * np.sin(self.omega*max(1e-20,t))
def getData():
"""
Creates a constructor for a list filled with time and data values
"""
t = getData.T0
cnt = 0
while cnt < getData.nT:
cnt+=1
t += getData.T1/getData.nT
yield t, getData.source.getSources(getData.thetaGrid,getData.Rgrid,t)
def updatePreCalc(i,ax,thetaGrid,Rgrid,data):
"""
Clears and updates the current plot to show the new frame
"""
ax.cla()
im = plt.contour(thetaGrid, Rgrid, data[i], 100)
return im,
def update(data,ax,thetaGrid,Rgrid):
"""
Clears and updates the current plot to show the new frame
"""
ax.cla()
t,z = data
im = plt.contour(thetaGrid, Rgrid, z, 100)
def setvisible(self,vis):
for c in self.collections: c.set_visible(vis)
im.set_visible = types.MethodType(setvisible,im,None)
im.axes = ax
return im,
# GRID
theta = np.linspace(0.,2.*np.pi,360)
R = np.linspace(0.1,1.0,50)
thetaGrid, Rgrid = np.meshgrid(theta, R)
# CONSTANTS
# initialise a monopole object
mon1 = monopole()
# initialise the timing function
getData.T0 = 0. # start time
getData.T1 = 10. # max time
getData.nT = 1000 # no. time intervals
# associate the timing function with the grid and monopole
getData.thetaGrid = thetaGrid
getData.Rgrid = Rgrid
getData.source = mon1
# create data for each frame
time,data = [0.]*getData.nT, [0.]*getData.nT
i = 0
for frame in getData():
time[i] = frame[0]
data[i] = frame[1]
i += 1
# PLOTTING
# set the window
fig = plt.figure(figsize=(12,10))
plt.subplot(1,1,1,polar=True)
# initial state
im = plt.contour(thetaGrid,Rgrid, mon1.getSources(thetaGrid,Rgrid,0.), 100)
plt.colorbar(im)
ax = fig.gca()
# aimate
# This works:
#ani = animation.FuncAnimation(fig, updatePreCalc, frames=xrange(getData.nT), fargs=(ax,thetaGrid,Rgrid,data), interval=1)
# This doesn't work
ani = animation.FuncAnimation(fig, update, getData, blit=True,fargs=(ax,thetaGrid,Rgrid), interval=1, repeat=False)
plt.show()