-
-
Notifications
You must be signed in to change notification settings - Fork 525
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Improvements and Documentation for Panes (#313)
- Loading branch information
1 parent
16f32ea
commit 94e3919
Showing
19 changed files
with
1,032 additions
and
98 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,204 @@ | ||
{ | ||
"cells": [ | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"import panel as pn\n", | ||
"pn.extension('plotly')" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"The ``HoloViews`` pane renders HoloViews plots with the selected or explicitly specified backend. It has native support for the regular HoloViews widgets to explore the key dimensions of a ``HoloMap`` or ``DynamicMap``, but is also more flexible since it allows customizing the choice of widget and their position relative to the plot.\n", | ||
"\n", | ||
"#### Parameters:\n", | ||
"\n", | ||
"For layout and styling related parameters see the [layout user guide](../../user_guide/Layout.ipynb).\n", | ||
"\n", | ||
"* **``backend``** (str): Any of the support HoloViews backends ('bokeh', 'matplotlib' or 'plotly')\n", | ||
"* **``object``** (object): The HoloViews object being displayed\n", | ||
"* **``widget_type``** (str): Whether to generate individual widgets for each dimension or on global scrubber.\n", | ||
"* **``widgets``** (dict): A mapping from dimension name to a widget class, instance or dictionary of overrides to modify the default widgets.\n", | ||
"\n", | ||
"##### Display\n", | ||
"\n", | ||
"* **``default_layout``** (pn.layout.Panel, default=Row): Layout to wrap the plot and widgets in\n", | ||
"\n", | ||
"___" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"When creating any ``HoloViews`` objects the panel function will automatically convert it into a displayable panel, while keeping all interactive features:" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"import numpy as np\n", | ||
"import holoviews as hv\n", | ||
"\n", | ||
"box = hv.BoxWhisker((np.random.randint(0, 10, 100), np.random.randn(100)), 'Group').sort()\n", | ||
"\n", | ||
"hv_layout = pn.panel(box)\n", | ||
"hv_layout" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"By setting the panes ``object`` the plot can be updated like all other Pane objects:" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"hv_layout.object = hv.Violin(box).opts(responsive=True, violin_color='Group', cmap='Category20')" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"### Widgets\n", | ||
"\n", | ||
"HoloViews natively renders plots with widgets if a HoloMap or DynamicMap declares any key dimensions. Unlike the ``interact`` functionality in panel this efficiently updates just the data inside a plot instead of replacing it entirely. By calling ``pn.panel`` on the DynamicMap will return ``Row`` layout (configurable via the ``default_layout`` option), this is equivalent to calling ``pn.pane.HoloViews(dmap).layout``:" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"import pandas as pd\n", | ||
"import hvplot.pandas\n", | ||
"\n", | ||
"def sine(frequency=1.0, amplitude=1.0, function='sin'):\n", | ||
" xs = np.arange(200)/200*20.0\n", | ||
" ys = amplitude*getattr(np, function)(frequency*xs)\n", | ||
" return pd.DataFrame(dict(y=ys), index=xs).hvplot()\n", | ||
"\n", | ||
"dmap = hv.DynamicMap(sine, kdims=['frequency', 'amplitude', 'function']).redim.range(\n", | ||
" frequency=(0.1, 10), amplitude=(1, 10)).redim.values(function=['sin', 'cos', 'tan'])\n", | ||
"\n", | ||
"hv_panel = pn.panel(dmap)\n", | ||
"\n", | ||
"hv_panel.pprint()" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"We can see the widgets generated for each of the dimensions and arrange them any way we like, e.g. by unpacking them into a ``Row``:" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"widgets = hv_panel[1]\n", | ||
"\n", | ||
"pn.Column(\n", | ||
" pn.Row(*widgets),\n", | ||
" hv_panel[0])" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"#### Customizing widgets\n", | ||
"\n", | ||
"As we saw above, the HoloViews pane will automatically try to generate appropriate widgets for the type of data usually defaulting to ``DiscreteSlider`` and ``Select`` widgets. This behavior can be modified by providing a dictionary of ``widgets`` by dimension name, the values of this dictionary can override the default widget in one of three ways:\n", | ||
"\n", | ||
"* Supplying a ``Widget`` instance\n", | ||
"* Supplying a compatible ``Widget`` type\n", | ||
"* Supplying a dictionary of ``Widget`` parameter overrides\n", | ||
" \n", | ||
"A ``Widget`` instances will be used as they are supplied and are expected to provide values matching compatible with the values defined on HoloMap/DynamicMap. Similarly if a ``Widget`` type is supplied it should be discrete if the parameter space defines a discrete set of values, if the defined parameter space is continuous on the other hand it may supply any valid value.\n", | ||
"\n", | ||
"\n", | ||
"In the example below we override the 'amplitude' dimension with an explicit ``Widget`` instance, the 'function' dimension is overridden with a RadioButtonGroup letting us toggle between the different functions and lastly we override the 'value' parameter on the 'frequency', changing the initial value:" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"pn.pane.HoloViews(dmap, widgets={\n", | ||
" 'amplitude': pn.widgets.LiteralInput(value=1., type=(float, int)),\n", | ||
" 'function': pn.widgets.RadioButtonGroup,\n", | ||
" 'frequency': {'value': 5}\n", | ||
"}).layout" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"### Switching backends\n", | ||
"\n", | ||
"The ``HoloViews`` pane will default to the bokeh backend if no backend has been loaded. However" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"import holoviews.plotting.mpl\n", | ||
"import holoviews.plotting.plotly\n", | ||
"\n", | ||
"hv_pane = pn.pane.HoloViews(dmap, backend='matplotlib')\n", | ||
"hv_pane" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"The ``backend`` like all other parameters can be modified after the fact, to demonstrate we can we can set up a select widget to toggle between backends:" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"backend_select = pn.widgets.RadioButtonGroup(name='Backend Selector:', options=['bokeh', 'matplotlib', 'plotly'])\n", | ||
"backend_select.link(hv_pane[0], value='backend')\n", | ||
"backend_select" | ||
] | ||
} | ||
], | ||
"metadata": { | ||
"language_info": { | ||
"name": "python", | ||
"pygments_lexer": "ipython3" | ||
} | ||
}, | ||
"nbformat": 4, | ||
"nbformat_minor": 2 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,166 @@ | ||
{ | ||
"cells": [ | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"import panel as pn\n", | ||
"pn.extension('plotly')" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"The ``Plotly`` pane renders Plotly plots inside a panel. It optimizes the plot rendering by using binary serialization for any array data found on the Plotly object, providing efficient updates. Note that to use the Plotly pane in the notebook the extension has to be loaded with 'plotly' as an argument to ensure that Plotly.js is initialized.\n", | ||
"\n", | ||
"#### Parameters:\n", | ||
"\n", | ||
"For layout and styling related parameters see the [layout user guide](../../user_guide/Layout.ipynb).\n", | ||
"\n", | ||
"* **``object``** (object): The Plotly figure being displayed\n", | ||
"\n", | ||
"___" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"As with most other types ``Panel`` will automatically convert a plotly figure to a ``Plotly`` pane if passed to the ``pn.panel`` function or a panel layout, but can be constructed directly using the ``pn.pane.Plotly`` constructor:" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"import numpy as np\n", | ||
"import plotly.graph_objs as go\n", | ||
"\n", | ||
"xx = np.linspace(-3.5, 3.5, 100)\n", | ||
"yy = np.linspace(-3.5, 3.5, 100)\n", | ||
"x, y = np.meshgrid(xx, yy)\n", | ||
"z = np.exp(-(x-1)**2-y**2)-(x**3+y**4-x/5)*np.exp(-(x**2+y**2))\n", | ||
"\n", | ||
"surface = go.Surface(z=z)\n", | ||
"layout = go.Layout(\n", | ||
" title='Plotly 3D Plot',\n", | ||
" autosize=False,\n", | ||
" width=500,\n", | ||
" height=500,\n", | ||
" margin=dict(t=50, b=50, r=50, l=50)\n", | ||
")\n", | ||
"fig = dict(data=[surface], layout=layout)\n", | ||
"\n", | ||
"plotly_pane = pn.pane.Plotly(fig)\n", | ||
"plotly_pane" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"Once created the plot can be updated by modifying the Plotly traces and then triggering an update by setting or triggering an event on the pane ``object``. Note that this only works if the ``Figure`` is defined as a dictionary since Plotly will copy make copies of the traces, which means that modifying them inplace has no effect. Modifying an array will just send the array using a binary protocol leading to fast and efficient updates." | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"surface.z = np.sin(z+1)\n", | ||
"plotly_pane.object = fig" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"Similarly modifying the plot ``layout`` will also only modify the layout leaving the traces unaffected." | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"fig['layout']['width'] = 800\n", | ||
"\n", | ||
"plotly_pane.object = fig" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"The Plotly pane supports layouts and subplots of arbitrary complexity, allowing even deeply nested Plotly figures to be displayed:" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"from plotly import tools\n", | ||
"\n", | ||
"heatmap = go.Heatmap(\n", | ||
" z=[[1, 20, 30],\n", | ||
" [20, 1, 60],\n", | ||
" [30, 60, 1]],\n", | ||
" showscale=False)\n", | ||
"\n", | ||
"y0 = np.random.randn(50)\n", | ||
"y1 = np.random.randn(50)+1\n", | ||
"\n", | ||
"box_1 = go.Box(y=y0)\n", | ||
"box_2 = go.Box(y=y1)\n", | ||
"data = [heatmap, box_1, box_2]\n", | ||
"\n", | ||
"fig = tools.make_subplots(rows=2, cols=2, specs=[[{}, {}], [{'colspan': 2}, None]],\n", | ||
" subplot_titles=('First Subplot','Second Subplot', 'Third Subplot'))\n", | ||
"\n", | ||
"fig.append_trace(box_1, 1, 1)\n", | ||
"fig.append_trace(box_2, 1, 2)\n", | ||
"fig.append_trace(heatmap, 2, 1)\n", | ||
"\n", | ||
"fig['layout'].update(height=600, width=600, title='i <3 subplots')\n", | ||
"fig = fig.to_dict()\n", | ||
"\n", | ||
"subplot_panel = pn.pane.Plotly(fig)\n", | ||
"subplot_panel" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"Just like in the single subplot case we can modify just certain aspect of a plot and then trigger an update, e.g. here we replace the overall title text:" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"fig['layout']['title']['text'] = 'i <3 updating subplots'\n", | ||
"subplot_panel.object = fig" | ||
] | ||
} | ||
], | ||
"metadata": { | ||
"language_info": { | ||
"name": "python", | ||
"pygments_lexer": "ipython3" | ||
} | ||
}, | ||
"nbformat": 4, | ||
"nbformat_minor": 2 | ||
} |
Oops, something went wrong.