Ipywidgets

Ipywidgets#

If you publish widgets in a jupyter book they might (depending on your implementation) require an active python kernel for the output to be interactive. Using the thebe-integration, this is possible. Note: You can circumvent the use of a kernel by using packages which don’t need such a kernel, for example the non-kernel-based widgets using Plotly.

matplotlib widgets#

When you’d like to use ipywidgets in combinations with a matplotlib figure, import the following packages:

import ipywidgets as widgets
import micropip
await micropip.install("ipympl")

Activate the correct output format:

%matplotlib widget

Write the code which generates your plot in a function:

fig = plt.figure()  # Define the figure once
ax = fig.add_subplot(1,1,1)       # Define the axis once

def update_plot(input_variables_from_widget):
    ax.clear()   # Clear the existing plot
    ax.plot(x,y) # Plot your actual data
    plt.draw()   # Update the plot whenever this function is executed

Initiate the widget:

input_slider = widgets.FloatSlider(value=0, min=0, max=10, step=1, description='Input variable:') # Defines a widget, more options than just FloatSlider
widgets.interact(update_plot, input_variable_from_widget = input_slider);

Please note:

  • You might want to hide the output before the thebe has been activated.

  • You can hide the code by adding a custom-made tag: thebe-remove-input-init.

  • You can automatically start the thebe functionality when you add auto-execute-page to a cell.

Example#

The code below shows an example of the strain energy in a structure and work done by a force for different trial functions. Because of the actual python code, the plot ‘refreshes’ upon updating a widgets. This can be avoided by updating the current figure instead of plotting a new figure. Remember, first press –> Live Code and then wait until all cells are executed:

import sympy as sp
F = 10
EI = 20e3
L = 3

# Polynomial trial function
x, C1, C2, C3, C4, F, u0= sp.symbols('x, C1, C2, C3, C4, F, u0')
w = C1*x**3+C2*x**2+C3*x + C4
eq1 = sp.Eq(w.subs(x,0),0)
eq2 = sp.Eq(w.diff(x).subs(x,0),0)
eq3 = sp.Eq((-w.diff(x,2)*EI).subs(x,L),0)
eq4 = sp.Eq(w.subs(x,L),u0)
sol = sp.solve((eq1, eq2,eq3,eq4),(C1,C2,C3,C4))
w_sol = sp.nsimplify(w.subs(sol))
w_numpy_polynomial = sp.lambdify((u0,x),w_sol)

M_sol_polynomial = sp.nsimplify(EI * w_sol.diff(x,2))

Ev_polynomial = sp.integrate(sp.nsimplify(M_sol_polynomial**2/(EI*2)),(x,0,3))

Ev_numpy_polynomial = sp.lambdify(u0,Ev_polynomial)

V_polynomial = Ev_polynomial - 10 * u0
V_numpy_polynomial = sp.lambdify(u0,V_polynomial)

#cosine trial function
w_sol = u0*sp.sin(x/12*2*sp.pi-sp.pi/2)+u0
w_numpy_sin = sp.lambdify((u0,x),w_sol)

M_sol_sin = sp.nsimplify(EI * w_sol.diff(x,2))

Ev_sin = sp.integrate(sp.nsimplify(M_sol_sin**2/(EI*2)),(x,0,3))

Ev_numpy_sin = sp.lambdify(u0,Ev_sin)

V_sin = Ev_sin - 10 * u0
V_numpy_sin = sp.lambdify(u0,V_sin)

#sin trial function
w_sol = 2*u0*(sp.cosh(x/sp.pi))-2*u0
w_numpy_cosh = sp.lambdify((u0,x),w_sol)

M_sol_cosh = sp.nsimplify(EI * w_sol.diff(x,2))

Ev_cosh = sp.integrate(sp.nsimplify(M_sol_cosh**2/(EI*2)),(x,0,3))

Ev_numpy_cosh = sp.lambdify(u0,Ev_cosh)

V_cosh = Ev_cosh - 10 * u0
V_numpy_cosh = sp.lambdify(u0,V_cosh)

import matplotlib.pylab as plt
import numpy as np
from ipywidgets import widgets, interact

def func(u,trial_function):
    fig, axs = plt.subplots(2, 2, figsize=(10, 6))

    x = np.linspace(0,3,100)
    if trial_function == 'Polynomial':
        w_numpy = w_numpy_polynomial
        Ev_numpy = Ev_numpy_polynomial
        V_numpy = V_numpy_polynomial
    elif trial_function == 'cos':
        w_numpy = w_numpy_sin
        Ev_numpy = Ev_numpy_sin
        V_numpy = V_numpy_sin
    elif trial_function == 'cosh':
        w_numpy = w_numpy_cosh
        Ev_numpy = Ev_numpy_cosh
        V_numpy = V_numpy_cosh
    axs[0,0].plot(x,w_numpy(u,x))
    axs[0,0].set_xlim([-0.2,3.2])
    axs[0,0].set_ylim([-0.003,0.01])
    axs[0,0].invert_yaxis()
    axs[0,0].annotate(text='', xy=(3,w_numpy(u,3)), xytext=(3,0), arrowprops=dict(arrowstyle='fancy'))
    axs[0,0].text(3.1,w_numpy(u,3),'$u_0$')
    axs[0,0].axis('off')
    axs[0,1].axis('off')
    axs[0,1].set_xlim([-0.2,3.2])
    axs[0,1].set_ylim([-0.003,0.01])
    axs[0,1].annotate(text='', xy=(1.5,w_numpy(u,3)), xytext=(1.5,w_numpy(u,3)-0.003), arrowprops=dict(arrowstyle='simple'))
    axs[0,1].invert_yaxis()
    x_axis= ['$E_v$','$A_F$','$E_v - A_F$']
    y_axis = [Ev_numpy(u),w_numpy(u,3)*10,Ev_numpy(u)-w_numpy(u,3)*10]
    axs[1,0].bar(x_axis,y_axis,color=('blue','green','orange'))
    axs[1,0].set_ylim([-0.03,0.1])
    axs[1,0].set_yticklabels([])
    axs[1,0].set_yticks([])
    
    u_range=np.linspace(-0.0015,0.01,100)
    axs[1,1].plot(u_range,Ev_numpy(u_range),label='$E_v$',color='blue')
    axs[1,1].plot(u_range,w_numpy(u_range,3)*10,label='$F_A$',color='green')
    axs[1,1].plot(u_range,V_numpy(u_range),label='$E_v - A_F$',color='orange')
    axs[1,1].legend()
    axs[1,1].plot(u,Ev_numpy(u),'o',color='blue')
    axs[1,1].plot(u,w_numpy(u,3)*10,'o',color='green')
    axs[1,1].plot(u,Ev_numpy(u)-w_numpy(u,3)*10,'o',color='orange')
    axs[1,1].set_ylim([-0.03,0.1])
    axs[1,1].set_xlim([-0.0015,0.01])
    axs[1,1].set_xlabel('$u_0$')
    axs[1,1].set_xticks([])
    axs[1,1].set_xticklabels([])
    axs[1,1].set_yticks([])
    plt.show()

The graph will appear below in interactive mode:

interact(func, u = widgets.FloatSlider(min=-0.001, max=0.01, value=0, step=0.0002, description="Displacement u_0",readout_format='.4f',style= {'description_width': '180px'},layout = {'width': '400px'}),
        trial_function = widgets.ToggleButtons(options=['Polynomial', 'cos', 'cosh']));