Updating a dropdown menu's contents dynamically

It seems that dropdown menus are used exclusively as inputs to other dash objects. Or at least this is the case in the examples. In the interactive section of the “getting started” guide, you get to select a country from the dropdown menu, and then the graph updates based on the country you’ve selected.

What if I want to update another dropdown menu? Would I use a callback to update the ‘options’ property of the child-dropdown? This doesn’t seem to work. Below is some code to see this. There are two dropdown menus.

The behavior I would expect is to see: The parent dropdown gets populated as normal (with names Chris and Jack), and selecting one of the names should update the options of the child dropdown.

For example, when chriddy is selected in the parent dropdown, the optn_c options should be available in the child dropdown, and when jackp is selected in the parent dropdown, the optn_j options should be available in the child dropdown.

The behavior that I see: The parent dropdown menu gets populated. Population order is random, since the data type is Dict. Assuming chriddy is the first item to appear in the parent dropdown, then the child dropdown gets populated with the ‘c’ options: 'opt1_c', 'opt2_c', 'opt3_c'. But when I choose the jackp from the parent dropdown, the ‘j’ options don’t show up in the second dropdown menu.

What am I doing wrong? This updating of dropdown lists in a chain would be very useful, as it naturally translates into SQL-like queries.

import dash
import dash_core_components as dcc
import dash_html_components as html

app = dash.Dash()

fnameDict = {'chriddy': ['opt1_c', 'opt2_c', 'opt3_c'], 'jackp': ['opt1_j', 'opt2_j']}

names = list(fnameDict.keys())
nestedOptions = fnameDict[names[0]]

app.layout = html.Div(
    [
        html.Div([
        dcc.Dropdown(
            id='name-dropdown',
            options=[{'label':name, 'value':name} for name in names],
            value = list(fnameDict.keys())[0]
            ),
            ],style={'width': '20%', 'display': 'inline-block'}),
        html.Div([
        dcc.Dropdown(
            id='opt-dropdown',
            options=[{'label':opt, 'value':opt} for opt in nestedOptions],
            value = nestedOptions[0]
            ),
            ],style={'width': '20%', 'display': 'inline-block'}
        ),
    ]
)

@app.callback(
    dash.dependencies.Output('opt-dropdown', 'options'),
    [dash.dependencies.Input('name-dropdown', 'value')]
)
def update_date_dropdown(name):
    opts = fnameDict[name]
    options=[{'label':opt, 'value':opt} for opt in opts]
    return {'options':options}

if __name__ == '__main__':
    app.run_server(debug=True)
4 Likes

This should work.

import dash
import dash_core_components as dcc
import dash_html_components as html

app = dash.Dash()

fnameDict = {'chriddy': ['opt1_c', 'opt2_c', 'opt3_c'], 'jackp': ['opt1_j', 'opt2_j']}

names = list(fnameDict.keys())
nestedOptions = fnameDict[names[0]]

app.layout = html.Div(
    [
        html.Div([
        dcc.Dropdown(
            id='name-dropdown',
            options=[{'label':name, 'value':name} for name in names],
            value = list(fnameDict.keys())[0]
            ),
            ],style={'width': '20%', 'display': 'inline-block'}),
        html.Div([
        dcc.Dropdown(
            id='opt-dropdown',
            ),
            ],style={'width': '20%', 'display': 'inline-block'}
        ),
        html.Hr(),
        html.Div(id='display-selected-values')
    ]
)

@app.callback(
    dash.dependencies.Output('opt-dropdown', 'options'),
    [dash.dependencies.Input('name-dropdown', 'value')]
)
def update_date_dropdown(name):
    return [{'label': i, 'value': i} for i in fnameDict[name]]

@app.callback(
    dash.dependencies.Output('display-selected-values', 'children'),
    [dash.dependencies.Input('opt-dropdown', 'value')])
def set_display_children(selected_value):
    return 'you have selected {} option'.format(selected_value)



if __name__ == '__main__':
    app.run_server()
10 Likes

Works!

Now I see what I did wrong too!

Thanks @raghunath!

Note that a similar example was posted in the user guide: https://plot.ly/dash/getting-started-part-2, code copied below:

# -*- coding: utf-8 -*-
import dash
from dash.dependencies import Input, Output
import dash_core_components as dcc
import dash_html_components as html

app = dash.Dash(__name__)

