diff --git a/.cspell.json b/.cspell.json index 8a77c687..b8786a53 100644 --- a/.cspell.json +++ b/.cspell.json @@ -152,6 +152,7 @@ "codegen", "codemirror", "colorbar", + "colorscale", "colspan", "combi", "commitlint", @@ -312,6 +313,7 @@ "subslide", "substack", "suptitle", + "surfacecolor", "symplot", "tbody", "thead", diff --git a/docs/conf.py b/docs/conf.py index d3c9d012..4f5d4a1a 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -332,7 +332,6 @@ def print_once(message: str) -> None: "report/002*", "report/003*", "report/005*", - "report/006*", "report/008*", "report/009*", "report/01*", diff --git a/docs/report/006.ipynb b/docs/report/006.ipynb index 33bb5590..405027fb 100644 --- a/docs/report/006.ipynb +++ b/docs/report/006.ipynb @@ -72,7 +72,7 @@ }, "outputs": [], "source": [ - "%pip install -q ipywidgets==8.1.1 matplotlib==3.4.3 numpy==1.19.5 sympy==1.8" + "%pip install -q ipywidgets==8.1.1 matplotlib==3.4.3 numpy==1.19.5 plotly==5.17.0 sympy==1.8" ] }, { @@ -109,6 +109,7 @@ "\n", "import matplotlib.pyplot as plt\n", "import numpy as np\n", + "import plotly.graph_objects as go\n", "import sympy as sp\n", "from IPython.display import display\n", "from ipywidgets import widgets as ipywidgets\n", @@ -457,6 +458,83 @@ "\n", "![ipywidgets interactive output with interactive_output()](https://user-images.githubusercontent.com/29308176/164993430-6f6b906a-dfb5-4c7c-bae5-d9951c02112b.gif)" ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Plotly with `ipywidgets`" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "3D plots with [Plotly](https://plotly.com/python) look a lot nicer and make it possible for the user to pan and zoom the 3D object. As an added bonus, Plotly figures [render as interactive 3D objects](https://myst-nb.readthedocs.io/en/v0.17.2/render/interactive.html#plotly) in the static HTML Sphinx build.\n", + "\n", + "Making 3D Plotly plots interactive with {mod}`ipywidgets` is quite similar to the previous examples with {mod}`matplotlib`. Two recommendations are:\n", + "\n", + "1. Set `continuous_update=False`, because {mod}`plotly` is slower than {mod}`matplotlib` in updating the figure.\n", + "2. Save the camera orientation and update it after calling `Figure.show()`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [ + "hide-input" + ] + }, + "outputs": [], + "source": [ + "plotly_a = ipywidgets.FloatSlider(\n", + " description=f\"${sp.latex(a)}$\",\n", + " value=a_init,\n", + " min=-2,\n", + " max=2,\n", + " step=0.1,\n", + " continuous_update=False,\n", + " readout_format=\".1f\",\n", + ")\n", + "plotly_b = ipywidgets.IntSlider(\n", + " description=f\"${sp.latex(b)}$\",\n", + " value=b_init,\n", + " min=10,\n", + " max=50,\n", + " continuous_update=False,\n", + ")\n", + "plotly_controls = {\"a\": plotly_a, \"b\": plotly_b}\n", + "\n", + "plotly_surface = go.Surface(\n", + " x=X,\n", + " y=Y,\n", + " z=Z,\n", + " surfacecolor=Z,\n", + " colorscale=\"RdBu_r\",\n", + " name=\"Surface\",\n", + ")\n", + "plotly_fig = go.Figure(data=[plotly_surface])\n", + "\n", + "\n", + "def update_plotly(a, b):\n", + " Z = numpy_function(X, Y, a, b)\n", + " camera_orientation = plotly_fig.layout.scene.camera\n", + " plotly_fig.update_traces(\n", + " x=X,\n", + " y=Y,\n", + " z=Z,\n", + " surfacecolor=Z,\n", + " selector=dict(name=\"Surface\"),\n", + " )\n", + " plotly_fig.show()\n", + " plotly_fig.update_layout(scene=dict(camera=camera_orientation))\n", + "\n", + "\n", + "plotly_ui = ipywidgets.HBox([plotly_a, plotly_b])\n", + "plotly_output = ipywidgets.interactive_output(update_plotly, plotly_controls)\n", + "display(plotly_ui, plotly_output)" + ] } ], "metadata": {