Problem summary
I have a mesh made by quadrilateral elements with a scalar field defined over the nodes of the elements. I am using Poly3DCollection
to plot the mesh with the elements coloured by the scalar field. However, I am forced to average the scalar field over the vertices composing each 3D polygon because I cannot find a way to have a smooth variation of the color of the faces based on the value of the scalar field at each vertex. Something similar was asked in this question, but the answer seems to work only for 2D paths and polygons.
Code
Below you can find a MWE to replicate my situation. As you can see, to set the color of the faces of each 3D polygon, I have to average the scalar field defined over the four vertices. How can I get a smooth variation of the color of the faces based on the value of the scalar field at the vertices?
import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.mplot3d.art3d import Poly3DCollection
# Create figure and axes
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
# Create coordinates of the vertices
vertices = [np.array([[.25, 0., 0.], [.75, 0., 0.], [.75, .3, .5], [.25, .3, .5]]),
np.array([[.25, .3, .5], [.75, .3, .5], [.75, .6, .5], [.25, .6, .5]]),
np.array([[.25, .6, .5], [.75, .6, .5], [.75, .9, 1.], [.25, .9, 1.]])]
# Create random scalar field over the vertices
scalar = np.random.rand(3, 4)
# Modify scalar field such that values are consistent over coincident vertices
scalar[1, 0:2] = scalar[0, 2:]
scalar[2, 0:2] = scalar[1, 2:]
# Average scalar field over each face
averaged_scalar = np.mean(scalar, axis=1)
# Create 3d polygons
pc = Poly3DCollection(vertices, linewidths=.1)
# Create normalized colormap
m = mpl.cm.ScalarMappable(cmap=mpl.cm.jet)
m.set_array(scalar)
m.set_clim(vmin=np.amin(averaged_scalar), vmax=np.amax(averaged_scalar))
rgba_array = m.to_rgba(averaged_scalar)
pc.set_facecolor([(i[0], i[1], i[2]) for i in rgba_array])
# Set color of the edges
pc.set_edgecolor('k')
# Add polygons to plot
ax.add_collection3d(pc)
# Show plot
plt.show()