manual_teachbooks/book/features/widgets.ipynb
2025-11-03 17:48:38 +01:00

243 lines
8.7 KiB
Text

{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Ipywidgets\n",
"\n",
"If you publish widgets in a TeachBook they might (depending on your implementation) require an active python kernel for the output to be interactive. Using the [thebe-integration](../examples/live_code.md), 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](./plotly.ipynb).\n",
"\n",
"## `matplotlib` widgets\n",
"When you'd like to use `ipywidgets` in combinations with a `matplotlib` figure, import the following packages:\n",
"\n",
"```python\n",
"import ipywidgets as widgets\n",
"import micropip\n",
"await micropip.install(\"ipympl\")\n",
"```\n",
"\n",
"Activate the correct output format:\n",
"\n",
"```python\n",
"%matplotlib widget\n",
"```\n",
"\n",
"Write the code which generates your plot in a function:\n",
"\n",
"```python\n",
"fig = plt.figure() # Define the figure once\n",
"ax = fig.add_subplot(1,1,1) # Define the axis once\n",
"\n",
"def update_plot(input_variables_from_widget):\n",
" ax.clear() # Clear the existing plot\n",
" ax.plot(x,y) # Plot your actual data\n",
" plt.draw() # Update the plot whenever this function is executed\n",
"```\n",
"\n",
"Initiate the widget:\n",
"\n",
"```python\n",
"input_slider = widgets.FloatSlider(value=0, min=0, max=10, step=1, description='Input variable:') # Defines a widget, more options than just FloatSlider\n",
"widgets.interact(update_plot, input_variable_from_widget = input_slider);\n",
"```\n",
"\n",
"Finally, When using `%matplotlib widget`, there's the following toolbar:\n",
"\n",
"![](./figures/toolbar.png)\n",
"\n",
"Which only shows up when you hoover above. If you want to disable the toolbar you can use:\n",
"```python\n",
"fig = plt.gcf()\n",
"fig.canvas.toolbar_visible = False\n",
"```\n",
"\n",
"If you want it to be visible even if you don't hoover above it, use:\n",
"\n",
"```python\n",
"fig = plt.gcf()\n",
"fig.canvas.toolbar_visible = True\n",
"```"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Please note:\n",
"- You might want to hide the output before the thebe has been activated.\n",
"- You can hide the code by adding a custom-made tag: `thebe-remove-input-init`.\n",
"- You can automatically start the thebe functionality when you add `auto-execute-page` to a cell. \n",
"\n",
"## Example\n",
"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 {fa}`rocket` --> {guilabel}`Live Code` and then wait until all cells are executed:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"tags": [
"thebe-remove-input-init",
"auto-execute-page"
]
},
"outputs": [],
"source": [
"import sympy as sp\n",
"F = 10\n",
"EI = 20e3\n",
"L = 3\n",
"\n",
"# Polynomial trial function\n",
"x, C1, C2, C3, C4, F, u0= sp.symbols('x, C1, C2, C3, C4, F, u0')\n",
"w = C1*x**3+C2*x**2+C3*x + C4\n",
"eq1 = sp.Eq(w.subs(x,0),0)\n",
"eq2 = sp.Eq(w.diff(x).subs(x,0),0)\n",
"eq3 = sp.Eq((-w.diff(x,2)*EI).subs(x,L),0)\n",
"eq4 = sp.Eq(w.subs(x,L),u0)\n",
"sol = sp.solve((eq1, eq2,eq3,eq4),(C1,C2,C3,C4))\n",
"w_sol = sp.nsimplify(w.subs(sol))\n",
"w_numpy_polynomial = sp.lambdify((u0,x),w_sol)\n",
"\n",
"M_sol_polynomial = sp.nsimplify(EI * w_sol.diff(x,2))\n",
"\n",
"Ev_polynomial = sp.integrate(sp.nsimplify(M_sol_polynomial**2/(EI*2)),(x,0,3))\n",
"\n",
"Ev_numpy_polynomial = sp.lambdify(u0,Ev_polynomial)\n",
"\n",
"V_polynomial = Ev_polynomial - 10 * u0\n",
"V_numpy_polynomial = sp.lambdify(u0,V_polynomial)\n",
"\n",
"#cosine trial function\n",
"w_sol = u0*sp.sin(x/12*2*sp.pi-sp.pi/2)+u0\n",
"w_numpy_sin = sp.lambdify((u0,x),w_sol)\n",
"\n",
"M_sol_sin = sp.nsimplify(EI * w_sol.diff(x,2))\n",
"\n",
"Ev_sin = sp.integrate(sp.nsimplify(M_sol_sin**2/(EI*2)),(x,0,3))\n",
"\n",
"Ev_numpy_sin = sp.lambdify(u0,Ev_sin)\n",
"\n",
"V_sin = Ev_sin - 10 * u0\n",
"V_numpy_sin = sp.lambdify(u0,V_sin)\n",
"\n",
"#sin trial function\n",
"w_sol = 2*u0*(sp.cosh(x/sp.pi))-2*u0\n",
"w_numpy_cosh = sp.lambdify((u0,x),w_sol)\n",
"\n",
"M_sol_cosh = sp.nsimplify(EI * w_sol.diff(x,2))\n",
"\n",
"Ev_cosh = sp.integrate(sp.nsimplify(M_sol_cosh**2/(EI*2)),(x,0,3))\n",
"\n",
"Ev_numpy_cosh = sp.lambdify(u0,Ev_cosh)\n",
"\n",
"V_cosh = Ev_cosh - 10 * u0\n",
"V_numpy_cosh = sp.lambdify(u0,V_cosh)\n",
"\n",
"import matplotlib.pylab as plt\n",
"import numpy as np\n",
"from ipywidgets import widgets, interact\n",
"\n",
"def func(u,trial_function):\n",
" fig, axs = plt.subplots(2, 2, figsize=(10, 6))\n",
"\n",
" x = np.linspace(0,3,100)\n",
" if trial_function == 'Polynomial':\n",
" w_numpy = w_numpy_polynomial\n",
" Ev_numpy = Ev_numpy_polynomial\n",
" V_numpy = V_numpy_polynomial\n",
" elif trial_function == 'cos':\n",
" w_numpy = w_numpy_sin\n",
" Ev_numpy = Ev_numpy_sin\n",
" V_numpy = V_numpy_sin\n",
" elif trial_function == 'cosh':\n",
" w_numpy = w_numpy_cosh\n",
" Ev_numpy = Ev_numpy_cosh\n",
" V_numpy = V_numpy_cosh\n",
" axs[0,0].plot(x,w_numpy(u,x))\n",
" axs[0,0].set_xlim([-0.2,3.2])\n",
" axs[0,0].set_ylim([-0.003,0.01])\n",
" axs[0,0].invert_yaxis()\n",
" axs[0,0].annotate(text='', xy=(3,w_numpy(u,3)), xytext=(3,0), arrowprops=dict(arrowstyle='fancy'))\n",
" axs[0,0].text(3.1,w_numpy(u,3),'$u_0$')\n",
" axs[0,0].axis('off')\n",
" axs[0,1].axis('off')\n",
" axs[0,1].set_xlim([-0.2,3.2])\n",
" axs[0,1].set_ylim([-0.003,0.01])\n",
" 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'))\n",
" axs[0,1].invert_yaxis()\n",
" x_axis= ['$E_v$','$A_F$','$E_v - A_F$']\n",
" y_axis = [Ev_numpy(u),w_numpy(u,3)*10,Ev_numpy(u)-w_numpy(u,3)*10]\n",
" axs[1,0].bar(x_axis,y_axis,color=('blue','green','orange'))\n",
" axs[1,0].set_ylim([-0.03,0.1])\n",
" axs[1,0].set_yticklabels([])\n",
" axs[1,0].set_yticks([])\n",
" \n",
" u_range=np.linspace(-0.0015,0.01,100)\n",
" axs[1,1].plot(u_range,Ev_numpy(u_range),label='$E_v$',color='blue')\n",
" axs[1,1].plot(u_range,w_numpy(u_range,3)*10,label='$F_A$',color='green')\n",
" axs[1,1].plot(u_range,V_numpy(u_range),label='$E_v - A_F$',color='orange')\n",
" axs[1,1].legend()\n",
" axs[1,1].plot(u,Ev_numpy(u),'o',color='blue')\n",
" axs[1,1].plot(u,w_numpy(u,3)*10,'o',color='green')\n",
" axs[1,1].plot(u,Ev_numpy(u)-w_numpy(u,3)*10,'o',color='orange')\n",
" axs[1,1].set_ylim([-0.03,0.1])\n",
" axs[1,1].set_xlim([-0.0015,0.01])\n",
" axs[1,1].set_xlabel('$u_0$')\n",
" axs[1,1].set_xticks([])\n",
" axs[1,1].set_xticklabels([])\n",
" axs[1,1].set_yticks([])\n",
" plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The graph will appear below in interactive mode:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"tags": [
"thebe-remove-input-init"
]
},
"outputs": [],
"source": [
"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'}),\n",
" trial_function = widgets.ToggleButtons(options=['Polynomial', 'cos', 'cosh']));"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": []
}
],
"metadata": {
"celltoolbar": "Tags",
"kernelspec": {
"display_name": "base",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.11"
}
},
"nbformat": 4,
"nbformat_minor": 2
}