Description
Bug report
Bug summary
Trying to give matplotlib.collections.QuadMesh.set_array()
the same argument as was used by matplotlib.axes.Axes.pcolormesh()
results in an error. Moreover, the argument format depends on the shading; an argument that is correct for shading='gouraud'
will be accepted and produce spurious graphics for shading='flat'
. In my opinion, the user should be able to use the same argument format for the update (via set_array
or another method if that causes backwards compatibility issues) than used for creation (via pcolormesh
), and not have to care about the shading when setting the data.
It was raised in a StackOverflow post from 2013 and the top answer (from 2015) gives workarounds, but I did not find anything in the issue tracker (here). It should at least be documented, the current doc only says "Set the image array from numpy array A".
Code for reproduction
import numpy as np
import matplotlib.pyplot as plt
def f(X, Y, t=0):
return np.sin(X+t*np.pi)*np.sin(Y)
xmin, xmax = 0.0, 4*np.pi
ymin, ymax = 0.0, 5*np.pi
Nx, Ny = 50, 40
x, y = np.linspace(xmin, xmax, num=Nx), np.linspace(ymin, ymax, num=Ny)
X, Y = np.meshgrid(x, y, indexing='ij')
zstart = f(X, Y)
run_number = np.random.rand()
# Intialize figure stuff
fig = plt.figure()
axs = [
plt.subplot(221, title='control flat'),
plt.subplot(222, title='test flat'),
plt.subplot(223, title='control gouraud'),
plt.subplot(224, title='test gouraud'),
]
def drawcmesh(X, Y, z, ax, shading):
ax.set_xlim(left=xmin, right=xmax)
ax.set_ylim(bottom=ymin, top=ymax)
cmesh = ax.pcolormesh(X, Y, z,
shading=shading, vmin=-1.5, vmax=1.5, cmap='hot')
return cmesh
zstart = f(X, Y)
perm_mesh = [
drawcmesh(X, Y, zstart, axs[1], shading='flat'),
drawcmesh(X, Y, zstart, axs[3], shading='gouraud')
]
drawcmesh(X, Y, zstart, axs[0], shading='flat')
drawcmesh(X, Y, zstart, axs[2], shading='gouraud')
def update(t):
z = f(X, Y, t)
for i in range(4):
ax = axs[i]
if i<2:
shading='flat'
else:
shading='gouraud'
if i%2 == 0:
# Control case: redraw by hand
axs[i].clear()
drawcmesh(X, Y, z, axs[i], shading=shading)
axs[i].set_title('control {}'.format(shading))
if i==1:
# Flat shading
# # The following would copy the syntax of plt.pcolormesh() but it
# # results in an error
# perm_mesh[0].set_array(z)
# The following does not error out but the plot is later incorrect
perm_mesh[0].set_array(z.ravel())
# # The following works
# perm_mesh[0].set_array(z[:-1, :-1].ravel())
if i==3:
# Gouraud shading
# # The following would copy the syntax of plt.pcolormesh() but it
# # results in an error
# perm_mesh[1].set_array(z)
# The following works
perm_mesh[1].set_array(z.ravel())
# # The following results in an error at draw time:
# perm_mesh[1].set_array(z[:-1, :-1].ravel())
# # Uncomment this to check that the initial drawing for the test case is correct
# plt.show(block=True)
plt.show(block=False)
for t in np.linspace(0.0, 4.0, num=50):
update(t)
fig.canvas.draw()
fig.canvas.flush_events()
Results
Cf commented code under # Flat shading
and # Gouraud shading
in the source for the various possibilities.
Spurious graphics for flat shading:
Error given by gouraud shading when dimensions do not match:
<current file>, line 93, in <module>
fig.canvas.draw()
File "<anaconda-site-packages>\matplotlib\backends\backend_agg.py", line 388, in draw
self.figure.draw(self.renderer)
File "<anaconda-site-packages>\matplotlib\artist.py", line 38, in draw_wrapper
return draw(artist, renderer, *args, **kwargs)
File "<anaconda-site-packages>\matplotlib\figure.py", line 1709, in draw
renderer, self, artists, self.suppressComposite)
File "<anaconda-site-packages>\matplotlib\image.py", line 135, in _draw_list_compositing_images
a.draw(renderer)
File "<anaconda-site-packages>\matplotlib\artist.py", line 38, in draw_wrapper
return draw(artist, renderer, *args, **kwargs)
File "<anaconda-site-packages>\matplotlib\axes\_base.py", line 2647, in draw
mimage._draw_list_compositing_images(renderer, self, artists)
File "<anaconda-site-packages>\matplotlib\image.py", line 135, in _draw_list_compositing_images
a.draw(renderer)
File "<anaconda-site-packages>\matplotlib\artist.py", line 38, in draw_wrapper
return draw(artist, renderer, *args, **kwargs)
File "<anaconda-site-packages>\matplotlib\collections.py", line 2037, in draw
self._meshWidth, self._meshHeight, coordinates)
File "<anaconda-site-packages>\matplotlib\collections.py", line 1985, in convert_mesh_to_triangles
c = self.get_facecolor().reshape((meshHeight + 1, meshWidth + 1, 4))
ValueError: cannot reshape array of size 7644 into shape (50,40,4)
Matplotlib version
- Operating system: Win10
- Matplotlib version: 3.1.1 (from conda)
- Matplotlib backend (
print(matplotlib.get_backend())
): Qt5Agg - Python version: 3.7.4