Sidebar with filters (dropdowns) in Plotly Dash

Viewed 799

I am trying to program a sidebar with some filters but the callback update_output of this dropdown is not working (not throwing an error, just doing nothing).

I think it is because this dropdown is not in the main layout, because my layout is composed of the sidebar and a content. My dropdowns in this sidebar will be filters that will be applied to the dataframe that feeds the graphs of the dashboard and dashboard2 layouts.

My question is how or where should I program those callbacks to give functionality to my sidebar dropdowns?

sidebar = html.Div(
    [
        html.H2("Sidebar", className="display-4"),
        html.Hr(),
        html.P(
            "Sidebar", className="lead"
        ),
        dbc.Nav(
            [
                dbc.NavLink("Home", href="/", active="exact"),
                dbc.NavLink("Page 1", href="/page-1", active="exact"),
                dbc.NavLink("Page 2", href="/page-2", active="exact"),
            ],
            vertical=True,
            pills=True,
        ),
        dcc.Dropdown(id='dropdown',value="City"),
        html.Br(),
        dcc.Dropdown(id='dropdown2',options=[])
        
    ],
    style=SIDEBAR_STYLE,
)

content = html.Div(id="page-content", children=[], style=CONTENT_STYLE)

app.layout = html.Div([
    dcc.Location(id="url"),
    sidebar,
    content
])


@app.callback(
    Output('dropdown2', 'options'),
    Input('dropdown', 'value')
)
def update_output(value):
    return df[df["cities"].isin(value)]



@app.callback(
    Output("page-content", "children"),
    [Input("url", "pathname")]
)
def render_page_content(pathname):
    if pathname == "/":
        return dashboard.layout
    elif pathname == "/page-1":
        return dashboard.layout
    elif pathname == "/page-2":
        return dashboard2.layout

    # return a 404 message when user tries to reach a different page
    return dbc.Jumbotron(
        [
            html.H1("404: Not found", className="text-danger"),
            html.Hr(),
            html.P(f"The pathname {pathname} was not recognised..."),
        ]
    )


if __name__=='__main__':
    app.run_server(debug=True, port=8000)
1 Answers

I find checklists to be better for this purpose. If you're open to using that instead of dropdown menu to filter your dataframe, then the complete snippet below will produce the following Plotly Dash App.

enter image description here

Complete code:

from jupyter_dash import JupyterDash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State, ClientsideFunction
import dash_bootstrap_components as dbc
import dash_core_components as dcc
import pandas as pd
import plotly.graph_objs as go
import numpy as np
import plotly.express as px

app = JupyterDash(external_stylesheets=[dbc.themes.SLATE])

df = px.data.stocks()
df = df.set_index('date')

controls = dbc.Card(
    [
        dbc.FormGroup(
            [
                dbc.Label("Checklist"),
                dcc.Checklist(
                    id="column_select",                   
                    options=[{"label":col, "value": col} for col in df.columns],
                    value=[df.columns[0]],
                    labelStyle={'display': 'inline-block', 'width': '12em', 'line-height':'0.5em'}
                ),
            ], 
        ),


    ],
    body=True,
    style = {'font-size': 'large'}
)


app.layout = dbc.Container(
    [
        html.H1("Dropdowns and checklists"),
        html.Hr(),
        dbc.Row([
            dbc.Col([controls],xs = 4),
            dbc.Col([
                dbc.Row([
                    dbc.Col(dcc.Graph(id="graph"), style={'height': '420px'}),
                ])
            ]),
        ]),
    ],
    fluid=True,
)

@app.callback(
    Output("graph", "figure"),
    [Input("column_select", "value"),],
)
def make_graph(cols):

    fig = px.line(df, x = df.index, y = cols, template = 'plotly_dark')
    return fig

app.run_server(mode='external', port = 8982)
Related