Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save MattJBritton/9dc26109acb4dfe17820cf72d82f1e6f to your computer and use it in GitHub Desktop.
Save MattJBritton/9dc26109acb4dfe17820cf72d82f1e6f to your computer and use it in GitHub Desktop.
Multiple checkbox selection with searching with ipywidgets

Multiple selection with checkboxes and search field

This gist is forked from pbugnion's great work on building a searchable multi-checkbox using ipywidgets. You can find that work in this gist.

This version adds compatability with Jupyter Widgets' interactive_output() function, and also makes it easier to see which elements were selected by sorting them to the top. It also makes a few small changes to enable this to work in Jupyter Lab.

Image of dropdown

Usage

import ipywidgets as wid
options_dict = {
    x: wid.Checkbox(
        description=x, 
        value=False,
        style={"description_width":"0px"}
    ) for x in ['hello','world']
}
ui = multi_checkbox_widget(options_dict)
out = wid.interactive_output(f, options_dict)
display(wid.HBox([ui, out]))

To get the selected options:

selected_options = [widget.description for widget in ui.children[1].children if widget.value]
import requests
import random
import ipywidgets as wid
def multi_checkbox_widget(options_dict):
""" Widget with a search field and lots of checkboxes """
search_widget = wid.Text()
output_widget = wid.Output()
options = [x for x in options_dict.values()]
options_layout = wid.Layout(
overflow='auto',
border='1px solid black',
width='300px',
height='300px',
flex_flow='column',
display='flex'
)
#selected_widget = wid.Box(children=[options[0]])
options_widget = wid.VBox(options, layout=options_layout)
#left_widget = wid.VBox(search_widget, selected_widget)
multi_select = wid.VBox([search_widget, options_widget])
@output_widget.capture()
def on_checkbox_change(change):
selected_recipe = change["owner"].description
#print(options_widget.children)
#selected_item = wid.Button(description = change["new"])
#selected_widget.children = [] #selected_widget.children + [selected_item]
options_widget.children = sorted([x for x in options_widget.children], key = lambda x: x.value, reverse = True)
for checkbox in options:
checkbox.observe(on_checkbox_change, names="value")
# Wire the search field to the checkboxes
@output_widget.capture()
def on_text_change(change):
search_input = change['new']
if search_input == '':
# Reset search field
new_options = sorted(options, key = lambda x: x.value, reverse = True)
else:
# Filter by search field using difflib.
#close_matches = difflib.get_close_matches(search_input, list(options_dict.keys()), cutoff=0.0)
close_matches = [x for x in list(options_dict.keys()) if str.lower(search_input.strip('')) in str.lower(x)]
new_options = sorted(
[x for x in options if x.description in close_matches],
key = lambda x: x.value, reverse = True
) #[options_dict[x] for x in close_matches]
options_widget.children = new_options
search_widget.observe(on_text_change, names='value')
display(output_widget)
return multi_select
# Get lots of words for our options
words_url = 'https://svnweb.freebsd.org/csrg/share/dict/words?view=co&content-type=text/plain'
response = requests.get(words_url)
response.raise_for_status()
words = response.text
words = set([word.lower() for word in words.splitlines()])
descriptions = random.sample(words, 100)
options_dict = {
x: wid.Checkbox(
description=x,
value=False,
style={"description_width":"0px"}
) for x in descriptions
}
def f(**args):
results = [key for key, value in args.items() if value]
display(results)
ui = multi_checkbox_widget(options_dict)
out = wid.interactive_output(f, options_dict)
display(wid.HBox([ui, out]))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment