Multiple Linked RadioItems

Hi How can I link multiple RadioItems so if an option is pressed from one list, the already selected ones from other RadioItems get unselected?
As an example let’s say we have the following RadioItems:

dcc.RadioItems(id='list1', options=[{'label': 'NYC', 'value': 'NYC'}]),
dcc.RadioItems(id='list2', options=[{'label': 'LA', 'value': 'LA'}]),
dcc.RadioItems(id='list3', options=[{'label': 'SF', 'value': 'SF'}]),

Let’s say first we select ‘NYC’ from ‘list1’. How can I link these RadioItems together so that when I select ‘LA’ from ‘list2’, the ‘NYC’ from ‘list1’ gets unselected. Thank you.

Hi @aasghari,

As you can see from the dcc.RadioItems documentation, one set of radioitems can be created by passing a list of dictionaries as options. Each of these dictionaries should have 'label', which is what is shown to user and 'value', which is the “inner value” for that label. The 'label' and 'value' can be the same in most cases, I guess. The value argument to the dcc.RadioItems tells what of the values in the options is selected by default.

Here is simple example:

dcc.RadioItems(
    options=[
        {'label': 'New York City', 'value': 'NYC'},
        {'label': 'Montréal', 'value': 'MTL'},
        {'label': 'San Francisco', 'value': 'SF'}
    ],
    value='MTL'
)  

and here is a standalone testapp, in which creating one set of items is put into a function get_radioitems that makes creating multiple dcc.RadioItems simpler (following the DRY principle):

import dash
import dash_core_components as dcc
import dash_html_components as html
import pandas as pd

external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']

app = dash.Dash(__name__, external_stylesheets=external_stylesheets)


def get_radioitems(items):
    return html.Div(
        dcc.RadioItems(
            options=[{
                'label': x,
                'value': x
            } for x in items],
            value=items[0],
        ), )


app.layout = html.Div(children=[
    html.H4(children='Test App'),
    get_radioitems(items=['NYC', 'LA', 'SF']),
    html.Hr(),
    get_radioitems(items=['Honey', 'Almonds', 'Milk']),
])

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

which produces

image

I hope it helps!

Hi np, thanks for your help. However, as you can see in your Test App, both options are selected from both RadioItems. How can we ‘unselect’ the previous one when new option is selected? e.g. when ‘Honey’ is selected, blue circle next to ‘NYC’ goes away.

Well that is pretty simple: You just put all the options inside one dcc.RadioItems.

Here is a little example with simple callback:

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

external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']

app = dash.Dash(__name__, external_stylesheets=external_stylesheets)


def get_radioitems(items, id):
    return html.Div(
        dcc.RadioItems(id=id,
                       options=[{
                           'label': x,
                           'value': x
                       } for x in items],
                       value=items[0]), )


app.layout = html.Div(children=[
    html.H4(children='Test App'),
    get_radioitems(items=['NYC', 'LA', 'SF', 'Honey', 'Almonds', 'Milk'],
                   id='my-radioitems'),
    html.Div(id='radioitems-callback-output')
])


@app.callback(Output('radioitems-callback-output', 'children'),
              [Input('my-radioitems', 'value')])
def react_on_radioitem_change(selected_radioitem):
    return html.Div(f'You have selected: {selected_radioitem}')


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

producing

testapp_dash

Correct but my issue is that it has to be 2 separate lists. Let’s say we have 2 lists, one with the cities in north america, and one the list with cities in Europe, and you’re asked where would you like to travel. You will choose only one city, but if you select a city in north america first e.g. NYC and then change you mind and select Paris, even though it is possible to determine which option has been selected the last (using callback_context.triggered), the NYC option is still selected because it’s not in the same list as Paris.

I guess there are other ways of achieving this goal, this way was the one that came to my mind. Let me know if you have any idea about how to achieve this.

One option would be to have one component (dcc.RadioItems, or dcc.Dropdown) to have

  • North America
  • Europe

and then, when the user has selected the category (country), you would show another list with subcategories (cities). There is an example of this with two dcc.RadioItems in Dash App With Chained Callbacks:

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

external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']

app = dash.Dash(__name__, external_stylesheets=external_stylesheets)

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

    html.Hr(),

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

    html.Hr(),

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


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


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


@app.callback(
    Output('display-selected-values', 'children'),
    [Input('countries-radio', 'value'),
     Input('cities-radio', '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)

which produces:

testapp_dash

1 Like

Thanks np, great idea.