Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Plotly: How do the buttons for the update menus really work?

Tags:

python

plotly

Why do I want to know?

This may seem like a very simple question, but I'm having some difficulties editing figures with multiple traces using dropdownmenus, so I'm really eager to make sure that I'm understanding the inner workings of plotlys dropdown menus, update menus and buttons 100% correct. So it would be great if someone could find the time to take a look at the example below.


What is the problem?

Consider the following simple plotly figure produced by the code snippet below:

Plot1 :

enter image description here

Code 1:

# imports
import plotly.graph_objs as go
import pandas as pd
import numpy as np

# data
df1 = pd.DataFrame({'index': ['1','2','3'], 'A': [10,10,12], 'B': [11,11,11]})
df2 = pd.DataFrame({'index': ['1','2','3'], 'A': [10,10,10], 'B': [11,11,12]})

# plotly figure setup
fig=go.Figure()
fig.add_trace(go.Scatter(x=df1['index'], y=df1['A'], mode='lines'))
fig.add_trace(go.Scatter(x=df1['index'], y=df1['B'], mode='lines'))

#f=fig.to_dict()
fig.show()

Now I'd like to replace the data for the blue line df1['A']=[10,10,12] with df2['A']=[10,10,10], and at the same time replace the data for the red line df1['B']=[11,11,11] with df1['B']=[11,11,11].

And I can easily do so by introducing a dropdown menu like this:

Plot 2 - Dropdownmenu = df1:

enter image description here

Plot 3 - Dropdown menu = df2

enter image description here

Code 2 - Same as Code 1 but with added menu:

# imports
import plotly.graph_objs as go
import pandas as pd
import numpy as np

# data
df1 = pd.DataFrame({'index': ['1','2','3'], 'A': [10,10,12], 'B': [11,11,11]})
df2 = pd.DataFrame({'index': ['1','2','3'], 'A': [10,10,10], 'B': [11,11,12]})

# plotly figure setup
fig=go.Figure()
fig.add_trace(go.Scatter(x=df1['index'], y=df1['A'], mode='lines'))
fig.add_trace(go.Scatter(x=df1['index'], y=df1['B'], mode='lines'))

f=fig.to_dict()
#fig.show()

buttons=list([dict(args=[{'y':[df1['A'],df1['B']],
                           #'type':'scatter',
                        }],
                    
                   label="df1",
                   method="restyle"
                ),
                dict(args=[{'y':[df2['A'], df2['B']],
                           #'type':'scatter',
                           #'mode':'markers'
                          }],
                    
                    label="df2",
                    method="restyle"
                )
            ])

fig.update_layout(
    updatemenus=[
        go.layout.Updatemenu(
            buttons=buttons,
            direction="down",
            pad={"r": 10, "t": 10},
            showactive=True,
            x=-0.25,
            xanchor="left",
            y=1,
            yanchor="top"
        ),
    ]
)

fig.show()

How does it work?

Now let's take a look at how the figure was structured before the dropdown menu was introduced. We can do so by lookingat the variable f=fig.to_dict(). Here are the top lines of that dict:

  {'data': [{'mode': 'lines',
   'x': array(['1', '2', '3'], dtype=object),
   'y': array([10, 10, 12], dtype=int64),
   'type': 'scatter'},
  {'mode': 'lines',
   'x': array(['1', '2', '3'], dtype=object),
   'y': array([11, 11, 11], dtype=int64),
   'type': 'scatter'}]

Here you can see that 'y' appears twice:

# 1
'y': array([10, 10, 12], dtype=int64),

# 2
'y': array([10, 10, 12], dtype=int64),

And this leaves me a bit puzzled, since we're able to change both values for y by only referencing it once int the button in the dropdown menu:

# from the snippet Code 2 above:
dict(args=[{'y':[df2['A'], df2['B']]}]

And finally, the main question:

Now it seems very apparent that the way this works is that the updatemenu takes the value for y from the button, looks up every 'y' key in the figure and inserts the elements in the list [df2['A'], df2['B']] one by one as long as there are ys to fill. But is that really exactly what's happening here? If any of you are able to deliver a confident 'YES' I'd be quite happy with that, but I'm really hoping for a confident 'NO' and a few details on how these things are really put together.

like image 331
vestland Avatar asked Sep 21 '25 12:09

vestland


1 Answers

Great question! How things really work is that with the method attribute you're specifying the name of the underlying plotly.js Javascript function you want to apply, and its arguments are drawn from args. So you're really calling the JS function Plotly.restyle(<fig>, {'y': <whatever>}). This means that the documentation you're seeking is here: https://plot.ly/javascript/plotlyjs-function-reference/ and more specifically the restyle function which is here https://plot.ly/javascript/plotlyjs-function-reference/#plotlyrestyle

As you can see it says:

Note, leaving the trace indices unspecified assumes that you want to restyle all the traces.

like image 119
nicolaskruchten Avatar answered Sep 23 '25 02:09

nicolaskruchten