Custom Interactive Controls in jupyter notebooks

1. using @interact decorator

This is the easiest way to add interactive widgets. Import the interact function from ipywidgets. Wrap the code you want to be interactive in a function with the parameters having a default value. Put @interact decorator above this function. On execution, the interact decorator creates widgets for each of the parameters of the wrapper function. The default values for the parameters are necessary because the interact decorator inferences the widget type using these values.

In this example, we plot a circle and provide interactive widgets to alter its linewidth, boundary color and radius. We start with putting %matplotlib widget which specifies that we want an interactive matplotlib figure (which can be zoomed, panned and saved). Next we import the necessary libraries and objects and define a function named circle to plot the circle. It contains arguments/parameters which we want to alter with interactive widgets and they have default values to be used with the interact decorator as described in earlier sections. Now we define the code to plot the circle inside this function and use these parameters wherever the alterable property is to be specified. Finally decorate the circle function with @interact.

Python3




%matplotlib widget
import numpy as np
import matplotlib.pyplot as plt
from ipywidgets import interact, widgets
 
@interact
def circle(radius=1.0, linewidth=1, color = ['red', 'blue', 'green']):
    angles = np.linspace(0,2*np.pi,100)
    fig, ax = plt.subplots()
    ax.set_aspect(1)
    ax.set_xlim(-10,10)
    ax.set_ylim(-10,10)
    ax.plot(radius*np.cos(angles), radius*np.sin(angles), linewidth = linewidth, c = color)
    plt.show()


Output:

2. using interact function call

This example improves the last example by using interact function call (instead of decorator) which allows greater flexibility as it allows specifying a widget for each parameter. We can remove the default arguments here. We use the interact function as shown earlier. Using this flexibility, we improve certain things like setting max and min for radius and linewidth. Earlier example provided a slider for linewidth which can be slided below 0. This is not desirable since specifying linewidth below 0 is meaningless, hence we specify the min of its slider to 0. Also, instead of a list of colors, we provided a color picker widget which allows the user to pick just any color.

Python3




%matplotlib widget
import numpy as np
import matplotlib.pyplot as plt
from ipywidgets import interact, widgets
 
def circle(radius, linewidth, color):
    angles = np.linspace(0,2*np.pi,100)
    fig, ax = plt.subplots()
    ax.set_aspect(1)
    ax.set_xlim(-10,10)
    ax.set_ylim(-10,10)
    ax.plot(radius*np.cos(angles), radius*np.sin(angles), linewidth = linewidth, c = color)
    plt.title('Circle of radius {} units'.format(radius))
    plt.show()
 
interact(
    circle,
    radius = widgets.FloatSlider(min = 0, max = 10, value = 1),
    linewidth = widgets.IntSlider(min = 0, max = 5, value = 1),
    color = widgets.ColorPicker()
)


Output:

Using the interact_manual function/decorator

When you want to turn off auto-update, just replace the interact decorator or function with interact_manual keeping rest of the things unchanged. Auto update will be turned off and you will get an update button as shown in this example –

Python3




import matplotlib.pyplot as plt
from ipywidgets import interact_manual, widgets
 
@interact_manual
def wrapperFunction(x = 5,y = 4):
    plt.xlim(0,10)
    plt.ylim(0,10)
    plt.plot(x,y,marker = 'o')
    plt.show()


Output:

Example of interactive controls in Jupyter Notebook using interact_manual from ipywidgets.

Notice that “Run Interact” button in the output. It should be clicked to update the output.

Note: We used matplotlib here, but one can use any plotting library that jupyter supports like plotly, bokeh, etc. inside the wrapper function because the code inside the wrapper function doesn’t matter for the interactive widgets.

Interactive scatter plot with IPywidgets controls

It is an interactive 3D scatter plot using IPywidgets and Matplotlib. It will display three sliders that allow you to interactively adjust the limits of the 3D scatter plot along the X, Y, and Z axes. The plot updates dynamically as you move the sliders, providing an interactive exploration of the 3D scatter plot.

Python3




import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import ipywidgets as widgets
from IPython.display import display
 
# Generate random data for the 3D scatter plot
np.random.seed(42)
x_data = np.random.rand(50)
y_data = np.random.rand(50)
z_data = np.random.rand(50)
 
# Create 3D scatter plot function
def create_3d_scatter_plot(x_limit, y_limit, z_limit):
    fig = plt.figure(figsize=(10, 8))
    ax = fig.add_subplot(111, projection='3d')
    ax.scatter(x_data, y_data, z_data, label='Scatter Plot', c='red', marker='o')
    ax.set_title('Interactive 3D Scatter Plot')
    ax.set_xlabel('X-axis')
    ax.set_ylabel('Y-axis')
    ax.set_zlabel('Z-axis')
    ax.set_xlim(0, x_limit)
    ax.set_ylim(0, y_limit)
    ax.set_zlim(0, z_limit)
    ax.legend()
    plt.show()
 
# Define interactive controls using IPywidgets
x_limit_slider = widgets.FloatSlider(value=1.0, min=0.1, max=2.0, step=0.1, description='X-axis Limit:')
y_limit_slider = widgets.FloatSlider(value=1.0, min=0.1, max=2.0, step=0.1, description='Y-axis Limit:')
z_limit_slider = widgets.FloatSlider(value=1.0, min=0.1, max=2.0, step=0.1, description='Z-axis Limit:')
 
# Define update function for the 3D scatter plot
def update_plot(change):
    create_3d_scatter_plot(x_limit_slider.value, y_limit_slider.value, z_limit_slider.value)
 
# Attach the update function to the sliders' value change event
x_limit_slider.observe(update_plot, 'value')
y_limit_slider.observe(update_plot, 'value')
z_limit_slider.observe(update_plot, 'value')
 