all_options = {
    'America': ['New York City', 'San Francisco', 'Cincinnati'],
    'Canada': [u'Montréal', 'Toronto', 'Ottawa']
}
app.layout = html.Div([
    dcc.RadioItems(
        id='countries-dropdown',
        options=[{'label': k, 'value': k} for k in all_options.keys()],
        value='America'
    ),

    html.Hr(),

    dcc.RadioItems(id='cities-dropdown'),

    html.Hr(),

    html.Div(id='display-selected-values')
])

@app.callback(
    dash.dependencies.Output('cities-dropdown', 'options'),
    [dash.dependencies.Input('countries-dropdown', 'value')])
def set_cities_options(selected_country):
    return [{'label': i, 'value': i} for i in all_options[selected_country]]

@app.callback(
    dash.dependencies.Output('cities-dropdown', 'value'),
    [dash.dependencies.Input('cities-dropdown', 'options')])
def set_cities_value(available_options):
    return available_options[0]['value']

@app.callback(
    dash.dependencies.Output('display-selected-values', 'children'),
    [dash.dependencies.Input('countries-dropdown', 'value'),
     dash.dependencies.Input('cities-dropdown', 'value')])
def set_display_children(selected_country, selected_city):
    return u'{} is a city in {}'.format(
        selected_city, selected_country,
    )

if __name__ == '__main__':
    app.run_server(debug=True)

2 Likes

There are 4 dropdown lists in my code. Is there anyone who can tell me why 3rd dropdown list will be affected by 1st one? I mean if I set value of 3rd one to yyy, it will change to xxx automatically if I choose any value in 1st one. Thanks a lot.

import dash
import dash_core_components as dcc
import dash_html_components as html

app = dash.Dash()

fnameDict = {‘chriddy’: [‘opt1_c’, ‘opt2_c’, ‘opt3_c’], ‘jackp’: [‘opt1_j’, ‘opt2_j’]}
fxxx = {‘xxx’: [‘opt1_c’, ‘opt2_c’, ‘opt3_c’], ‘yyy’: [‘opt1_j’, ‘opt2_j’]}

names = list(fnameDict.keys())
nxxx = list(fxxx.keys())

app.layout = html.Div(
[

html.Div([dcc.Dropdown(id='name-dropdown',options=[{'label':name, 'value':name} for name in names],
    value = list(fnameDict.keys())[0]),],style={'width': '15%', 'display': 'inline-block'}),
html.Div([dcc.Dropdown(id='opt-dropdown',),],style={'width': '15%', 'display': 'inline-block'}),

html.Div([dcc.Dropdown(id='xxxx',options=[{'label':name1, 'value':name1} for name1 in nxxx],
    value = list(fxxx.keys())[0]),],style={'width': '15%', 'display': 'inline-block'}),
html.Div([dcc.Dropdown(id='opt-dropdown1',),],style={'width': '15%', 'display': 'inline-block'}),

html.Hr(),
html.Div(id='display-selected-values')        
    
]

)

@app.callback(
dash.dependencies.Output(‘opt-dropdown’, ‘options’),
[dash.dependencies.Input(‘name-dropdown’, ‘value’)]
)
def update_date_dropdown(name):
return [{‘label’: i, ‘value’: i} for i in fnameDict[name]]

@app.callback(
dash.dependencies.Output(‘display-selected-values’, ‘children’),
[dash.dependencies.Input(‘opt-dropdown’, ‘value’)])
def set_display_children(selected_value):
return ‘you have selected {} option’.format(selected_value)

if name == ‘main’:
app.run_server()

A post was split to a new topic: Dash Collapsible Tree - Details & Links?

@chriddyp Can I update “options” of a dropdown dynamically using uploaded csv from “Upload” component

2 Likes

I am also having same requirements, please anyone can help out possibilities.

Yes. In the case you would create a callback with the Upload component as the input and the DropDown component as the output; the body of the callback should parse the .csv file and return the desired list of options for the DropDown menu.

Yes. It is working with the way you suggested. Thanks.

Please anyone can help:
When dropdown value which is dynamically updated is used for filtering data from column of uploaded file’s dataframe thenit is providing null filtered values which was supposed to be used for plotting graph.

Is it possible to update the dropdown menu dynamically, without defining a corresponding dictionary before that outlines the possible combinations?

yes, see the “dynamic options” example in the drop down documentation: https://dash.plot.ly/dash-core-components/dropdown

The one that does not work??

could you clarify? are you seeing error messages? are you on a recent version of dash? could you share a simple reproducible example that shows what doesn’t work?