Suppose we want to explore the effect of changing the frequency of a sine wave plotted over a specific range of values.
We can use matplotlib to plot a simple chart.
%matplotlib inline
import matplotlib.pyplot as plt
import numpy as np
# Create 1000 evenly-spaced values from 0 to 2 pi
x = np.linspace(0, 2*np.pi, 1000)
#Set the frequency
f=1
#Plot a sine wave over those values
y = np.sin(f*x)
plt.plot(x, y)
[<matplotlib.lines.Line2D at 0x112e2b550>]
To plot the chart for a different value of f
, we could change the value of f
in the code cell above and run the code again.
Or we could repeat ourselves a bit...
#Set the frequency
f=2
#Plot a sine wave over those values
y = np.sin(f*x)
plt.plot(x, y)
[<matplotlib.lines.Line2D at 0x112e0ecf8>]
Wouldn't it be nice if we could make a simple interactive tool that lets us explore the effect of changing f
directly? For example, a slider we could use to set the value of f
and automatically plot the result?
The interact()
function in the ipywidgets
package let's us do exactly that - but it requires that we get our code into a form where we can just pass it the value of f
and let it plot the chart.
Defing a function allows us to do exactly that:
#Create a function that will plot a sine wave over the range 0..2 pi for a specified frequency
#If no frequncy value is specified, use the default setting: f=1
def sinplot(f=1):
#Define a range of x values
x = np.linspace(0, 2*np.pi, 1000)
#Plot a sine wave with the specified frequency over that range
y = np.sin(f*x)
#Plot the chart
plt.plot(x, y)
sinplot(f=3)
Now let's use that function with a widget to control the setting of the frequency, specifying the initial default value for slider and letting the interact()
function set the range automatically:
from ipywidgets import interact
interact(sinplot, f=5)
<function __main__.sinplot>
We can make things more elaborate - for example, setting the maximum x value too, and specifying a range for the slider values, rather than letting interact()
guess at the limits for us.
def sinplot2(f=1,max_x=2*np.pi):
#Define a range of x values
x = np.linspace(0, max_x, 1000)
#Plot a sine wave with the specified frequency over that range
y = np.sin(f*x)
#Plot the chart
plt.plot(x, y)
interact(sinplot2, f=5,max_x=[0,4*np.pi])
There is an even tidier way of doing this, which is to use python function decorators. How these work can be a little difficult to explain, but you should be able to see a pattern going from the previous code cell to the one immediately below that's make them work in this case...
@interact(f=5,max_x=[0,7])
def sinplot2(f=1,max_x=2*np.pi):
''' Plot the sine of a range of values '''
#Define a range of x values
x = np.linspace(0, max_x, 1000)
#Plot a sine wave with the specified frequency over that range
y = np.sin(f*x)
#Plot the chart
plt.plot(x, y)
If you decorate the function simply with:
@interact()
the widget ranges will be automatically determined from the default values passed into the decorated function.
If you want to create a simple interactive visualisation as part of an exploratory data analysis process, create a function that generates the plot and accepts parameters related to the dimensions you want to explore, and then pass it to the ipywidgets interact()
function. You can also pass in an indication of the default values or range you want applied to the widgets.
The interact()
function can also be used to generate a range of other widget types, such as drop down lists for categorical variables.
Widgets can also be defined relative to one another. For example, it is possible to link two drop down lists where the contents of one list are dependent on the contents of another (example).