3. Widgets

If you are like a lot of data scientists, you are using Jupyter to manage and code your experiments and analyses. Instead of presenting static content generated by your notebooks, you can also make your notebooks interactive by using Jupyter Widgets. Let’s dive into widgets and see how they work.

3.1. Interact

The @interact decorator may be placed around functions to create

  • sliders

  • checkboxes

  • input text boxes

  • select dropdowns

[1]:
%matplotlib inline
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

np.random.seed(37)
plt.style.use('ggplot')

Here are two arguments, mean \(\mu\) and std \(\sigma\), that are associated with sliders. The sliders control the mean and standard deviation values that we used to sample from the \(X \sim \mathcal{N}(\mu, \sigma)\). Sliders are controlled by a tuple: (start, stop, step).

[2]:
from ipywidgets import interact

@interact(mean=(-40, 40, 2), std=(1, 5, 0.5))
def f(mean=10, std=1):
    fig, ax = plt.subplots(figsize=(5, 3))
    s = pd.Series(np.random.normal(mean, std, 5000))
    _ = s.plot(kind='kde', ax=ax)
    _ = ax.set_title('Slider Demo, change distribution')

An argument that is associated with checkbox must have boolean value. In the example below, we toggle the color of positive bars to blue (True) or red (False).

[3]:
@interact
def f(pos_blue=True):
    s = pd.Series([10, 15, -8, 7, -15])

    fig, ax = plt.subplots(figsize=(10, 3))

    color_map = {True: 'b', False: 'r'} if pos_blue else {True: 'r', False: 'b'}
    _ = s.plot(kind='bar', ax=ax, color=(s > 0).map(color_map))
    _ = ax.set_title('Bar plot, toggle colors')

A string argument will always create an input text box. In this example below, we convert each character to the integer representation in Unicode using ord() and plot out a line graph.

[4]:
@interact
def f(text='one-off coder is the best!'):
    if len(text.strip()) == 0:
        text = 'one-off coder is the best!'

    s = pd.Series([ord(l) for l in list(text)])

    fig, ax = plt.subplots(figsize=(10, 3))
    _ = s.plot(kind='line', ax=ax)
    _ = ax.set_title(f'Line plot, {text}')

Select dropdown boxes are created with a list of values. If the list is of tuples, each tuple must be of size two, where the first element is the display value and the second element is the backing value.

[5]:
df = pd.DataFrame(
    [('left', np.random.normal(5, 1)) for _ in range(100)] +
    [('right', np.random.normal(10, 1)) for _ in range(100)],
    columns=['handedness', 'score'])

@interact(handedness=[('left', 0), ('right', 1)])
def f(handedness=0):
    h = 'left' if handedness == 0 else 'right'
    s = df[df.handedness == h].score

    fig, ax = plt.subplots(figsize=(5, 3))

    _ = s.plot(kind='box', ax=ax)
    _ = ax.set_title(f'Box plot, {h} handedness, mean={s.mean():.2f}')

3.2. interactive()

You can use interactive() to create multiple widgets. Below, we create two sliders, one select dropdown box and one checkbox.

[6]:
from ipywidgets import interactive

def f(mean=3, std=2.5, color='red', small_sample=False):
    n = 100 if small_sample else 5000
    s = pd.Series(np.random.normal(mean, std, n))

    fig, ax = plt.subplots(figsize=(5, 3))

    _ = s.plot(kind='box', ax=ax, color=color)
    _ = ax.set_title(f'Box plot, mean={s.mean():.2f}')

w = interactive(f, mean=(-10, 10, 1), std=(1, 10, 0.5), color=['red', 'blue'], small_sample=False)
display(w)

3.3. interact_manual()

Using interact_manual() will display a button to execute the attached function only if the button is executed.

[7]:
from ipywidgets import interact_manual

w = interact_manual(f, mean=(-10, 10, 1), std=(1, 10, 0.5), color=['red', 'blue'], small_sample=False)
_ = display(w)
<function __main__.f(mean=3, std=2.5, color='red', small_sample=False)>

3.4. interactive_output()

With interactive_output() you can associate widgets to parameters of a function.

[8]:
import ipywidgets as widgets

mean_slider = widgets.IntSlider(min=-10, max=10, step=1, value=3, description='mean')
std_slider = widgets.FloatSlider(min=0.01, max=10.0, step=0.01, value=1.0, description='standard deviation')
small_checkbox = widgets.Checkbox(description='small sample?')
color_dropdown = widgets.Dropdown(options=['red', 'blue'], value='red', description='color')

ui = widgets.HBox([mean_slider, std_slider, small_checkbox, color_dropdown])
out = widgets.interactive_output(f, {'mean': mean_slider, 'std': std_slider, 'color': color_dropdown, 'small_sample': small_checkbox})

display(ui, out)

3.5. Other widgets

There are just too many widgets. Let’s look at the fun ones. Here’s the FloatProgress widget.

[9]:
import time

def do_it(fp):
    for i in range(1, 10):
        fp.value = i
        time.sleep(1)

fp = widgets.FloatProgress(
    value=0.0,
    min=0.0,
    max=10.0,
    step=1.0,
    description='progress:',
    bar_style='info',
    orientation='horizontal'
)

display(fp)
do_it(fp)

Sometimes we need to pick dates.

[10]:
dp = widgets.DatePicker(
    description='date:',
    disabled=False
)
display(dp)

At other times, colors.

[11]:
cp = widgets.ColorPicker(
    concise=False,
    description='color:',
    value='red',
    disabled=False
)
display(cp)
[12]:
btn = widgets.Button(
    description='Click me',
    disabled=False,
    button_style='danger',
    tooltip='Click me',
    icon='check'
)
display(btn)

3.6. Layouts

There’s four basic layouts.

  • box

  • horizontal box

  • vertical box

  • grid box (advanced, but seems to be experimental at the moment)

[13]:
widgets.Box([fp, dp, cp, btn])
[14]:
widgets.HBox([fp, dp, cp, btn])
[15]:
widgets.VBox([fp, dp, cp, btn])

You can use these layouts together.

[16]:
row_0 = widgets.HBox([fp, dp])
row_1 = widgets.HBox([cp, btn])
col = widgets.VBox([row_0, row_1])
display(col)

Out of the box layouts are also available.