Search code examples
pythondashboardplotly-dash

How to update RadioItems options?


How can I update one RadioItem options when choosing other RadioItem ?

More details:

  • I have 2 RadioItems (radio1 and radio2).
  • When the user choose value from radio1, I want the options of radio2 to be changed.
  • How can I do it ?

I tried in this way, but it doesn't work:

import dash
import dash_html_components as html
import dash_core_components as dcc
from dash.dependencies import Input, Output

external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)


app.layout = html.Div([

    html.Div([
        html.Div(children=[
            html.H1(children="main-groups")
        ]),
        dcc.RadioItems(
            id="radio1",
            options=[
                {'label': 'New York City', 'value': 'NYC'},
                {'label': 'Montréal', 'value': 'MTL'},
                {'label': 'San Francisco', 'value': 'SF'}
            ],
        )]),

    html.Div([
        html.Div(children=[
            html.H1(children="sub-groups")
        ]),
        dcc.RadioItems(
                id="radio2",
                options=[
                ],
        ),
        html.Div(children=[
            html.H1(id="res", children="results")
        ]),
        ])


])


@app.callback(
              [Output('radio2', 'options')],
              [Input('radio1', 'value')])

def chnage_selection(val):
    print("change main radio: {}".format(val))

    if val == "NYC":
        return [
                    {'label': 'a1', 'value': 'a1'},
                    {'label': 's1', 'value': 's1'}
                ]
    elif val == "MTL":
        return [
                    {'label': 'a2', 'value': 'a2'},
                    {'label': 's2', 'value': 's2'}
                ]
    else:
        return [
                    {'label': 'a3', 'value': 'a3'},
                    {'label': 's3', 'value': 's3'}
                ]

    print("Error")
    return None



def main():
    app.run_server(debug=True)

if __name__ == "__main__":
    main()

Solution

  • Don't surround your single Output with a list or surround your return values with a list.

    So you could change your callback from this:

    @app.callback([Output("radio2", "options")], [Input("radio1", "value")])
    def chnage_selection(val):
        print("change main radio: {}".format(val))
    
        if val == "NYC":
            return [{"label": "a1", "value": "a1"}, {"label": "s1", "value": "s1"}]
        elif val == "MTL":
            return [{"label": "a2", "value": "a2"}, {"label": "s2", "value": "s2"}]
        else:
            return [{"label": "a3", "value": "a3"}, {"label": "s3", "value": "s3"}]
    
        print("Error")
        return None
    

    to this:

    @app.callback(Output("radio2", "options"), [Input("radio1", "value")])
    def chnage_selection(val):
        print("change main radio: {}".format(val))
    
        if val == "NYC":
            return [{"label": "a1", "value": "a1"}, {"label": "s1", "value": "s1"}]
        elif val == "MTL":
            return [{"label": "a2", "value": "a2"}, {"label": "s2", "value": "s2"}]
        else:
            return [{"label": "a3", "value": "a3"}, {"label": "s3", "value": "s3"}]
    
        print("Error")
        return None
    

    To add some more explanation on the what was happening with your original code. The expected return value of the original callback was a list with a single element. So when you returned the list of options inside your checks it treated each option object as a separate callback output.