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.
The expected behavior is to create an animation of the 3d surface plots over time (where obviously iterations are the frames). I get a surface plot of the first solution, however after that I am getting a qt-related error and there is no animation.
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" (i.e. 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).
Edit #3
I figured out that I was erroneously assuming that variable "it" was being passed by reference. Changing the code to use "len(data)" instead fixed the problem. If anyone knows why this causes the error that is given, I am curious enough to want to know.