Is it possible to use modeBarButtonsToAdd on Scatter3d plots?

That’s my question… Is it possible to use modeBarButtonsToAdd on Scatter3d plots? I have tried one of the examples in Jupyter and no buttons other than default. The following code does not give me a plot with the additional buttons.

import plotly.express as px
df = px.data.iris()
fig = px.scatter_3d(df, x=‘sepal_length’, y=‘sepal_width’, z=‘petal_width’,
color=‘species’)
fig.update_layout(
dragmode=‘drawopenpath’,
newshape_line_color=‘cyan’,
title_text=‘Draw a path to separate versicolor and virginica’,
modebar_add=[‘drawline’,
‘drawopenpath’,
‘drawclosedpath’,
‘drawcircle’,
‘drawrect’,
‘eraseshape’
]
)

fig.show()

Hello @wanderingnature welcome to the forums.

You need to add this to the config, see also:

I checked that, and that page has an example of 2d scatter which works perfectly.

import plotly.express as px

df = px.data.iris()

fig = px.scatter(df, x=‘petal_width’, y=‘sepal_length’, color=‘species’)

fig.update_layout(
dragmode=‘drawopenpath’,
newshape_line_color=‘cyan’,
title_text=‘Draw a path to separate versicolor and virginica’
)

fig.show(config={‘modeBarButtonsToAdd’: [‘drawline’,
‘drawopenpath’,
‘drawclosedpath’,
‘drawcircle’,
‘drawrect’,
‘eraseshape’
]})

Then I tried another example with scatter_3d from this page: 3d scatter plots in Python, and added the same config= as above:

import plotly.express as px
df = px.data.iris()
fig = px.scatter_3d(df, x=‘sepal_length’, y=‘sepal_width’, z=‘petal_width’,
color=‘species’)
fig.update_layout(
dragmode=‘drawopenpath’,
newshape_line_color=‘cyan’,
title_text=‘Draw a path to separate versicolor and virginica’
)

fig.show(config={‘modeBarButtonsToAdd’: [‘drawline’,
‘drawopenpath’,
‘drawclosedpath’,
‘drawcircle’,
‘drawrect’,
‘eraseshape’
]})

The data and configuration are the same, only difference is the addition of Z values and scatter_3d instead of scatter

Also, per the page: Configuration in Python
New in v5.0

The layout.modebar.add attribute can be used instead of the approach used above:

This should work in version >5 (I’m running 5.20.0) but it doesn’t with scatter_3d:

import plotly.express as px
df = px.data.iris()
fig = px.scatter_3d(df, x=‘sepal_length’, y=‘sepal_width’, z=‘petal_width’,
color=‘species’)

fig.update_layout(
dragmode=‘drawopenpath’,
newshape_line_color=‘cyan’,
title_text=‘Draw a path to separate versicolor and virginica’,
modebar_add=[‘drawline’,
‘drawopenpath’,
‘drawclosedpath’,
‘drawcircle’,
‘drawrect’,
‘eraseshape’
]
)

fig.show()

1 Like

I’m sorry, I’ve overseen the 3dscatter. So my guess would be that drawing and selections works for 2d only.

How would you draw a rectangle in 3 dimensions?

Well, it’s a rectangle, which is two dimensional, so I expected it to draw a 2d shape which could be drawn in a 3d space. I was hoping to be able to enable some annotation using the drawing tools. I didn’t think they were themselves working in 3d but rather overlayed on top of the plot (thus they are 2d). It isn’t listed as a limitation or restriction nor does it say that the shapes are drawn within the plot (e.g. using the dimensions, either 2d or 3d). It would be nice if they could draw ‘within’ the plot. As it is I’ll just add an option for the user to get a flattened plot to enable the drawing tools.

I understand, makes sense what you are saying.

Unfortunately, it seems that rendering in a Flask app is not getting the modebar correct either. This must be somewhat working because I can draw a freeform line in black on the 2d plot… but the buttons for the controls are not in the modebar. It works perfectly in Jupyter.

x_max = df[‘X’].max()
z_max = 35 # Given as per your description

    fig = px.scatter(df, x='X', y='Z', color='Label',
                        color_discrete_map={
                            "Ground" : "rgba(111,78,55,1)",
                            "Vegetation" : "rgba(67,102,29,1)"
                        })
    fig.update_traces(marker=dict(size=1.25))
    fig.update_layout(
        legend=dict(
            title_font_size=16,  # Adjusts the legend title font size
            font=dict(
                size=14,  # Adjusts the legend text font size
            ),
        ),
        xaxis=dict(
            title='Slice Length (meters)',
            showticklabels=True,
            range=[0,x_max]  # Setting the x-axis range
        ),
        yaxis=dict(
            title='Height (meters)',
            showticklabels=True,
            scaleanchor='x',
            scaleratio=1,
            constrain='domain',
            range=[0,z_max]  # Adjusting the y-axis range
        ),
        title_text=f'<b>Flattened LiDAR Slice Number: {slicenum}</b>',
        dragmode='drawopenpath',
        newshape_line_color='black',
        modebar_add=['drawline',
                     'drawopenpath',
                     'drawclosedpath',
                     'drawcircle',
                     'drawrect',
                     'eraseshape']
    )

graphJSON = json.dumps(fig, cls=plotly.utils.PlotlyJSONEncoder)
return render_template("plot.html", graphJSON=graphJSON). 

In my html template I am including plotly

And I am using Plotly.newPlot

<script type="text/javascript">
    var graphs = {{ graphJSON | safe }};
    Plotly.newPlot('plot', graphs);

Developer Tools in the browser shows that the configuration is there:
“modebar”: {
“add”: [“drawline”, “drawopenpath”, “drawclosedpath”, “drawcircle”, “drawrect”, “eraseshape”]
},

It seems this src=https://cdn.plot.ly/plotly-latest.min.js doesn’t get you actually the latest. I needed to be explicit to get 2.30.1 => src=“https://cdn.plot.ly/plotly-2.30.1.min.js” charset=“utf-8”

latest get you plotly.js v1.58.5. ugh…

1 Like