Search code examples
pythonmatplotlibsurfacematplotlib-3d

How do I highlight a slice on a 3D surface plot?


I have a 3D surface plot. I would also like to plot slices of this plot in 2D, and somehow indicate on the 3D plot where the slices came from (such as coloring the points along the slice to 'highlight' the slice, or plotting an intersecting plane or something).

Following is an example where I am simply setting a particular row to 0 so I can see where the slice is on the 3D plot.

import numpy as np
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt


# Grid and test function
N = 29;
x,y = np.linspace(-1,1, N*2), np.linspace(-1,1, N)
X,Y = np.meshgrid(x,y)
F = lambda X,Y : np.sin(10*X)/(1+5*(X**2+Y**2))
Z = F(X,Y)

# 3D Surface plot
plt.figure(figsize = (5,6))
Z2 = Z.copy(); Z2[10,:] = 0 # <----- Replace this code
ax = plt.subplot(211, projection='3d')
ax.plot_surface(X,Y,Z2)

# 2D Plot of slice of 3D plot 
plt.subplot(212)
plt.plot(x,Z[10,:])
plt.show()

plt.savefig('surfacePlotHighlight.png')

3D surface plot and 2D slice


Solution

  • You can color slices in the X or Y directions using the facecoloroptions in plot_surface, and a similar setting of the color in plot. E.g.

    import numpy as np
    from mpl_toolkits.mplot3d import Axes3D
    import matplotlib.pyplot as plt
    
    # Grid and test function
    N = 29;
    x,y = np.linspace(-1,1, N*2), np.linspace(-1,1, N)
    X,Y = np.meshgrid(x,y)
    F = lambda X,Y : np.sin(10*X)/(1+5*(X**2+Y**2))
    Z = F(X,Y)
    
    # 3D Surface plot
    plt.figure(figsize = (5,6))
    ax = plt.subplot(211, projection='3d')
    # Normalise Y for calling in the cmap.
    Ys = Y/Y.max()
    cmap = plt.cm.viridis
    ax.plot_surface(X, Y, Z2, facecolors=cmap(Ys))
    
    # 2D Plot of slice of 3D plot 
    # Normalise y for calling in the cmap.
    ys = y/y.max()
    plt.subplot(212)
    plt.plot(x,Z[10,:], color=cmap(ys[10]))
    plt.plot(x,Z[20,:], color=cmap(ys[20]))
    plt.show()
    
    plt.savefig('surfacePlotHighlight.png')
    

    enter image description here

    EDIT: This can be used to highlight a single row (or column, or arbitrary set of points) by editing the color array to call out specific cells, such as:

    # 3D Surface plot
    plt.figure(1,figsize = (5,6))
    ax = plt.subplot(211, projection='3d')
    # Create array to specify color of each pixel on surface
    Ys = Y*0
    Ys[:,:] = .3
    Ys[10] = 1
    Ys[20] = .7
    cmap = plt.cm.viridis
    ax.plot_surface(X, Y, Z, facecolors=cmap(Ys))
    
    # 2D Plot of slice of 3D plot 
    # Normalise y for calling in the cmap.
    ys = Ys[:,0]
    plt.subplot(212)
    plt.plot(x,Z[10,:], color=cmap(ys[10]))
    plt.plot(x,Z[20,:], color=cmap(ys[20]))
    plt.show()
    
    plt.savefig('surfacePlotHighlight.png')
    

    enter image description here