Bring Drag & Drop to Dash with Dashboard Engine. 💫 Learn how at our next webinar!

Surface plot with dropdown: project_z not working

Hi,

I have a surface plot with two traces:

# create figure
fig = go.Figure()

# Add surface trace
fig.add_trace(go.Surface(z=dict_inteff[select_eff[0]]["z1"],x=dict_inteff[select_eff[0]]["x1"],y=dict_inteff[select_eff[0]]["y1"], 
                         cmin=dict_inteff[select_eff[0]]["zmin"], cmax=dict_inteff[select_eff[0]]["zmax"], colorscale="RdYlGn",
                         contours = {"z": {"show": True, "start": dict_inteff[select_eff[0]]["zmin"], "end": dict_inteff[select_eff[0]]["zmax"], "size": 0.2,"project_z":True}}
                         )
              )
fig.add_trace(go.Surface(z=dict_inteff[select_eff[0]]["z2"],x=dict_inteff[select_eff[0]]["x2"],y=dict_inteff[select_eff[0]]["y2"],
                         showscale=False, cmin=dict_inteff[select_eff[0]]["zmin"], cmax=dict_inteff[select_eff[0]]["zmax"], colorscale="RdYlGn",
                         contours = {"z": {"show": True, "start": dict_inteff[select_eff[0]]["zmin"], "end": dict_inteff[select_eff[0]]["zmax"], "size": 0.2,"project_z":True}},
                         )
              )

When I run this code contour lines are projected on the z axis.

But when I update the input data for the surface plot with a dropdown button:

buttons1 = [dict(method = "restyle",
                  args = [{
                          'x': [dict_inteff[select_eff[k]]["x1"], dict_inteff[select_eff[k]]["x2"]],
                          'y': [dict_inteff[select_eff[k]]["y1"], dict_inteff[select_eff[k]]["y2"]],
                          'z': [dict_inteff[select_eff[k]]["z1"], dict_inteff[select_eff[k]]["z2"]],
                          'cmin': [dict_inteff[select_eff[k]]["zmin"],dict_inteff[select_eff[k]]["zmin"]],
                          'cmax': [dict_inteff[select_eff[k]]["zmax"],dict_inteff[select_eff[k]]["zmax"]],
                          'contours':[ {"z": {"show": True,"start": dict_inteff[select_eff[k]]["zmin"], "end": dict_inteff[select_eff[k]]["zmax"],"size": 0.2,"project_z":True}},
                                       {"z": {"show": True,"start": dict_inteff[select_eff[k]]["zmin"], "end": dict_inteff[select_eff[k]]["zmax"],"size": 0.2,"project_z":True}}]
                            }],                    
                  label = select_eff[k] )   for k in range(0, len(select_eff))]

the contour ist not projected on the z-axis as soon as I select another input data with the button. So the “project_z”:True inside the Button is not working.
What am I doing wrong?
Any help would be appreciated :wink:

Best regards
Peter

Here is a working example code where you can see the problem:

x1 = [1,2,3,4,5]
y1 = [1,2,3,4,5]
z1 = [[0, 1, 0, 1, 0],
     [1, 0, 1, 0, 1],
     [0, 1, 0, 1, 0],
     [1, 0, 1, 0, 1],
     [0, 1, 0, 1, 0]]
x2 = [1,2,3,4,5]
y2 = [1,2,3,4,5]
z2 = [[1, 0, 1, 0, 1],
     [0, 1, 0, 1,0],
     [1, 0, 1, 0, 1],
     [0, 1, 0, 1, 0],
     [1, 0, 1, 0, 1]]
zmin = 0
zmax = 1

dict_inteff={}
dict_inteff["test1"]={"x":x1,"y":y1,"z":z1,"zmin":zmin,"zmax":zmax}
dict_inteff["test2"]={"x":x2,"y":y2,"z":z2,"zmin":zmin,"zmax":zmax}
#key list
select_eff=["test1","test2"]

# create figure
fig = go.Figure()

