Overlaying 2D contour plot over a 3D surface with different datasets

Is it possible?
I have been reading and trying for a few days and I still can’t figure out if this is something I could do easily with plotly and Dash. I would like to ask if this is something that can possibly be done, and if so, how to. Thanks! More info:

I have 3D surface plot of the seabed (bathymetry or depth of the ocean), as shown below. On it, I want to overlay a contour plot of the water temperature (different data to seabed depth) for a single depth. As an example, let’s say I want to overlay water temperature at 1000m deep using 2D contour lines that hover flat at that depth. Eventually I will like to add a dropdown to select any depth and update the figure accordingly. But for the time being and as a proof of concept, I’d like to see if it is actually possible to overlay such 2D contour plot at a given z level of a surface plot.

Hi @CFL08, welcome to the forum. Do you mean something like below ?

If you want to plot something like this it is possible with plotly and dash.

Hello @akroma, thanks for the welcome. It’s always daunting participating in a professional forum as a “newbie”.
Your proposed plot is somewhat similar to what I want and indicates that it may be possible. In my case I would have my topography surface (like the one I posted or like the surface that appears at the top of your figure). Then, I just want to add a single flat layer (like one of the several that you show below your surface).

In my case, however, I would like to:

  • Display black contours on the 2D surface without filling.
  • Preferably having the rest of the 2D surface transparent.
  • Consider that the the 2D will inevitably intersect with the 3D surface where they share the same Z value

What is the approach to insert those 2D surface with the rest to get to your figure?

Hey @CFL08 ,

I don’t have real data set at the moment but i created an example for you. Lets say you have flat surfaces at different depths.

import plotly.graph_objs as go

z1 = [

z2 = [[zij-1 for zij in zi] for zi in z1]
z3 = [[zij-2 for zij in zi] for zi in z1]

fig = go.Figure()

for step in range(3):
    fig.add_trace(go.Surface(z=z1,  visible=False, showscale=False)),
    fig.add_trace(go.Surface(z=z2,  visible=False, showscale=False)),
    fig.add_trace(go.Surface(z=z3,  visible=False, showscale=False)),

# Show First Layer
fig.data[0].visible = True

# Create slider


steps = []
for i in range(3):   

    step = dict(method="update",
                label = str(depth[i]),
                args = [{"visible": [False] * len(fig.data)},
                        {"title": "Depth: " + str(depth[i])}
    step["args"][0]["visible"][i] = True  

sliders = [dict(active=0, 
                currentvalue={"prefix": "Depth: ", "suffix": " km"},
                pad={"t": 50},

#Button (Show All Traces)
fig.update_layout(updatemenus=[dict(type = "buttons", direction = "left",

                                                  label="Show All Traces"
                                    pad={"r": 0, "t": 30},

fig.update_layout(scene=dict(zaxis=dict(range=[1, 5],autorange=False)), sliders=sliders)



To create flat surface, lets say you have lon, lat, dat values.

fig = go.Figure()

fig.add_trace(go.Surface(x=lon, y=lat, z=np.ones(shape=lon.shape) * constant ,  # constant = your desired depth
                                            surfacecolor = dat,                 # color corresponds to data

But I am not sure if we can create flattened 3D contours without filling.
If I discover something I’ll let you know, for dropdown menus and more functionality you can combine your plot with Dash.

Have a nice day.

1 Like