Demo: IPyWidgets
The following sections contain examples of some common widget types. Remix this notebook to play around with them.
Note: IPyWidget support is currently experimental. Check out IPyWidgets Support for more info.
Interactive Matplotlib Visualisations
In its simplest form, widgets enhance Python functions with interaction capabilities. The following example shows how to use a context manager to plot solutions to a SIR ODE model (see hidden code cell) whose parameters can be changed by dragging the slider for each input.
SIR Model
import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import odeint
N = 1 # Size of the population (so everything in proportions)
I0 = 0.01 # Initial proportion of the population infected
S0 = N - I0 # Initial proportion of the population susceptible
R0 = 0.0 # Initial proportion of the population recovered
maxT = 25 # max number of periods in simulation
beta = 0.5 # transmission rate
gamma = 0.1 # recovery rate
def SIR(y, t, beta, gamma):
'''the SIR model'''
S, I, R = y
dSdt = -beta*S*I
dIdt = beta*S*I - gamma*I
dRdt = gamma*I
return([dSdt, dIdt, dRdt])
Input Sliders
from ipywidgets import interact
beta=(0,1,0.05), gamma=(0,1,0.05), maxT=(5,100,5)) (
def plotSIR(beta = beta, gamma = gamma, maxT = maxT):
'''Solve differential equations in SIR and plot'''
t = np.linspace(0, maxT, 1000)
soln = odeint(SIR, [S0,I0,R0], t, args=(beta, gamma))
soln = np.array(soln)
plt.figure(figsize=[8,6])
plt.plot(t, soln[:,0], linewidth=3, label = 'S(t)')
plt.plot(t, soln[:,1], linewidth=3, label = 'I(t)')
plt.plot(t, soln[:,2], linewidth=3, label = 'R(t)')
plt.title("SIR model")
plt.xlabel("Time"); plt.ylabel("proportions")
plt.grid(); plt.legend()
Compound Widgets
This examples shows how you can use a compound widget for exploring data frames. Specifically, we will use VBox
and HBox
for more fine-grained control over the layout and how to combine update callbacks with the observe
method:
import pandas as pd
from ipywidgets import widgets
df = pd.read_csv(cars.csv)
Data Frame Explorer
table = widgets.HTML()
html = widgets.HTML()
min_sl = widgets.IntSlider(min= 0, max=40, value=7)
max_sl = widgets.IntSlider(min=0, max=40, value=8)
def draw(_ = None):
min_mpg = min_sl.value
max_mpg = max_sl.value
cols = ['ID', 'City mpg']
selection = df.loc[df['City mpg'].between(min_mpg, max_mpg)]
selection.reindex(columns=cols)
table.value = f'<h3>Found: {len(selection)}</h3>'
html.value = selection[cols].to_html()
min_sl.observe(draw)
max_sl.observe(draw)
draw() # first draw
widgets.VBox([table,
widgets.HBox([min_sl, max_sl]),
html])
Plotly Figure Widgets
The following example shows how to set up a basic Plotly FigureWidget (based on the examples in Jon Mease's notebooks):
from sklearn import datasets
import time
iris_data = datasets.load_iris()
feature_names = [name.replace(' (cm)', '').replace(' ', '_') for name in iris_data.feature_names]
iris_df = pd.DataFrame(iris_data.data, columns=feature_names)
iris_class = iris_data.target + 1
FigureWidgets behave almost identically to Plotly Figure objects. The major difference here is that they are also IPyWidgets that can be interacted with. If you execute all the cells following the next cell ("Commands ⌘/Ctrl+J
→ Run Cells Below") you’ll see the plot changing on each evaluation.
Mind you can always use "Commands ⌘/Ctrl+J
→ Outputs / Clear" to remove the plots.
import plotly.graph_objs as go
fig = go.FigureWidget()
fig
fig.add_scatter(x=iris_df.sepal_length, y=iris_df.petal_width)
scatter = fig.data[0]
Any change to the widget’s underlying data (which acts as traitlets) will automatically update the plot for you …
time.sleep(2)
scatter.mode = 'markers'
scatter.marker.size = 8
scatter.marker.color = iris_class
scatter.marker.cmin = 0.5
scatter.marker.cmax = 3.5
scatter.marker.colorscale = [[0, 'red'], [0.33, 'red'],
[0.33, 'green'], [0.67, 'green'],
[0.67, 'blue'], [1.0, 'blue']]
… batch updates instead send a single message to the frontend, aggregating all changed attributes at once:
with fig.batch_update():
scatter.marker.colorbar.ticks = 'outside'
scatter.marker.colorbar.tickvals = [1, 2, 3]
scatter.marker.colorbar.ticktext = iris_data.target_names.tolist()
scatter.marker.colorbar.title = 'Species'
scatter.marker.colorbar.titlefont.size = 16
scatter.marker.colorbar.titlefont.family = 'Rockwell'
fig.layout.xaxis.title = 'sepal_length'
fig.layout.yaxis.title = 'petal_width'
scatter.marker.showscale = True
Animating Changes
All changes to the data can also be animated …
with fig.batch_animate(duration=1500):
scatter.marker.size = np.sqrt(iris_df.petal_length.values * 60)
with fig.batch_animate(duration=1500):
scatter.marker.size = 8
… and Figure widgets can interact with any other kind of widget to be assembled into more complex visualisations:
from IPython.display import display, HTML
outx = widgets.Output()
outy = widgets.Output()
fig2 = go.FigureWidget(data=fig.data)
def report_extrema(trace, points, state):
outx.clear_output(wait=True)
outy.clear_output(wait=True)
with outx:
display(HTML(f"<em>Max x-value: {np.max(points.xs)}</em>"))
display(HTML(f"<em>Min x-value: {np.min(points.xs)}</em>"))
with outy:
display(HTML(f"<em>Max y-value: {np.max(points.ys)}</em>"))
display(HTML(f"<em>Min y-value: {np.min(points.ys)}</em>"))
fig2.layout.dragmode = 'lasso'
fig2.data[0].marker.showscale = False
fig2.data[0].on_selection(report_extrema)
In the following plot, every "lasso" selection performed by the cursor will populate HTML output widgets with minima and maxima values from the selected points:
widgets.VBox([fig2, widgets.HBox([outx, outy])])
We hope this short overview has been useful and inspires creating more interactive notebooks.
Troubleshooting
If widget display goes out-of-sync with the backend kernel try to:
Clear outputs: Commands
⌘/Ctrl+J
→ Outputs / ClearStop the runtime: Commands
⌘/Ctrl+J
→ Runtime / Reset