Multiple Drop Down menu in plotly

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:

image

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!

@empet I’ve seen some solutions from other posts you helped, I tried to implement them but without any proper solution, if you have some idea how to do it I will be very grateful :slight_smile: