Mastering widgets in the Jupyter Notebook
The ipywidgets package provides many common user interface controls for exploring code and data interactively. These controls can be assembled and customized to create complex graphical user interfaces. In this recipe, we introduce the various ways we can create user interfaces with ipywidgets.
Getting ready
The ipywidgets package should be installed by default in Anaconda, but you can also install it manually with conda install ipywidgets
.
Alternatively, you can install ipywidgets with pip install ipywidgets
, but then you also need to type the following command in order to enable the extension in the Jupyter Notebook:
jupyter nbextension enable --py --sys-prefix widgetsnbextension
How to do it...
- Let's import the packages:
>>> import ipywidgets as widgets from ipywidgets import HBox, VBox import numpy as np import matplotlib.pyplot as plt from IPython.display import display %matplotlib inline
- The
@interact
decorator shows a widget for controlling the arguments of a function. Here, the functionf()
accepts an integer as an argument. By default, the@interact
decorator displays a slider to control the value passed to the function:>>> @widgets.interact def f(x=5): print(x)
The function
f()
is called whenever the slider value changes. - We can customize the slider parameters. Here, we specify a minimum and maximum integer range for the slider:
>>> @widgets.interact(x=(0, 5)) def f(x=5): print(x)
- There is also an
@interact_manual
decorator that provides a button to call the function manually. This is useful with long-lasting computations that should not run every time a widget value changes. Here, we create a simple user interface for controlling four parameters of a function that displays a plot. There are two floating-point sliders, a drop-down menu for choosing a value among a few predefined options, and a checkbox for Boolean values:>>> @widgets.interact_manual( color=['blue', 'red', 'green'], lw=(1., 10.)) def plot(freq=1., color='blue', lw=2, grid=True): t = np.linspace(-1., +1., 1000) fig, ax = plt.subplots(1, 1, figsize=(8, 6)) ax.plot(t, np.sin(2 * np.pi * freq * t), lw=lw, color=color) ax.grid(grid)
- In addition to the
@interact
and@interact_manual
decorators, ipywidgets provides a simple API to create individual widgets. Here, we create a floating-point slider:>>> freq_slider = widgets.FloatSlider( value=2., min=1., max=10.0, step=0.1, description='Frequency:', readout_format='.1f', ) freq_slider
- Here is an example of a slider for selecting pairs of numbers, such as intervals and ranges:
>>> range_slider = widgets.FloatRangeSlider( value=[-1., +1.], min=-5., max=+5., step=0.1, description='xlim:', readout_format='.1f', ) range_slider
- The toggle button can control a Boolean value:
>>> grid_button = widgets.ToggleButton( value=False, description='Grid', icon='check' ) grid_button
- Drop-down menus and toggle buttons are useful when selecting a value among a predefined set of options:
>>> color_buttons = widgets.ToggleButtons( options=['blue', 'red', 'green'], description='Color:', ) color_buttons
- The text widget allows the user to write a string:
>>> title_textbox = widgets.Text( value='Hello World', description='Title:', ) title_textbox
- We can let the user choose a color using the built-in system color picker:
>>> color_picker = widgets.ColorPicker( concise=True, description='Background color:', value='#efefef', ) color_picker
- We can also simply create a button:
>>> button = widgets.Button( description='Plot', ) button
- Now, we will see how to combine these widgets into a complex Graphical User Interface, and how to react to user interactions with these controls. We create a function that will display a plot as defined by the created controls. We can access the control value with the
value
property of the widgets:>>> def plot2(b=None): xlim = range_slider.value freq = freq_slider.value grid = grid_button.value color = color_buttons.value title = title_textbox.value bgcolor = color_picker.value t = np.linspace(xlim[0], xlim[1], 1000) f, ax = plt.subplots(1, 1, figsize=(8, 6)) ax.plot(t, np.sin(2 * np.pi * freq * t), color=color) ax.grid(grid)
- The
on_click
decorator of abutton
widget lets us react to click events. Here, we simply declare that the plotting function should be called when the button is pressed:>>> @button.on_click def plot_on_click(b): plot2()
- To display all of our widgets in a unified graphical interface, we define a layout with two tabs. The first tab shows widgets related to the plot itself, whereas the second tab shows widgets related to the styling of the plot. Each tab contains a vertical stack of widgets defined with the
VBox
class:>>> tab1 = VBox(children=[freq_slider, range_slider, ]) tab2 = VBox(children=[color_buttons, HBox(children=[title_textbox, color_picker, grid_button]), ])
- Finally, we create the
Tab
instance with our two tabs, we set the titles of the tabs, and we add the plot button below the tabs:>>> tab = widgets.Tab(children=[tab1, tab2]) tab.set_title(0, 'plot') tab.set_title(1, 'styling') VBox(children=[tab, button])
There's more...
The documentation for ipywidgets demonstrates many other features of the package. Styling the widgets can be customized. New widgets can be created by writing Python and JavaScript code (see the Creating custom Jupyter Notebook widgets in Python, HTML, and JavaScript recipe). Widgets can also remain at least partly functional in a static notebook export.
Here are a few references:
- ipywidgets user guide at https://ipywidgets.readthedocs.io/en/stable/user_guide.html
- Building a custom widget at https://ipywidgets.
See also
- The Creating custom Jupyter Notebook widgets in Python, HTML, and JavaScript recipe