I am using dropdown to filter state in the line graph below. Here d is the dataframe, ther are 16 of them. In every dataframe I am trying to plot week as x axis and other values as y axis or traces in each graph. So far I am able to get dropdown menu for every 16 graph which would reupdate only given graph. Instead I want single dropdown value to update all the 16 graphs based on state selected on dropdown. Please see image attached.
This is the image which shows dropdown for every graph
This is my code:
state_list = list(df['GeogName'].unique())
for item in d.values(): #d is dictionary which has 16 dataframe as value, item is datafrme here.
fig=go.Figure()
state_plot_names = []
buttons=[]
default_state = "NY"
for state_name in state_list:
state_df = item[item["GeogName"]== region_name]
for i in range(5): #adding 5 other traces as value in graph
fig.add_trace(go.Scatter(x=state_df['Week'], y =state_df.iloc[:,i], line={}, visible=(state_name==default_state)))
state_plot_names.extend([state_name])
for state_name in state_list :
buttons.append(dict(method='update',
label=state_name ,
args = [{'visible': [state_name ==s for s in state_plot_names]}]))
fig.update_layout(autosize=False,
width=1000,
height=700,showlegend=True, updatemenus=[{"buttons": buttons, "direction": "down", "active": state_list.index(default_state), "showactive": True, "x": 0.5, "y": 1.15}])
fig.show()
import numpy as np
import pandas as pd
import plotly.express as px
# replicate data described in question
states = ["NY", "NH", "IN", "CT", "MT", "VA", "ME", "SD", "KS", "MN"]
sigma = 0.01
d = {}
for di in range(16):
df = pd.DataFrame()
for s, (state, mu) in enumerate(
zip(states, np.random.uniform(0.001, 0.005, len(states)))
):
np.random.seed((s + 1) * di)
start_price = np.random.uniform(1, 5, [5, 1])
returns = np.random.normal(loc=mu, scale=sigma, size=100)
df = pd.concat(
[
df,
pd.DataFrame(
(start_price * (1 + returns).cumprod()).T,
columns=[f"value{di}_{n}" for n in range(5)],
)
.assign(GeogName=state)
.reset_index()
.rename(columns={"index": "Week"}),
]
)
d[chr(ord("A") + di)] = df
# integrate all dataframes so it's simple to use plotly express
# encode column name and GeogName into single column for definition of trace
df = pd.concat(
[
df.set_index(["Week", "GeogName"])
.stack()
.reset_index()
.rename(columns={"level_2": "trace", 0: "value"})
.assign(dataframe=k, trace=lambda d: d["GeogName"]+d["trace"])
for k, df in d.items()
]
)
fig = px.line(
df,
x="Week",
y="value",
color="trace",
facet_row="dataframe",
)
# default state...
fig.for_each_trace(lambda t: t.update(visible=(t.name[0:2] == "NY")))
fig.update_layout(
updatemenus=[
{
"buttons": [
{"label": state, "method": "restyle", "args": [{"visible":[t.name[0:2]==state for t in fig.data]}]}
for state in df["GeogName"].unique()
],
"y":1.01,
"x":.5
}
],
autosize=False,
height=1500
)
# compress up space between subplots
fig.update_layout({
f"yaxis{'' if axis==0 else axis+1}": {"domain": [s, e-.002]}
for axis, (s, e) in enumerate(
zip(np.linspace(0, 1, len(d.keys())+1), np.linspace(0, 1, len(d.keys())+1)[1:])
)
})