Often, you want the user to choose n options (where n is small-ish) from a very large (hundreds or thousands) number of possibilities. Good UX around this dictates that the user should be able to search for the options they want.
This gist puts together a minimal example of binding a search field with multiple checkboxes using ipywidgets.
widget = multi_checkbox_widget(['hello', 'world'])
widget # Display the widget
To get the selected options:
selected_options = [widget.description for widget in w.children[1].children if widget.value]
-
This is in need of some layout/CSS TLC.
-
At the moment, we just use difflib from the standard library for searching through the options. It mostly works, but I don't think it's what difflib is supposed to be used as. Using a different search algorithm might lead to better results.
Like some of the commenters above, I was unable to use this excellent code with interact/interactive, which is my main use case for using Jupyter Widgets. However, I was able to find a fix. You can find my solution in a fork of this project.
It is impossible (to my knowledge) to use interact/interactive because those functions cannot accept a VBox as a parameter, and the output of
multi_checkbox_widget()
is a VBox. However, you can create the individual checkbox widgets outside of themulti_checkbox_widget()
function, pass them in, and then use the Jupyter Widgetsinteractive_output()
method instead. This method allows you to pass widgets (representing interactive parameter controls) to a function without displaying them, and then display inside of a container later.Because the number of checkboxes is arbitrary, our function must then take
**args
as its only parameter. I was unfortunately unable to passipywidgets.fixed()
to the function, so I had to use global variables to access a data set in the function. This is not a problem in the trivial example in the gist, but was a consideration for my use case.I also added a small UX improvement by automatically sorting any selected items to the top of the list.
Lastly, note that I use
@output_widget.capture()
as a function decorator for myon_text_change()
function. This was not present in the original, and is only required for correct functioning in Jupyter Lab, not Jupyter Notebook. See here for more info.I hope this is helpful for those who stumble across this page in the future!