Selection of multiple-checkboxes linked to different dropdown selections

I am working on a graph that takes multiple user inputs to create a grouped bar chart that compares school testing performance based on different variables (grade, ethnicity, etc.). Because there are thousands of schools in the set, I am organizing them by school district. So I have a dropdown menu with all of the school districts. When a district is selected, a checklist is then populated with the schools in the district. Whichever schools are selected from that list are displayed on the graph.

I want to allow the user to select as many schools as they like, which is no problem if they are simply selecting checkboxes from a single school district. However, if they switch the dropdown to a different district, an entirely new set of school checkboxes appears. Any school checkbox that was checked from the first dropdown remains on the graph. This is intended behavior.

However, there is no way to uncheck that original school checkbox without re-selecting the school district from the dropdown and then unchecking the box. This is cumbersome. What I would like to do is ‘mirror’ all of the checked schools in another list somewhere on the page. See below:
tmp1
You can see that Item #2 is selected in the dropdown, which causes “Sub Item #2a” and “Sub Item #2b” checkboxes to be displayed below. Sub Item #2a is checked. Prior to this, the user had selected Item #1 in the dropdown and checked the “Sub Item #1b” checkbox. It remains checked even though it is no longer displayed directly under the dropdown. It is the behavior on the right that I want to create. A list of all checkbox items that have been selected which are themselves checkboxes so that they can be easily unchecked (at which point they disappear from the list). This would allow a user to select many sub items from many different items and to remove them easily.

I’ve tried all sorts of things without success. My current code is the closest, but it only displays the “selected” checkbox option without displaying (or being able to affect) the state of the checkbox.

        html.P('Select Schools', className = 'fix_label', style = {'color': 'steelblue'}),
        dcc.Checklist(id = 'school-checklist-select',
            value=[],
            labelStyle={'display': 'block'},
        ),

        html.P('Selected Schools:', className = 'fix_label', style = {'color': 'steelblue'}),
        dcc.Checklist(id = 'school-checklist-display',
            value=[],
            labelStyle={'display': 'block'},
        ),

@app.callback(
    Output('school-checklist-select', 'options'),
    Input('corporation-dropdown', 'value')
)
def set_school_options(selected_corporation):
    schools = csv.loc[csv['Corp ID'] == selected_corporation]
    schools_dict = dict(zip(schools['School Name'], schools['School ID']))
    options = []
    for name, id in schools_dict.items():
        options.append({'label': name, 'value': id})
    return options

@app.callback(
    Output('school-checklist-display', 'options'),
    Input('school-checklist-select', 'value')
)
def set_school_display(school_display):
    print ('display school')
    print(school_display)
    for school in school_display:
        school_data = csv.loc[csv['School ID'] == school]
        schools_dict = dict(zip(school_data['School Name'], school_data['School ID']))
    
        options = []
        for name, id in schools_dict.items():
            options.append({'label': name, 'value': id})
    return options

I’ve tried to work through the various advanced callback examples, but I still can’t quite figure out how to mirror/display both the name and state and allow the user to interact with either the ‘selected’ checkbox or the ‘displayed’ checkbox.

Any assistance would be appreciated!

1 Like

hi @etonblue
welcome to the Dash community. And thank you for the detailed question. Can you please include sample data with your code. That way, it would be easier for others to test your code locally and try to find a solution.

Thank you,

Okay, simplified and updated (but still not working) example of what I am trying to do here:

from dash import Dash, dcc, html, Input, Output

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

app = Dash(__name__, external_stylesheets=external_stylesheets)

dropdown_items = {
    'School District #1': ['School #1A', 'School #1B', 'School #1C'],
    'School District #2': ['School #2A', 'School #2B', 'School #2C'],
    'School District #3': ['School #3A', 'School #3B', 'School #3C']
}    

app.layout = html.Div(
    [
    dcc.Dropdown(
        id='main-dropdown',
        multi = False,
        options = [{'label': k, 'value': k} for k in dropdown_items.keys()],
        value = 'School District #1',
    ),
    dcc.Checklist(id="select-checklist", inline=True),
    dcc.Checklist(id="display-checklist", inline=True)
    ],
    style={'width': '50%'}
)

# Populate Checklist from Dropdown
@app.callback(
    Output('select-checklist', 'options'),
    Input('main-dropdown', 'value')
)
def set_select_checklist(dropdown_value):
    return [{'label': i, 'value': i} for i in dropdown_items[dropdown_value]]
     
