Hello, I am trying to plot 12 subplots with 2 dropdown menus in Plotly.
Basically I have to data sets, Collisions and Forecast where I have data for 2 years, 2014 and 2015 for each day in each month. I would like to plot the collisions in each month (Jan-Dec) and the forecast conditions for each month, where I can select wich year I am visualizing and which condition I am visualizing.
You can find the data here: Data
But that’s how the forecast data look like:
And that’s how the collision data looks like:
Both data sets have been prepared for this purpose.
I have achieved to display 12 subplots of year 2014 where I can select the forecast condition in a drop down menu
I have done the above plot with the following code:
fig = make_subplots(rows=6, cols=2, specs=[[{"secondary_y": True}, {"secondary_y": True}],
[{"secondary_y": True}, {"secondary_y": True}],
[{"secondary_y": True}, {"secondary_y": True}],
[{"secondary_y": True}, {"secondary_y": True}],
[{"secondary_y": True}, {"secondary_y": True}],
[{"secondary_y": True}, {"secondary_y": True}],
])
# condition = "snow"
colors = {"Collisions": "#FFA07A",
"tempmax": "#FF0000",
"tempmin": "#00FF00",
"temp": "#7EC0EE",
"humidity": "#808080",
"precip": "#E389B9",
"snow": "#800080",
"visibility": "#000000",
}
forecast = list(df_brook_fore.columns[1:])
months = list(range(1,13))
for i, mon in enumerate(months):
for j, condition in enumerate(forecast):
column_idx = 1 if i%2==0 else 2
row_idx = i//2+1
days = list(range(1, len(df_brook_fil_group[2014][mon]) + 1))
fig.add_trace(go.Bar(x=days, y=df_brook_fil_group[2014][mon], marker_color=colors["Collisions"], visible=(j == 0),
name='Collisions' if i == 0 else '', showlegend=True if i == 0 else False),
row=row_idx, col=column_idx)
fig.add_trace(go.Scatter(x=days, y=df_brook_fore.loc[2014, mon][condition], visible=(j == 0),
marker_color=colors[condition], name=condition if i == 0 else '',
showlegend=True if i == 0 else False), row=row_idx, col=column_idx, secondary_y=True)
fig.update_yaxes(title_text="Collisions", row=row_idx, col=column_idx, secondary_y=False, showgrid=False)
fig.update_yaxes(title_text="Visibility", row=row_idx, col=column_idx, secondary_y=True, showgrid=False)
fig.update_layout(width=1000, height=1200, coloraxis=dict(colorscale='Bluered_r'), showlegend=True)
fig.update_layout(
updatemenus=[
dict(
active=0,
buttons=list([
dict(label=condition, method="update", args=[{"visible": [((j == i*2) or (j == i*2+1)) for j in range(
len(forecast)*2)]}, {"title": "Normalized Collision Count by Hour for " + condition}])
for i, condition in enumerate(forecast)
]),
x=0.05, y=1.1, xanchor="left", yanchor="top"
)
],
title_text="Normalized Collision Count by Hour for " + forecast[0],
title_x=0.5
)
fig.show()
I am trying to create the same logic with 2 drop down list, one more for the years.
I tried to do it like this:
fig = make_subplots(rows=6, cols=2, specs=[[{"secondary_y": True}, {"secondary_y": True}],
[{"secondary_y": True}, {"secondary_y": True}],
[{"secondary_y": True}, {"secondary_y": True}],
[{"secondary_y": True}, {"secondary_y": True}],
[{"secondary_y": True}, {"secondary_y": True}],
[{"secondary_y": True}, {"secondary_y": True}],
])
# condition = "snow"
colors = {"Collisions": "#FFA07A",
"tempmax": "#FF0000",
"tempmin": "#00FF00",
"temp": "#7EC0EE",
"humidity": "#808080",
"precip": "#FFC0CB",
"snow": "#800080",
"visibility": "#FFA500",
}
forecast = list(df_brook_fore.columns[1:])
months = list(range(1,13))
years = list(df_brook_fore.index.get_level_values(0).unique())
for i, mon in enumerate(months):
for k, year in enumerate(years):
for j, condition in enumerate(forecast):
column_idx = 1 if i%2==0 else 2
row_idx = i//2+1
days = list(range(1, len(df_brook_fil_group[year][mon]) + 1))
fig.add_trace(go.Bar(x=days, y=df_brook_fil_group[year][mon], marker_color=colors["Collisions"], visible=(j == 0) and (k==0),
name='Collisions' if i == 0 else '', showlegend=True if i == 0 else False),
row=row_idx, col=column_idx)
fig.add_trace(go.Scatter(x=days, y=df_brook_fore.loc[year, mon][condition], visible=(j == 0),
marker_color=colors[condition], name=condition if i == 0 else '',
showlegend=True if i == 0 else False), row=row_idx, col=column_idx, secondary_y=True)
fig.update_yaxes(title_text="Collisions", row=row_idx, col=column_idx, secondary_y=False, showgrid=False)
fig.update_yaxes(title_text="Visibility", row=row_idx, col=column_idx, secondary_y=True, showgrid=False)
fig.update_layout(width=1000, height=1200, coloraxis=dict(colorscale='Bluered_r'), showlegend=True)
# Define the unique values of the year, month, and forecast variables
years = list(df_brook_fore.index.get_level_values(0).unique())
months = list(range(1, 13))
forecast = list(df_brook_fore.columns[1:])
# Define the dropdown menu options for the year and forecast variables
year_options = [{"label": str(year), "value": year} for year in years]
forecast_options = [{"label": condition, "value": condition} for condition in forecast]
# Add the dropdown menus to the figure layout
fig.update_layout(
updatemenus=[
dict(
active=0,
buttons=list([
dict(
label=year,
method="update",
args=[
{"visible": [[(j == i*2) or (j == i*2+1) for j in range(len(forecast)*2)] for i in range(len(years))] + [(j == k*2+i) or (j == k*2+1+i) for j in range(len(forecast)*2)]},
{"title": {"text": "Normalized Collision Count by Hour for " + condition}}]
) for i, year in enumerate(years)
]),
x=0.05, y=1.2, xanchor="left", yanchor="top"
),
dict(
active=0,
buttons=list([
dict(
label=condition,
method="update",
args=[
{"visible": [[(j == i*2) or (j == i*2+1) for j in range(len(forecast)*2)] for i in range(len(years))] + [(j == k*2+i) or (j == k*2+1+i) for j in range(len(forecast)*2)]},
{"title": {"text": "Normalized Collision Count by Hour for " + condition}}]
) for k, condition in enumerate(forecast)
]),
x=0.15, y=1.2, xanchor="left", yanchor="top"
)
],
title_text="Normalized Collision Count by Hour for " + forecast[0],
title_x=0.5
)
fig.show()
But it’s not working properly…
I don’t fully understand how the boolean conditions work for a double drop down menu and I am trying to find a solution but any help will be really valuable.
Thanks in advance!