# Add surface trace
fig.add_trace(go.Surface(z=dict_inteff[select_eff[0]]["z"],x=dict_inteff[select_eff[0]]["x"],y=dict_inteff[select_eff[0]]["y"], 
                         #cmin=dict_inteff[select_eff[0]]["zmin"], cmax=dict_inteff[select_eff[0]]["zmax"], colorscale="RdYlGn",
                         contours = {"z": {"show": True, "start": dict_inteff[select_eff[0]]["zmin"], "end": dict_inteff[select_eff[0]]["zmax"], "size": 0.05,"project_z":True}}
                         )
              )

buttons1 = [dict(method = "restyle",
                  args = [{
                          'x': [dict_inteff[select_eff[k]]["x"]],
                          'y': [dict_inteff[select_eff[k]]["y"]],
                          'z': [dict_inteff[select_eff[k]]["z"]],
                          'cmin': [dict_inteff[select_eff[k]]["zmin"]],
                          'cmax': [dict_inteff[select_eff[k]]["zmax"]],
                          'contours':[ {"z": {"show": True,"start": dict_inteff[select_eff[k]]["zmin"], 
                                              "end": dict_inteff[select_eff[k]]["zmax"],
                                              "size": 0.05,"project_z":True}}]
                            }],                    
                  label = select_eff[k] )   for k in range(0, len(select_eff))] 

# Add dropdown
fig.update_layout(
    updatemenus=[
        dict(active=0,
            buttons=buttons1,
            pad={"l": 35},
            x=0.07,
            y=1.1,
            xanchor='left',
            yanchor='top')
            ]  
    )

fig.show()

Hi @pepo83,

I displayed the json version of your code and used it to simplify button definitions, as well as to get it working:

fig=go.Figure(go.Surface({'contours': {'z': {'end': 1, 
                                             'project': {'z': True}, 
                                             'show': True, 
                                             'start': 0,
                                             'size': 0.05,  
                                             'width':1}},
                          'x': [1, 2, 3, 4, 5],
                          'y': [1, 2, 3, 4, 5],
                          'z': [[0, 1, 0, 1, 0], [1, 0, 1, 0, 1], [0, 1, 0, 1, 0], [1, 0, 1, 0, 1], [0, 1, 0, 1, 0]], 
                         'coloraxis': "coloraxis"}))

updatemenus  = [{
     'active': 0,
     'buttons': [{'args': [{'z': [[[0, 1, 0, 1, 0], [1, 0, 1, 0, 1], [0, 1, 0, 1,
                                  0], [1, 0, 1, 0, 1], [0, 1, 0, 1, 0]]]}],
                  'label': 'test1',
                  'method': 'restyle'},
                 {'args': [{'z': [[[1, 0, 1, 0, 1], [0, 1, 0, 1, 0], [1, 0, 1, 0,
                                  1], [0, 1, 0, 1, 0], [1, 0, 1, 0, 1]]]}],
                  'label': 'test2',
                  'method': 'restyle'}],
     'pad': {'l': 35},
     'x': 0.07,
     'xanchor': 'left',
     'y': 1.1,
     'yanchor': 'top'
      }]

fig.update_layout(width=600, height=600,
                  updatemenus=updatemenus, scene_zaxis_range=[-3, 1],
                 scene_camera_eye=dict(x=1.750, y=1.75, z=0.75),
                  coloraxis_colorscale="matter_r",
                 coloraxis_colorbar_thickness=25,
                 coloraxis_colorbar_len=0.6)

In button definition don’t set all trace attributes, but only what is changing when you are clicking one of the buttons. In your case only the surface z-values are changing.
In order to let user inspect the projected contours, I enlarged the scene zaxis_range, and the camera eye position.
cmin=0, cmax=1 have been removed, because these are the default value deduced by plotly.js from your data.

1 Like

Hi @empet ,

thank you for your help!
The example code is very simplified, in my real use case I have 2 traces and more complex data, so I also need the cmin cmax so that both traces have the same color scale.
But It seems that the “project_z”:True is the problem, if i replace it with project’: {‘z’: True} (for the figuer and the button), the example code is also working.