尝试使用matplotlib创建动画3d plot_surface时出现python错误

时间:2017-02-27 18:05:26

标签: python qt matplotlib

似乎这类文件的文档非常不完整,或者我只是完全在错误的位置查找。以前的问题似乎从来没有得到回答或看起来不同,不适用于此处。我希望解决方案能够提供当前不存在的此流程的文档。 (编辑我的错误 - one of the linked posts或多或少已存在的答案。)

我有几百个nx x ny数组,包含网格上PDE解的迭代。

预期的行为是随着时间的推移创建三维表面图的动画(显然迭代是帧)。我得到了第一个解决方案的表面图,但之后我得到了一个与qt相关的错误并且没有动画。

以下是行为的最小工作示例

# matplotlib stuff
from mpl_toolkits.mplot3d import axes3d, Axes3D
import matplotlib.pyplot as plt
from matplotlib import animation

# lots of array indexing will be had
import numpy

# gussy up matplotlib
from matplotlib import cm

def data_generating_function(p, epsilon, it):
# scale values down randomly until epsilon
    pn = numpy.empty_like(p)
    pt = [p.copy()]
    l2norm = 1
    while l2norm > epsilon:
        pn = p.copy()
        p = numpy.random.uniform() * pn
        l2norm = numpy.sqrt(numpy.sum((p - pn)**2) / numpy.sum(pn**2))
        pt = numpy.append(pt, [p], axis=0)
        it += 1
    return pt

def update_plot(i, data, plot):
    ax.clear()
    plot = ax.plot_surface(xv, yv, data[i,:], rstride=1, cstride=1, cmap=cm.plasma, linewidth=0, antialiased=True)
    return plot,

##
# main
##
nx = 200
ny = 100
epsilon = 1e-8
it = 0

# initialize
p = numpy.random.rand(ny, nx)
x = numpy.linspace(0, 1, nx)
y = numpy.linspace(0, 1, ny)

xv, yv = numpy.meshgrid(x, y)

# attach 3D axis to the figure
fig = plt.figure()
ax = Axes3D(fig)

# populate data
# data will contain several hundred nx x ny arrays
data = data_generating_function(p.copy(), epsilon, it)

# set the axes properties
ax.set_xlim(0, 1)
ax.set_ylim(0, 1)
ax.set_xlabel('$x$')
ax.set_ylabel('$y$')
ax.set_zlabel('$z$')
ax.view_init(30, 45)

# create the animation object
plot = ax.plot_surface(xv, yv, data[0,:], rstride=1, cstride=1, cmap=cm.plasma, linewidth=0, antialiased=True)
line_ani = animation.FuncAnimation(fig, update_plot, frames=it, fargs=(data, plot), interval=30, blit=False)

plt.show()

这里是追溯

Traceback (most recent call last):
  File "C:\Users\Walter\Anaconda3\lib\site-packages\matplotlib\backends\backend_qt5agg.py", line 197, in __draw_idle_agg
    FigureCanvasAgg.draw(self)
  File "C:\Users\Walter\Anaconda3\lib\site-packages\matplotlib\backends\backend_agg.py", line 464, in draw
    self.figure.draw(self.renderer)
  File "C:\Users\Walter\Anaconda3\lib\site-packages\matplotlib\artist.py", line 63, in draw_wrapper
    draw(artist, renderer, *args, **kwargs)
  File "C:\Users\Walter\Anaconda3\lib\site-packages\matplotlib\figure.py", line 1150, in draw
    self.canvas.draw_event(renderer)
  File "C:\Users\Walter\Anaconda3\lib\site-packages\matplotlib\backend_bases.py", line 1815, in draw_event
    self.callbacks.process(s, event)
  File "C:\Users\Walter\Anaconda3\lib\site-packages\matplotlib\cbook.py", line 549, in process
    proxy(*args, **kwargs)
  File "C:\Users\Walter\Anaconda3\lib\site-packages\matplotlib\cbook.py", line 416, in __call__
    return mtd(*args, **kwargs)
  File "C:\Users\Walter\Anaconda3\lib\site-packages\matplotlib\animation.py", line 831, in _start
    self._init_draw()
  File "C:\Users\Walter\Anaconda3\lib\site-packages\matplotlib\animation.py", line 1490, in _init_draw
    self._draw_frame(next(self.new_frame_seq()))
StopIteration

修改

我应该提到我碰巧知道数据中的解决方案是“正确的”(即我希望以我期望的形式获得数据),并且我知道这些图应该可以解决,因为我可以绘制任何给定的迭代作为一个表面本身(不是动画。)

类似的问题被问到here,但似乎从未得到过回答。

修改编辑

包含一个示例data_generating_function,将我的代码段转换为最小的工作示例,并澄清了预期的行为(以回应评论)。

编辑#3

我发现我错误地认为变量“it”是通过引用传递的。更改代码以使用“len(data)”代替修复问题。如果有人知道为什么会导致错误,我很好奇想知道。

1 个答案:

答案 0 :(得分:1)

正如您所发现的,frames参数必须是一个提供帧数或列表或可迭代的整数,为动画函数提供参数。

在您的情况下,您使用了变量itframes=it)。如果它为零,it = 0,动画将由零帧组成,因此立即停止,抛出上述错误。

重现此错误的最小示例是

import matplotlib.pyplot as plt
import matplotlib.animation

fig,ax = plt.subplots()
l, = ax.plot([],[])
x=[];y=[]

def animate(i):
    x.append(i)
    y.append(i**2/9.)
    l.set_data(x,y)
    ax.set_xlim(min(x), max(x)+1.e-5)
    ax.set_ylim(min(y), max(y)+1.e-5)

ani = matplotlib.animation.FuncAnimation(fig, animate, frames=0, interval=500)
plt.show()

设置frames = 10可以消除错误。

请注意即使在您修改后的代码版本中也是如此。 it始终为零。在python中,' by-reference'或者'按价值'不直接适用;相反,有可变和不可变的对象。像it这样的整数是不可变的,因此在函数定义的封闭范围内更改它不会在外部更改它。