31  Widgets

Author

Andres Patrignani

Published

January 9, 2024

Adding interactivity to Jupyter notebooks can be a great way of improving exploratory data analysis and real-time interactive data visualization. The ipywidgets library provides a powerful toolset for creating interactive widget elements like sliders, dropdowns, and buttons in Jupyter notebooks.

The following examples will demonstrate:

Note

The widgets may not appear in the online version of the tutorial. Either copy the code and run it in your local Jupyter notebook or download the notebook from the Github repository.

Example 1: Convert bushels to metric tons

A common task in agronomy is to convert grain yields from bushels to metric tons. We will use ipywidgets to create interactive dropdowns and slider widgets to facilitate the convertion between these two units for common crops.

# Import modules
import ipywidgets as widgets
# Define widget
crop_dropdown = widgets.Dropdown(options=['Barley','Corn','Sorghum','Soybeans','Wheat'],
                                 value='Wheat', description='Crop')
bushels_slider = widgets.FloatSlider(value=40, min=0, max=200, step=1,
                                    description='Bushels/acre')

# Define function
def bushels_to_tons(crop, bu):
    """Function that converts bushels to metric tons for common crops.
       Source: https://grains.org/
    """
    # Define constants
    lbs_per_ton = 0.453592/1000
    acres_per_ha = 2.47105
    
    # Convert bu -> lbs -> tons
    if crop == 'Barley':
        tons =  bu * 48 * lbs_per_ton 
        
    elif crop == 'Corn' or crop == 'Sorghum':
        tons =  bu * 56 * lbs_per_ton
        
    elif crop == 'Wheat' or crop == 'Soybeans':
        tons = bu * 60 * lbs_per_ton
        
    # Convert acre -> hectares
    tons = round(tons * acres_per_ha, 2)
    return widgets.FloatText(value=tons, description='Tons/ha', disabled=True)


# Define interactivity
widgets.interact(bushels_to_tons, crop=crop_dropdown, bu=bushels_slider);

Example 2: Runoff-Precipitation

Widgets are also a great tool to explore and learn how models representing real-world processes respond to input changes. In this example we will explore how the curve number of a soil is related to the amount of runoff for a range of precipitation amounts.

import ipywidgets as widgets
import matplotlib.pyplot as plt
import numpy as np
plt.style.use('ggplot')
# Create widget
cn_slider = widgets.IntSlider(50, min=1, max=100, description='Curve number')

# Create function
def estimate_runoff(cn):
    """Function that computes runoff based on the 
    curve number method proposed by the Soil Conservation Service
    Source: https://www.wikiwand.com/en/Runoff_curve_number

    Inputs
    cn : Curve number. 0 means fully permeable and 100 means fully impervious.
    
    Returns
    Figure of runoff as a function of precipitation
    """

    P = np.arange(0, 12, step=0.01) # Precipitation in inches
    RO = np.zeros_like(P)
    S = 1000/cn - 10
    Ia = S * 0.05 # Initial abstraction (inches)
    idx = P > Ia
    RO[idx] = (P[idx] - Ia)**2 / (P[idx] - Ia + S)

    # Create figure
    plt.figure(figsize=(6,4))
    plt.plot(P,RO,'--k')
    plt.title('Curve Number Method')
    plt.xlabel('Precipitation (inches)')
    plt.ylabel('Runoff (inches)')
    plt.xlim([0,12])
    plt.ylim([0,12])
    return plt.show()

# Define interactivity
widgets.interact(estimate_runoff, cn=cn_slider);