# Display the interactive controls
display(x_limit_slider)
display(y_limit_slider)
display(z_limit_slider)
 
# Initial 3D scatter plot
create_3d_scatter_plot(x_limit_slider.value, y_limit_slider.value, z_limit_slider.value)


Output:

Browsing images using IPython widgets

We can put in the name of a folder and the file dropdown will list all the image files (ending with .png, .jpg, .jpeg and .gif). We can select an image to show. Moreover, one can choose to apply the blur radius using checkbox and select the blur radius through the slider. We need flexibility in deciding and defining widgets so we naturally use the method of calling interact function explicitly here. The code structure is almost similar to the last example except that we observe any changes in value of folder input widget. Whenever its value changes, we update the file selection (dropdown) widget to list all the image files in that folder and show the first one by default. To work with the image we need to install pillow library which must be installed using pip as all the other modules were installed earlier.

Python3




%matplotlib widget
import matplotlib.pyplot as plt
from ipywidgets import interact, widgets
import numpy as np
import os
from PIL import Image, ImageFilter
 
def imageEditor(folder, filename, blur, blurRadius):   
    # Opens a image in RGB mode
    im = Image.open('{}\\{}'.format(folder, filename))
 
    if(blur == True):
        # blur only if checkbox checked
        im = im.filter(ImageFilter.GaussianBlur(blurRadius))
         
    # show the image
    plt.imshow(im)
    plt.axis('off')
    plt.show()
 
# creating the widgets
folderWidget = widgets.Text(value = os.getcwd() + '\\images\\pngFiles')
fileWidget = widgets.Dropdown(options = os.listdir(folderWidget.value))
 
# update function to update fileslist when folder name changes
def updateFilesList(*args):
    filesList = [file for file in os.listdir(folderWidget.value) if file.endswith(('.png', '.jpg', '.jpeg','.gif'))]
    fileWidget.options = filesList
    fileWidget.value = filesList[0]
 
# observer folder widget and call updateFilesList whenever its value changes
folderWidget.observe(updateFilesList, 'value')
 
interact(
    imageEditor,
    filename = fileWidget,
    folder = folderWidget,
    blur = widgets.Checkbox(value = False),
    blurRadius = widgets.FloatSlider(min = 0, max = 5, description = "Blur Radius")
)


Output:

Interactive Paraboloid

Now the reader has enough knowledge to understand the code for the paraboloid example shown in the cover video. Here is the code for the paraboloid with interactive controls shown in cover video –

Python3




from ipywidgets import interact
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
 
 
def plot_paraboloid(height=1.0, radius=1.0, rotation=5.0, colormap='viridis'):
    u = np.linspace(0, 1, 20)
    v = np.linspace(0, 2 * np.pi, 20)
    u, v = np.meshgrid(u, v)
 
    x = radius * ((u / height) ** 0.5) * np.cos(v)
    y = radius * ((u / height) ** 0.5) * np.sin(v)
    z = u
 
    fig = plt.figure()
    ax = fig.add_subplot(111, projection='3d')
    ax.set_aspect('equal')
    ax.set_xlim(-1.5, 1.5)
    ax.set_ylim(-1.5, 1.5)
    ax.set_zlim(0, 1)
    ax.plot_surface(x, y, z, cmap=colormap)
    ax.view_init(elev=20, azim=rotation)
    plt.show()
 
 
interact(plot_paraboloid, height=(0.1, 2.0), radius=(0.1, 2.0),
         rotation=(-180, 180), colormap=['viridis', 'Blues', 'magma_r'])


Output:

Interactive 3D Surface Plot

It creates an interactive 3D surface plot using IPywidgets and Matplotlib. The sliders for adjusting the values of a, b, and c, as well as a dropdown menu for selecting different colormaps. The 3D surface plot dynamically updates as you interact with the sliders and colormap menu.

Python3




from ipywidgets import interact
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
 
def surface_plot(a=1, b=1, c=1, colormap='viridis'):
    x = np.linspace(-5, 5, 100)
    y = np.linspace(-5, 5, 100)
    x, y = np.meshgrid(x, y)
    z = a * np.exp(-(x**2 + y**2) / (2*c**2))
 
    fig = plt.figure()
    ax = fig.add_subplot(111, projection='3d')
    ax.plot_surface(x, y, z, cmap=colormap)
    ax.set_xlabel('X-axis')
    ax.set_ylabel('Y-axis')
    ax.set_zlabel('Z-axis')
    ax.set_title('3D Surface Plot')
    plt.show()
 
interact(surface_plot, a=(0.1, 2.0), b=(0.1, 2.0), c=(0.1, 2.0), colormap=['viridis', 'Blues', 'magma_r'])


Output:

Interactive Controls in Jupyter Notebooks

This article explains the significance of interactive controls in Jupyter Notebooks and presents a few different methods of adding them to the notebooks for Python programming language. A list of basic controls/widgets and finally examples are provided to demonstrate all that is presented throughout this article. This article expects basic familiarity with Python and Jupyter Notebooks.

Similar Reads

Interactive Controls for Jupyter Notebooks

We often need to explore figures and data in Jupyter notebooks by observing it for different values of parameters involved. The obvious solution is to change the value of parameters in the code and then run it and repeat this process for the different values we are targeting. In practice, this process becomes inconvenient and frustrating as the number of parameters and the possible values for each parameter that we want to explore grows. One solution for this problem is Jupiter interactive controls which can be added by using Jupyter widgets....

Basic Interactive widgets in Jupyter Notebooks

Lots of widgets are available in ipywidgets for jupyter notebooks. The complete list can be obtained here on the official documentation. This section provides the syntax and usage of few basic widgets –...

Custom Interactive Controls in jupyter notebooks

...

Conclusion

...