I am trying to get a 3D contour plot to shade, or have shadows so that it 'looks' 3D. I am using matplotlib, mainly due to the high quality of plots and would prefer to continue to use it.
Ultimately I would like a single or flat coloured surface with shadows cast on it in a matplotlib style plot.
I am using scipy to do some interpolation and skimage and marching cube algorithm to generate the contours. Then finally use that to create and shade the poly collection.
import numpy as np
from skimage import measure
from scipy.interpolate import griddata
import matplotlib as mpl
from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d.art3d import Poly3DCollection
from matplotlib.colors import LightSource
# Generate an grid to inerpolate to
X, Y, Z = np.meshgrid(0.0:1.0:50j, 0.0:1.0:50j, 0.0:1.0:50j)
# Interpolate (coor and phi are the numerical grid and scalar values)
F = griddata(coor, phi, (X, Y, Z), method='nearest')
# Make the contour, marching cubes
marchCubeSpace = 1.0 / 50.0
verts, faces, normals, values = measure.marching_cubes_lewiner(F, 0.5, spacing=(marchCubeSpace, marchCubeSpace, marchCubeSpace))
# Create Ploy3D
mesh = Poly3DCollection(verts[faces], alpha=1.0)
# An attempt to get some sort of height data.
facearray = np.array([np.array((np.sum(verts[face[:], 0]/3), np.sum(verts[face[:], 1]/3), np.sum(verts[face[:], 2]/3))) for face in faces])
# light source, ultimately I want to use not `reds` but just a red for all faces.
ls = LightSource(azdeg=45.0, altdeg=90.0)
rgb = ls.blend_hsv(rgb=ls.shade(facearray, plt.cm.Reds), intensity=ls.shade_normals(normals, fraction=0.25))
mesh.set_facecolor(rgb[:, 0])
# Plot
fig = plt.figure()
ax = fig.add_subplot(0, 0, 0, projection='3d')
ax.add_collection3d(mesh)

