问题
I was learning plotly dropdown menu and stumbled on a label problem.
Question
- How to show labels
sin and sin-1
when selected Sine. And show labelstan and tan-1
when selected Tan?
MWE
# imports
import plotly.graph_objects as go
import numpy as np
# data
x = np.linspace(-np.pi, np.pi, 100)
y1 = np.sin(x)
y1b = y1-1
y2 = np.tan(x)
y2b = y2-1
# plotly setup
fig = go.Figure()
# Add one ore more traces
fig.add_traces(go.Scatter(x=x, y=y1,name='sin'))
fig.add_traces(go.Scatter(x=x, y=y1b,name='sin - 1'))
fig.add_traces(go.Scatter(x=x, y=y2,name='tan'))
fig.add_traces(go.Scatter(x=x, y=y2b,name='tan - 1'))
# construct menus
updatemenus = [{'buttons': [{'method': 'update',
'label': 'Sine',
'args': [{'y': [y1, y1b]},]
},
{'method': 'update',
'label': 'Tan',
'args': [
{'y': [y2, y2b],'label':['a','b']},
]}
],
'direction': 'down',
'showactive': True,}]
# update layout with buttons, and show the figure
fig.update_layout(updatemenus=updatemenus)
fig.show()
output
回答1:
Here's a generic helper function that you could use:
# Helper functions to create the appropriate buttons
def makePlotButtons(options, nTracesPerOption=1):
buttons = []
for i, opt in enumerate(options):
visibleArr = np.full((nTracesPerOption*len(options),),
False, dtype=bool)
startIdx = nTracesPerOption*i
for idx in range(nTracesPerOption):
visibleArr[startIdx + idx] = True
buttons.append(dict(label=str(opt),
method='restyle',
args=[{'visible': list(visibleArr)}])) # 'Visible' arg determines which plots are shown
# depending on which dropdown is selected
return buttons
where options
is a list of strings and nTracesPerOption
is how many traces you have per option. In the case of your questions, your options
parameter would be ['Sine', 'Tan']
and nTracesPerOption
is 2 (e.g. for sin and sin - 1).
Then in the MWE you provided, you would update the buttons
field in your updatemenus
variable to makePlotButtons(options, 2)
回答2:
For challenges such as this I've pretty much moved on to using Dash, so my abilites when it comes to specifying dropdown buttons like this is a bit rusty. So you'll have to forgive me because the following suggestion will only be a good solution if you stick to switching between Sine
and Tan
for the dropdown options. And select Sine
as your first option. If you do, then:
1. Clicking Sine
will give you this:
2. Clicking Tan
will give you this:
3. And clicking Sine
for the second time will give you this again:
And on and on it spins...
And notice how the legend shows only traces for your selected categories.
This has been made possible through specifying which traces to restyle by specifying them trough their position in fig.data
using integers [0, 1]
and [2, 3]
for the different buttons. The toggle functionality has been made possible using the args2 attribute. You can see all details in the complete code snippet below.
So why is this not a perfect solution??
The button label shows some weire behavior where
Sine
disappears.If you select
Tan
first then... Try for yourself and see =)
Anyway, if other options turn out to be too complex or have other shortcomings, maybe you or other readers figure out how to make this suggestion meet your requirements 100%.
Complete code:
# imports
import plotly.graph_objects as go
import numpy as np
# data
x = np.linspace(-np.pi, np.pi, 100)
y1 = np.sin(x)
y1b = y1-1
y2 = np.tan(x)
y2b = y2-1
# plotly setup
fig = go.Figure()
# Add one ore more traces
fig.add_traces(go.Scatter(x=x, y=y1,name='sin'))
fig.add_traces(go.Scatter(x=x, y=y1b,name='sin - 1'))
fig.add_traces(go.Scatter(x=x, y=y2,name='tan'))
fig.add_traces(go.Scatter(x=x, y=y2b,name='tan - 1'))
# construct menus
updatemenus = [{'buttons': [{'method': 'restyle',
'label': 'Sine',
'args': [{'y': [y1, y1b],
'label':'Sine',
'name':['sin', 'sin - 1'],
'visible': True}, [0, 1]],
'args2': [{'y': [y1, y1b],
'visible': False}, [2, 3]]
},
{'method': 'restyle',
'label': 'Tan',
'args': [{'y': [y2, y2b],
'name': ['tan', 'tan - 1'],
'visible':True}, [0, 1]],
'args2': [{'y': [y2, y2b],
'visible':False}, [2, 3]],
}
],
'direction': 'down',
'showactive': True,}]
# update layout with buttons, and show the figure
fig.update_layout(updatemenus=updatemenus)
fig.show()
回答3:
I got the following answer as suggested by @Jacob K
# imports
import plotly.graph_objects as go
import numpy as np
# data
x = np.linspace(-np.pi, np.pi, 100)
# plotly setup
fig = go.Figure()
# Add traces
fig.add_traces(go.Scatter(x=x, y=np.sin(x),name='sin'))
fig.add_traces(go.Scatter(x=x, y=np.sin(x)-1,name='sin - 1'))
fig.add_traces(go.Scatter(x=x, y=np.cos(x),name='cos'))
fig.add_traces(go.Scatter(x=x, y=np.cos(x)-1,name='cos - 1'))
fig.add_traces(go.Scatter(x=x, y=np.tan(x),name='tan'))
fig.add_traces(go.Scatter(x=x, y=np.tan(x)-1,name='tan - 1'))
# construct menus
# Helper functions to create the appropriate buttons
def makePlotButtons(options, nTracesPerOption=1):
buttons = []
for i, opt in enumerate(options):
visibleArr = np.full((nTracesPerOption*len(options),),
False, dtype=bool)
startIdx = nTracesPerOption*i
for idx in range(nTracesPerOption):
visibleArr[startIdx + idx] = True
buttons.append(dict(label=str(opt),
method='restyle',
args=[{'visible': list(visibleArr)}])) # 'Visible' arg determines which plots are shown
# depending on which dropdown is selected
return buttons
# update layout with buttons, and show the figure
updatemenus = [{'buttons': makePlotButtons(['Sine','Cosine', 'Tan'], 2),
'direction': 'down',
'showactive': True,}]
fig.update_layout(updatemenus=updatemenus)
fig.show()
and got following output
来源:https://stackoverflow.com/questions/65605076/plotly-how-to-give-different-label-names-in-a-dropdown-menu