Hi @kerim ,
If I understand what you need to achieve, maybe the output something like this :
Here is the options that you can do :
Suppose the button will update two traces in one Figure and assuming that the ticker number is even
so it can be divided by 2, so I customize your data frame by adding new ticker value ‘d’
df = pd.DataFrame(
{'ticker' : ['a', 'b', 'c', 'd', 'a', 'b', 'c', 'd', 'a', 'b', 'c', 'd'],
'timestamp' : [1,1,1,1,2,2,2,2,3,3,3,3],
'val' : [10,110,12,130, 21,220,23,240, 100, 200, 300,400]
}
)
For initial lice only first two tickers, ex. ‘a’ and ‘b’ and using for loop to create two traces (trace ‘a’ an ‘b’ )
dfa = df.query("ticker in ['a','b']")
for idx,label in enumerate(tickers[:2]):
fig.add_trace(go.Scatter(
x=dfa[dfa['ticker'] == label].timestamp,
y=dfa[dfa['ticker'] == label].val,
visible=True,
# mode='markers',
marker=dict(size=12, line=dict(width=1, color=colors[idx])),
))
Updating the second trace by appending the x
and y
value in args
.
for selection in zip(tickers[::2],tickers[1::2]):
select_buttons.append(dict(method='update',
label="+".join(selection), # join two tickers as label
args=[{'x': [
df.query(f"ticker in ['{selection[0]}']").timestamp, # update x values for first trace
df.query(f"ticker in ['{selection[1]}']").timestamp # update x values for second trace
],
'y': [
df.query(f"ticker in ['{selection[0]}']").val, # update y values for first trace
df.query(f"ticker in ['{selection[1]}']").val]}, # update y values for first trace
]
)
)
And here is the complete code.
# based primarily on https://stackoverflow.com/q/69510612/8508004,
# combining with https://stackoverflow.com/q/75365695/8508004
# Influenced also by
# based on https://plotly.com/python/dropdowns/#relayout-dropdown and https://stackoverflow.com/q/71296687/8508004 and
# and https://stackoverflow.com/q/69510612/8508004 and
# https://community.plotly.com/t/how-to-delete-a-particular-trace-from-multiple-traces-in-a-graph-objects-figure/70203/2
import pandas as pd
import plotly.graph_objects as go
# Suppose the button will update two traces in one Figure.
# I assume that the ticker have even value so it can be devided by 2
# so I customize your dataframe by adding new ticker value 'd'
df = pd.DataFrame(
{'ticker' : ['a', 'b', 'c', 'd', 'a', 'b', 'c', 'd', 'a', 'b', 'c', 'd'],
'timestamp' : [1,1,1,1,2,2,2,2,3,3,3,3],
'val' : [10,110,12,130, 21,220,23,240, 100, 200, 300,400]
}
)
# you can use unique() method to get only unique values
tickers = df.ticker.unique().tolist()
# if you are using graph object you need to define the colors
colors = ['blue','red']
# Create figure and add one scatter trace
fig = go.Figure()
# for initial lice only first two tickers, ex. 'a' and 'b'
dfa = df.query("ticker in ['a','b']")
# and using for loop to create two traces (trace 'a' an 'b' )
for idx,label in enumerate(tickers[:2]):
fig.add_trace(go.Scatter(
x=dfa[dfa['ticker'] == label].timestamp,
y=dfa[dfa['ticker'] == label].val,
visible=True,
# mode='markers',
marker=dict(size=12, line=dict(width=1, color=colors[idx])),
))
# Create selection buttons
select_buttons = []
# Convert the ticker from ['a','b','c','d']
# into [['a','b'],['c','d']]
# by using slice and zip
for selection in zip(tickers[::2],tickers[1::2]):
select_buttons.append(dict(method='update',
label="+".join(selection), # join two tickers as label
args=[{'x': [
df.query(f"ticker in ['{selection[0]}']").timestamp, # update x values for first trace
df.query(f"ticker in ['{selection[1]}']").timestamp # update x values for second trace
],
'y': [
df.query(f"ticker in ['{selection[0]}']").val, # update y values for first trace
df.query(f"ticker in ['{selection[1]}']").val]}, # update y values for first trace
]
)
)
# Pass buttons to the updatemenus argument
fig.update_layout(updatemenus=[dict(buttons=select_buttons,x=0.18, y=1.21),])
# Update remaining layout properties
fig.update_layout(
title_text="Select Ticker:",
showlegend=False,
)
fig.show()