# Populate persistant checklist of all selected checkboxes
# Issues:
# 1) Checkboxes are displaying, but not 'checked'
# 2) Selecting the "display" checkbox has no effect on either the "display"
#    or the "select" checkbox.

@app.callback(
    Output("display-checklist", "options"),
    Input("select-checklist", "value"),
    prevent_initial_call=True,
)
def display(select):
    if select is not None:
        return [{'label': i, 'value': i} for i in select]

if __name__ == "__main__":
    app.run_server(debug=True)
  • Page loads with dropdown value of School District #1 and all schools associated with School District #1 as checkboxes below - working as intended.
  • Selecting or deselecting any of the school checkboxes causes a duplicate ‘display’ checkbox to appear or disappear. This ‘display’ checkbox remains even if the user moves to a different dropdown selection - this is also working as intended.
  • What is currently ‘not’ working is: 1) Checkboxes that are selected are added to the ‘display’ but are not checked; and 2) Selecting the ‘display’ checkbox has no effect on either the “display” or the “select” checkbox.

The intended effect is that the user can simply uncheck the ‘display’ checkboxes to determine what is shown on the graph without having to cycle back through the dropdown menu to find the original school district dropdown (there are hundreds of school districts and thousands of schools).

Hope this makes it clearer.

Thanks!

Hi @etonblue
Is this what you’re looking for?

from dash import Dash, dcc, html, Input, Output, no_update

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

app = Dash(__name__, external_stylesheets=external_stylesheets)

dropdown_items = {
    'School District #1': ['School #1A', 'School #1B', 'School #1C'],
    'School District #2': ['School #2A', 'School #2B', 'School #2C'],
    'School District #3': ['School #3A', 'School #3B', 'School #3C']
}

app.layout = html.Div(
    [
        dcc.Dropdown(
            id='main-dropdown',
            multi=False,
            options=[{'label': k, 'value': k} for k in dropdown_items.keys()],
            value='School District #1',
        ),
        dcc.Checklist(id="select-checklist", inline=True),
        html.Br(),
        html.Br(),
        dcc.Checklist(id="display-checklist", inline=True,
                      options=['School #1A', 'School #1B', 'School #1C', 'School #2A', 'School #2B', 'School #2C', 'School #3A', 'School #3B', 'School #3C'])
    ],
    style={'width': '50%'}

)


# Populate Checklist from Dropdown
@app.callback(
    Output('select-checklist', 'options'),
    Input('main-dropdown', 'value')
)
def set_select_checklist(dropdown_value):
    return [{'label': i, 'value': i} for i in dropdown_items[dropdown_value]]


# Populate persistant checklist of all selected checkboxes
# Issues:
# 1) Checkboxes are displaying, but not 'checked'
# 2) Selecting the "display" checkbox has no effect on either the "display"
#    or the "select" checkbox.

@app.callback(
    Output("display-checklist", "value"),
    Input("select-checklist", "value"),
    prevent_initial_call=True,
)
def display(select):
    print(select)
    if select:  #  same meaning as: if select is not None
        return select
    elif len(select)==0:
        return no_update


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

Not exactly. There are 250+ school Districts and 1,500 schools in the dataset, so it would be pretty messy to display all of the schools on the screen at once. For that reason, I am trying to figure out a way to only display the schools on the ‘display’ line if they are checked in the ‘select’ line. Similarly, I would like for a school that is displayed on the ‘display’ line to disappear from that line if the check is removed from either the ‘select’ or the ‘display’ line.

What I am looking to do is something like this:

https://www.freakyjolly.com/wp-content/uploads/2020/03/angular-how-to-get-selected-checked-checkboxes-demo.gif

With the addition of the ability to click directly on the list item to remove it from the list (and also uncheck the associated ‘select checkbox.’

Does that make sense? I’m trying to find a better example out there.

Thanks for the help!

Hi, dont know if you still need this but i think this would help. This code print out in a div the selected items, and if the check is removed it will update accordingly. (I dont use “display-checklist”). The same values from select-checklist are the ones display.
by the way sorry for the redaction this is not mi native language.

# in the layout..
       html.Div(["Output: "]),
        html.Div(id='my_output')


@app.callback(
    Output('my_output','children'),
    Input ('select-checklist', 'value'),
    prevent_initial_call=True,
)

def update_output_div(check_option):
    return 'option is : ' + str(check_option)
1 Like