简体   繁体   English

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

[英]python error when trying to a create an animated 3d plot_surface with matplotlib

It seems like the documentation for something like this is very much incomplete, or I am just altogether looking in the wrong spot. 看起来像这样的文档非常不完整,或者我只是在错误的地方寻找。 Previous questions seem to have never been answered or seem different enough not to apply here. 以前的问题似乎从未得到解答,或者看起来足够不同,无法在此处应用。 My hope is that a solution will provide documentation for this process that does not currently exist. 我希望有一个解决方案可以为该过程提供当前不存在的文档。 ( Edit How wrong I was - the answer more or less already existed at one of the linked posts .) 编辑我错了- 链接的帖子之一或多或少已经存在答案。)

I have a few hundred nx x ny arrays containing iterations of solutions of a PDE over a grid. 我有数百个nx x ny数组,其中包含PDE在网格上的解决方案迭代。

The expected behavior is to create an animation of the 3d surface plots over time (where obviously iterations are the frames). 预期的行为是随时间创建3d曲面图的动画(其中明显是迭代)。 I get a surface plot of the first solution, however after that I am getting a qt-related error and there is no animation. 我得到第一个解决方案的表面图,但是此后,我遇到了与qt相关的错误,并且没有动画。

Here is a minimal working example of the behavior 这是该行为的最小工作示例

# 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()

and here is the traceback 这是回溯

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

Edit 编辑

I should mention that I happen to know that the solutions in data are "correct" (ie have the data I expect in the form I expect), and I know that the plots should work out because I can plot any given iteration as a surface by itself (not animated.) 我应该提一下,我碰巧知道数据中的解是“正确的”(即,我期望的数据以我期望的形式出现),并且我知道这些图应该可以计算出来,因为我可以将任何给定的迭代绘制为表面本身(非动画)。

A similar question was asked here but appears never to have been answered. 在这里提出类似的问题,但似乎从未得到回答。

Edit Edit 编辑编辑

Included an example data_generating_function to turn my code snippet into a minimal working example and clarified the expected behavior (in response to comment). 包括一个示例data_generating_function,可以将我的代码片段转换为一个最小的工作示例,并阐明了预期的行为(以回应评论)。

Edit #3 编辑#3

I figured out that I was erroneously assuming that variable "it" was being passed by reference. 我发现我错误地认为变量“ it”是通过引用传递的。 Changing the code to use "len(data)" instead fixed the problem. 将代码更改为使用“ len(data)”可以解决该问题。 If anyone knows why this causes the error that is given, I am curious enough to want to know. 如果有人知道为什么这会导致给出的错误,我很想知道。

As you found out, the frames argument must be an integer providing the number of frames or a list or iterable, providing the argument to the animation function. 如您所知, frames参数必须是提供frames的整数,或者是一个列表,或者是可迭代的,并为animation函数提供参数。

In your case you used the variable it ( frames=it ). 在您的情况下,您使用了变量itframes=it )。 In case it is zero, it = 0 , the animation will consist of zero frames and therefore immediately stop, throwing the above error. 如果为零, it = 0 ,动画将由零帧组成,因此将立即停止,并抛出上述错误。

A minimal example to reproduce this error is 重现此错误的最小示例是

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()

Setting frames = 10 gets rid of the error. 设置frames = 10消除错误。

Be aware of the fact that even in your modified version of the code. 请注意,即使在代码的修改版本中也是如此。 it is constantly zero. it一直为零。 In python the concepts of 'by-reference' or 'by-value' are not directly applicable; 在python中,“按引用”或“按值”的概念不直接适用; instead there are mutable and immutable objects. 而是有可变且不可变的对象。 Integers, like it are immutable, therefore changing it in the enclosing scope of the function definition, does not change it outside. 像整数一样, it是不可变的,因此在函数定义的封闭范围内对其进行更改不会在外部进行更改。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM