{ "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 }