Search code examples
pythonnumpymatplotlibclassificationdata-analysis

How to plot multiple three-dimensional surface plots with matplotlib in the same plane


My goal is to plot the probability distribution functions (pdfs) of two classes. Each class has Gaussian likelihood and equivalent covariance matrices, but different mean vectors. I want both pdfs on the same plane in the z-axis, with the x and y axes containing the projections of the pdfs. The following code (mostly borrowed from here) plots one of the pdfs:

# Our 2-dimensional distribution will be over variables X and Y
N = 100
X = np.linspace(-10, 15, N)
Y = np.linspace(-10, 15, N)
X, Y = np.meshgrid(X, Y)

# Mean vector and covariance matrix
mu1 = np.array([8, 2])
mu2 = np.array([2,8])
Sigma1 = Sigma2 = np.array([[4.1,0],[0,2.8]])


# Pack X and Y into a single 3-dimensional array
pos = np.empty(X.shape + (2,))
pos[:, :, 0] = X
pos[:, :, 1] = Y

F1 = multivariate_normal(mu1, Sigma1)
F2 = multivariate_normal(mu2, Sigma2)
Z1 = F1.pdf(pos)
Z2 = F2.pdf(pos)
# Create a surface plot and projected filled contour plot under it.
fig1 = plt.figure(figsize=[10,10])

ax1 = fig1.gca(projection='3d')

ax1.plot_surface(X, Y, Z1, rstride=3, cstride=3, linewidth=1, 
antialiased=True,cmap=cm.inferno)

cset = ax1.contourf(X, Y, Z1, zdir='z', offset=-0.15, cmap=cm.inferno)

# Adjust the limits, ticks and view angle
ax1.set_zlim(-0.15,0.2)
ax1.set_zticks(np.linspace(0,0.2,5))
ax1.view_init(27, -21)


 plt.show()

This is the plot that results from the above code: plot_surfaces for plotting bivariate pdf. However, I need to plot both Z1 and Z2 on the same plane. If I try creating two plots, they overlap and the Z2 pdf cannot be seen. Tweaking the code slightly, I get roughly what I want:

ax1 = fig1.gca(projection='3d')
ax2 = fig1.gca(projection='3d')
ax1.plot_wireframe(X, Y, Z1, rstride=3, cstride=3, linewidth=1, 
antialiased=True,cmap=cm.inferno)

ax2.plot_wireframe(X,Y,Z2,rstride=3, cstride=3, linewidth=1, 
antialiased=True,cmap=cm.inferno)

the resulting plot of which can be found here: wireframe method to plot 2 bivariate pdfs. But these plots are still overlapping. How can I get around this issue? I want the result to be styled as the first plot, with the surface_plot method and projections on the x-y plane.


Solution

  • You can play with alpha:

    ax1.plot_surface(X, Y, Z1, rstride=3, cstride=3, linewidth=1,
    antialiased=True,cmap=cm.inferno, alpha = 0.5)
    ax1.plot_surface(X, Y, Z2, rstride=3, cstride=3, linewidth=1,
    antialiased=True,cmap=cm.inferno, alpha = 1)
    cset = ax1.contourf(X, Y, Z1, zdir='z', offset=-0.15, cmap=cm.inferno, alpha=1)
    cset = ax1.contourf(X, Y, Z2, zdir='z', offset=-0.15, cmap=cm.inferno, alpha=0.5)
    

    But in some cases you can get the same results by just summing your pdf's

    ax1.plot_surface(X, Y, Z1 + Z2, rstride=3, cstride=3, linewidth=1, antialiased=True,cmap=cm.inferno)
    cset = ax1.contourf(X, Y, Z1 + Z2, zdir='z', offset=-0.15, cmap=cm.inferno)