Problem with 3D contour plots in matplotlib

Question:

I created a 3D contour map in Mathematica a while back, and I am trying to do it in Python this time. First let me show you what I obtained:

Mathematica:

enter image description here

Python:

enter image description here

Now, I would like the foreground (the visible part of the hills) to hide the background (the invisible part). In the Python version, it seems as if you are watching these mountains as if you were beneath them. I am not sure how to fix it, to make it more like the Mathematica version (I don’t care about the colors, I actually like the colors in the Python version better). Here is the code:

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

plt.rcParams["lines.linewidth"]=0.5
fig = plt.figure()
ax = fig.add_subplot(111, projection="3d")
X, Y = np.mgrid[-3:3:30j, -3:3:30j]
Z= np.exp(-(abs(X)**2 + abs(Y)**2)) + 0.8*np.exp(-4*((abs(X-1.5))**4.2 + (abs(Y-1.4))**4.2))

ax.plot_surface(X, Y, Z, cmap="coolwarm", rstride=1, cstride=1, alpha=0.2)
# ax.contourf(X, Y, Z, levels=60, colors="k", linestyles="solid", alpha=0.9, antialiased=True) 
ax.contour(X, Y, Z, levels=60, linestyles="solid", alpha=0.9, antialiased=True) 

plt.show()
plt.savefig('contour3D.png', dpi=300)
Asked By: Vincent Granville

||

Answers:

I think solution is to simply set alpha to 1, because making the surface transparent shows the background behind it.

ax.plot_surface(X, Y, Z, cmap="coolwarm", rstride=1, cstride=1, alpha=1)

new graph

Answered By: matoqq

Matplotlib is not really great when it comes to 3D plot. You lowered the opacity of the surface to make the contour lines visible. I’m afraid that what you are asking is impossible to achieve with matplotlib.

What if you were to try a different library? For example Plotly or Mayavi?

import numpy as np
import plotly.graph_objects as go
import matplotlib

X, Y = np.mgrid[-3:3:100j, -3:3:100j]
Z= np.exp(-(abs(X)**2 + abs(Y)**2)) + 0.8*np.exp(-4*((abs(X-1.5))**4.2 + (abs(Y-1.4))**4.2))

fig = go.Figure(data=[
    go.Surface(
        x=X, y=Y, z=Z,
        contours={
            "z": {"show": True, "start": 0, "end": 1, "size": 1/60,
                  "width": 1, "usecolormap": True}
        }, showscale=False, colorscale="Aggrnyl"
    )
], layout=dict(
    scene=dict(aspectmode="manual", aspectratio=dict(x=1.5, y=1.5, z=1))
))

w, h, dpi = 15, 7.5, 300 # width and heigh in inches
fig.write_image(file="test2.png", width=w*dpi, height=h*dpi, scale=1)

Here is a few resources:

Answered By: Davide_sd