diff --git a/examples/reference/panes/HoloViews.ipynb b/examples/reference/panes/HoloViews.ipynb
index 1b423463b4..a2757fe5df 100644
--- a/examples/reference/panes/HoloViews.ipynb
+++ b/examples/reference/panes/HoloViews.ipynb
@@ -6,33 +6,62 @@
"metadata": {},
"outputs": [],
"source": [
+ "import holoviews as hv\n",
"import panel as pn\n",
- "pn.extension('plotly')"
+ "\n",
+ "hv.extension(\"bokeh\", \"plotly\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
- "The ``HoloViews`` pane renders HoloViews plots with one of the plotting backends supported by HoloViews. It supports the regular HoloViews widgets for exploring the key dimensions of a ``HoloMap`` or ``DynamicMap``, but is more flexible than the native HoloViews widgets since it also allows customizing widget types and their position relative to the plot.\n",
+ "[HoloViews](https://holoviews.org/) is a popular and powerful data visualization library supporting many data and plotting *backends*.\n",
+ "\n",
+ "[hvPlot](https://hvplot.holoviz.org/index.html) (quick viz) and [GeoViews](https://holoviz.org/assets/geoviews.png) (spatial viz) are built on top of HoloViews and produces `HoloViews` objects.\n",
+ "\n",
+ "**Panel, HoloViews, hvPlot and GeoViews are all members of the [HoloViz](https://holoviz.org) ecosystem and you can expect them to work perfectly together**.\n",
+ "\n",
+ "
\n",
+ "\n",
+ "In this reference notebook we will assume a basic level of understanding of HoloViews and optionally hvPlot or Geoviews if you want to use them with Panel.\n",
+ "\n",
+ "---\n",
+ "\n",
+ "The `HoloViews` pane renders [HoloViews](https://holoviews.org/) objects with one of the *plotting backends* supported by HoloViews. This includes objects produced by [hvPlot](https://hvplot.holoviz.org/index.html) and [GeoViews](https://holoviz.org/assets/geoviews.png).\n",
+ "\n",
+ "The `HoloViews` pane supports displaying interactive [`HoloMap`](https://holoviews.org/reference/containers/bokeh/HoloMap.html) and [`DynamicMap`](https://holoviews.org/reference/containers/bokeh/DynamicMap.html) objects containing widgets. The `HoloViews` pane even allows customizing the widget types and their position relative to the plot.\n",
"\n",
"#### Parameters:\n",
"\n",
"For details on other options for customizing the component see the [layout](../../how_to/layout/index.md) and [styling](../../how_to/styling/index.md) how-to guides.\n",
"\n",
- "* **``backend``** (str): Any of the supported HoloViews backends ('bokeh', 'matplotlib', or 'plotly')\n",
- "* **``center``** (boolean, default=False): Whether to center the plot\n",
- "* **``linked_axes``** (boolean, default=True): Whether to link axes across plots in a panel layout\n",
- "* **``object``** (object): The HoloViews object being displayed\n",
- "* **``widget_location``** (str): Where to lay out the widget relative to the plot \n",
- "* **``widget_layout``** (ListPanel type): The object to lay the widgets out in, one of ``Row``, ``Column`` or ``WidgetBox``\n",
- "* **``widget_type``** (str): Whether to generate individual widgets for each dimension, or to use a global linear scrubber with dimensions concatenated.\n",
- "* **``widgets``** (dict): A mapping from dimension name to a widget class, instance, or dictionary of overrides to modify the default widgets.\n",
+ "The main argument is the `object` parameter\n",
"\n",
- "##### Display\n",
+ "* **`object`** (object): The HoloViews object being displayed\n",
"\n",
- "* **``default_layout``** (pn.layout.Panel, default=Row): Layout to wrap the plot and widgets in\n",
+ "You can control the way the `object` is rendered and sharing axes with other plots via the parameters\n",
"\n",
+ "* **`backend`** (str): Any of the supported HoloViews backends ('bokeh', 'matplotlib', or 'plotly'). If none is specified defaults to the active holoviews renderer. This is by default 'bokeh'.\n",
+ "* **`linked_axes`** (boolean, default=True): Whether to link axes across plots in a panel layout\n",
+ "* **`format`** (str, default='png'): The output format to use when plotting a Matplotlib plot. \n",
+ "* **`renderer`**: Explicit [HoloViews Renderer](https://holoviews.org/user_guide/Plots_and_Renderers.html#renderers) instance to use for rendering the HoloViews plot. Overrides the` backend` parameter.\n",
+ "* **`theme` (str, Theme)**: [Bokeh theme](https://docs.bokeh.org/en/latest/docs/reference/themes.html) to apply to the HoloViews plot.\n",
+ "\n",
+ "You can access the layout and (optional) widgets via\n",
+ "\n",
+ "* **`layout`** (pn.layout.Panel): The layout containing the plot pane and (optionally) the `widget_box` layout.\n",
+ "* **`widget_box`** (ListPanel): The layout containing the widgets\n",
+ "\n",
+ "##### Layout and Widget Parameters\n",
+ "\n",
+ "The below parameters are used to control the layout and widgets when using `pn.panel` or `pn.pane.HoloViews(...).layout`.\n",
+ "\n",
+ "* **`center`** (boolean, default=False): Whether to center the plot or not.\n",
+ "* **`widgets`** (dict, argument): A mapping from dimension name to a widget class, instance, or dictionary of overrides to modify the default widgets. Provided as an argument.\n",
+ "* **`widget_location`** (str): Where to lay out the widget relative to the plot \n",
+ "* **`widget_layout`** (ListPanel): The object to lay the widgets out in, one of `Row`, `Column` or `WidgetBox`\n",
+ "* **`widget_type`** (str): Whether to generate individual widgets for each dimension, or to use a global linear scrubber with dimensions concatenated.\n",
"___"
]
},
@@ -40,7 +69,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "The `panel` function will automatically convert any ``HoloViews`` object into a displayable panel, while keeping all of its interactive features:"
+ "The `pn.pane.HoloViews` pane will automatically convert any ``HoloViews`` object into a displayable panel, while keeping all of its interactive features:"
]
},
{
@@ -50,12 +79,12 @@
"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",
+ "data = {\"group\": np.random.randint(0, 10, 100), \"value\": np.random.randn(100)}\n",
+ "box = hv.Scatter(data, kdims=\"group\", vdims=\"value\").sort().opts()\n",
"\n",
- "hv_layout = pn.panel(box)\n",
- "hv_layout"
+ "hv_pane = pn.pane.HoloViews(box, height=300, sizing_mode=\"stretch_width\")\n",
+ "hv_pane"
]
},
{
@@ -71,16 +100,37 @@
"metadata": {},
"outputs": [],
"source": [
- "hv_layout.object = hv.Violin(box).opts(violin_color='Group', cmap='Category20')"
+ "hv_pane.object = hv.Violin(box).opts(violin_color='Group', responsive=True, height=300)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "You can display [hvPlot](https://hvplot.holoviz.org/) (and [GeoViews](https://geoviews.org/)) objects too because they are `HoloViews` objects."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import pandas as pd\n",
+ "import hvplot.pandas\n",
+ "\n",
+ "df = pd.DataFrame(data)\n",
+ "plot = df.hvplot.box(by=\"group\", y=\"value\", responsive=True, height=300)\n",
+ "pn.pane.HoloViews(plot, height=300, sizing_mode=\"stretch_width\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
- "### Widgets\n",
+ "You can also display [`HoloMap`](https://holoviews.org/reference/containers/bokeh/HoloMap.html) and [`DynamicMap`](https://holoviews.org/reference/containers/bokeh/DynamicMap.html) objects.\n",
"\n",
- "HoloViews natively renders plots with widgets if a HoloMap or DynamicMap declares any key dimensions. Unlike Panel's ``interact`` functionality, this approach efficiently updates just the data inside a plot instead of replacing it entirely. Calling ``pn.panel`` on the DynamicMap will return a ``Row`` layout (configurable via the ``default_layout`` option), which is equivalent to calling ``pn.pane.HoloViews(dmap).layout``:"
+ "[HoloViews](https://holoviews.org/) (the framework) natively renders plots with widgets if a [`HoloMap`](https://holoviews.org/reference/containers/bokeh/HoloMap.html) or [DynamicMap](https://holoviews.org/reference/containers/bokeh/DynamicMap.html) declares any *key dimensions*. This approach efficiently updates just the data inside a plot instead of replacing the plot entirely."
]
},
{
@@ -96,21 +146,61 @@
"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",
+ " return pd.DataFrame(dict(y=ys), index=xs).hvplot(height=250, responsive=True)\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",
+ "hv_panel = pn.pane.HoloViews(dmap)\n",
+ "hv_panel"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The `layout` parameter contains the `HoloViews` pane and the `widget_box`."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "print(hv_panel.layout, \"\\n\\n\", hv_panel.widget_box)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Backend\n",
+ "\n",
+ "The ``HoloViews`` pane will default to the 'bokeh' plotting backend if no backend has been loaded via `holoviews`, but you can change the backend to any of the 'bokeh', 'matplotlib' and 'plotly' backends as needed.\n",
"\n",
- "print(hv_panel)"
+ "### Bokeh\n",
+ "\n",
+ "Bokeh is the default plotting backend, so normally you don't have to specify it. But lets do it here to show how it works."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "plot = df.hvplot.scatter(x=\"group\", y=\"value\")\n",
+ "pn.pane.HoloViews(plot, backend='bokeh', sizing_mode=\"stretch_width\", height=300)"
]
},
{
"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``:"
+ "### Matplotlib\n",
+ "\n",
+ "The Matplotlib backend allows generating figures for print and publication. If you want to allow for responsive sizing you can set `format='svg'` and then use the standard responsive `sizing_mode` settings:"
]
},
{
@@ -119,18 +209,245 @@
"metadata": {},
"outputs": [],
"source": [
- "widgets = hv_panel[1]\n",
+ "hvplot.extension(\"matplotlib\")\n",
+ "\n",
+ "plot = df.hvplot.scatter(x=\"group\", y=\"value\")\n",
+ "\n",
+ "pn.pane.HoloViews(plot, backend='matplotlib', sizing_mode=\"stretch_both\", format='svg', center=False)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Please note that in a *server context* you might have to set the matplotlib backend like below depending on your setup.\n",
+ "\n",
+ "```python\n",
+ "import matplotlib\n",
+ "matplotlib.use('agg')\n",
+ "```"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Plotly\n",
+ "\n",
+ "To use the 'plotly' plotting backend you will need to run `hv.extension(\"plotly\")` to configure the 'plotly' backend.\n",
+ "\n",
+ "If you are using `hvPlot` you can use `hvplot.extension(\"plotly\")` instead."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "hvplot.extension(\"plotly\")\n",
+ "\n",
+ "plot = df.hvplot.scatter(x=\"group\", y=\"value\", height=300, responsive=True)\n",
+ "\n",
+ "pn.pane.HoloViews(plot, backend='plotly', height=300)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Lets change the default backend back to 'bokeh'"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "hvplot.extension(\"bokeh\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Dynamic\n",
+ "\n",
+ "You can change the plotting backend dynamically via a widget too."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "plot = df.hvplot.scatter(x=\"group\", y=\"value\", height=300, responsive=True, title=\"Try changing the backend\")\n",
+ "\n",
+ "plot_pane = pn.pane.HoloViews(plot, backend='bokeh', sizing_mode=\"stretch_width\", height=300)\n",
+ "\n",
+ "widget = pn.widgets.RadioButtonGroup.from_param(\n",
+ " plot_pane.param.backend, button_type=\"primary\", button_style=\"outline\"\n",
+ ")\n",
+ "\n",
+ "pn.Column(widget, plot_pane)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Linked Axes\n",
+ "\n",
+ "By default the axes of plots with shared key or value dimensions are linked. You can remove the link by setting the `linked_axes` parameter to `False`."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "not_linked_plot = df.hvplot.scatter(x=\"group\", y=\"value\", responsive=True, title=\"Not Linked Axes\").opts(active_tools=['box_zoom'])\n",
+ "linked_plot = df.hvplot.scatter(x=\"group\", y=\"value\", responsive=True, title=\"Linked Axes\").opts(active_tools=['box_zoom'])\n",
+ "\n",
"\n",
"pn.Column(\n",
- " pn.Row(*widgets),\n",
- " hv_panel[0])"
+ " pn.pane.HoloViews(not_linked_plot, backend='bokeh', sizing_mode=\"stretch_width\", height=200, linked_axes=False),\n",
+ " pn.pane.HoloViews(linked_plot, backend='bokeh', sizing_mode=\"stretch_width\", height=200),\n",
+ " pn.pane.HoloViews(linked_plot, backend='bokeh', sizing_mode=\"stretch_width\", height=200),\n",
+ ")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
- "However, more conveniently the HoloViews pane offers options to lay out the plot and widgets in a number of preconfigured arrangements using the ``center`` and ``widget_location`` parameters."
+ "## Theme\n",
+ "\n",
+ "You can change the `theme`."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "plot = df.hvplot.scatter(x=\"group\", y=\"value\", height=300, responsive=True)\n",
+ "pn.pane.HoloViews(plot, height=300, theme=\"night_sky\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Layout and Widget Parameters\n",
+ "\n",
+ "Please note that above we used the `Holoviews` pane to display HoloViews objects.\n",
+ "\n",
+ "Below we will be using `pn.panel(...)` instead. `pn.panel(...)` is the same as `pn.pane.HoloViews(...).layout`\n",
+ "\n",
+ "### Center\n",
+ "\n",
+ "You can center your plots via the `center` parameter."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "plot = df.hvplot.scatter(x=\"group\", y=\"value\", height=100, width=400)\n",
+ "\n",
+ "pn.Column(\n",
+ " \"`center=True`, `sizing_mode='fixed'`\",\n",
+ " pn.panel(plot, center=True, sizing_mode=\"fixed\"),\n",
+ " \"`center=True`, `sizing_mode='stretch_width'`\",\n",
+ " pn.panel(plot, center=True, sizing_mode=\"stretch_width\"),\n",
+ " \"`center=False`, `sizing_mode='fixed'`\",\n",
+ " pn.panel(plot),\n",
+ " \"`center=False`, `sizing_mode='stretch_width'`\",\n",
+ " pn.panel(plot, sizing_mode=\"stretch_width\"),\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### HoloMap and DynamicMap Widgets\n",
+ "\n",
+ "[HoloViews](https://holoviews.org/) (the framework) natively renders plots with widgets if a [`HoloMap`](https://holoviews.org/reference/containers/bokeh/HoloMap.html) or [DynamicMap](https://holoviews.org/reference/containers/bokeh/DynamicMap.html) declares any *key dimensions*. This approach efficiently updates just the data inside a plot instead of replacing it entirely.\n",
+ "\n",
+ "When rendering a `HoloMap` or `DynamicMap` object with `pn.panel`, then the `pn.pane.HoloViews(...).layout` will be displayed. Not `pn.pane.HoloViews(...)`."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import pandas as pd\n",
+ "import hvplot.pandas\n",
+ "import holoviews.plotting.bokeh\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(height=250, responsive=True)\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",
+ "dmap_panel = pn.panel(dmap, height=400, sizing_mode=\"stretch_width\")\n",
+ "dmap_panel"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Lets inspect the `dmap_panel`"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "print(dmap_panel)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Lets try to modify the `FloatSlider` before we render it:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "float_slider = hv_panel[1][0]\n",
+ "\n",
+ "float_slider.styles = {'border': '2px solid red', 'padding': '10px', 'border-radius': '5px'}\n",
+ "\n",
+ "float_slider"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Lets try to reorganize the layout"
]
},
{
@@ -139,24 +456,64 @@
"metadata": {},
"outputs": [],
"source": [
- "pn.panel(dmap, center=True, widget_location='right_bottom')"
+ "widgets = hv_panel[1]\n",
+ "\n",
+ "pn.Row(pn.Column(*widgets), hv_panel[0])"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The widgets in the `.layout` can be customized via the `widgets`, `widget_location`, `widget_layout` and `widget_type` parameters."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
+ "#### `widget_location`\n",
+ "\n",
+ "The HoloViews pane offers options to lay out the plot and widgets in a number of preconfigured arrangements using the ``center`` and ``widget_location`` parameters.\n",
+ "\n",
"The ``widget_location`` parameter accepts all of the following options:\n",
" \n",
" ['left', 'bottom', 'right', 'top', 'top_left', 'top_right', 'bottom_left',\n",
" 'bottom_right', 'left_top', 'left_bottom', 'right_top', 'right_bottom']"
]
},
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "pn.panel(dmap, center=True, widget_location='left')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "#### `widget_layout`\n",
+ "\n",
+ "Lets change the widget layout to a `Row`."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "pn.panel(dmap, center=True, widget_layout=pn.Row, widget_location='top_left')"
+ ]
+ },
{
"cell_type": "markdown",
"metadata": {},
"source": [
- "#### Customizing widgets\n",
+ "#### `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",
@@ -179,16 +536,20 @@
" 'amplitude': pn.widgets.LiteralInput(value=1., type=(float, int)),\n",
" 'function': pn.widgets.RadioButtonGroup,\n",
" 'frequency': {'value': 5}\n",
- "}).layout"
+ "}).layout\n",
+ "\n",
+ "hv_panel"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
- "### Switching backends\n",
+ "### Bound Functions and DynamicMaps\n",
+ "\n",
+ "When working with reactive references and functions (such as those returned by `.bind`, `.depends` or `.rx`) that return HoloViews elements and overlays it is recommended that you wrap them in a `DynamicMap`. This allows us to construct plots that depend on the values of widgets or other parameters or expressions in a straightforward way. Note that this differs from auto-generating widgets from dimensions as we've seen so far. Internally HoloViews will inspect the function and create a so called [`Stream`](https://holoviews.org/user_guide/Responding_to_Events.html) that updates the `DynamicMap` when the dependencies change. This also means that any widget you depend on will not appear alongside the other widgets, derived from a dimension.\n",
"\n",
- "The ``HoloViews`` pane will default to the Bokeh backend if no backend has been loaded, but you can override the backend as needed."
+ "Instead of re-rendering the entire plot each time a parameter changes this will delegate the update to HoloViews and update the data inplace:"
]
},
{
@@ -197,36 +558,22 @@
"metadata": {},
"outputs": [],
"source": [
- "import holoviews.plotting.mpl\n",
- "import holoviews.plotting.plotly\n",
+ "def get_plot(n):\n",
+ " return hv.Scatter(range(n), kdims=\"x\", vdims=\"y\").opts(\n",
+ " height=300, responsive=True, xlim=(0, 100), ylim=(0, 100)\n",
+ " )\n",
"\n",
- "hv_pane = pn.pane.HoloViews(dmap, backend='matplotlib')\n",
- "hv_pane"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Please note that in a *server context* you will also have to set the matplotlib backend like below\n",
+ "widget = pn.widgets.IntSlider(value=50, start=1, end=100, name=\"Number of points\")\n",
+ "plot = hv.DynamicMap(pn.bind(get_plot, widget))\n",
"\n",
- "```python\n",
- "import matplotlib\n",
- "matplotlib.use('agg')\n",
- "```\n",
- "\n",
- "The ``backend``, like all other parameters, can be modified after the fact. To demonstrate, we can set up a select widget to toggle between backends for the above plot:"
+ "pn.Column(widget, plot)"
]
},
{
- "cell_type": "code",
- "execution_count": null,
+ "cell_type": "markdown",
"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"
+ "Please note the bound function may not return `Layout`s, `NdLayout`s, `GridSpace`s, `DynamicMap`s or `HoloMaps` as these are not supported by the `DynamicMap`."
]
}
],
diff --git a/panel/pane/holoviews.py b/panel/pane/holoviews.py
index 855de13082..368ac6eb82 100644
--- a/panel/pane/holoviews.py
+++ b/panel/pane/holoviews.py
@@ -1,5 +1,6 @@
"""
HoloViews integration for Panel including a Pane to render HoloViews
+
objects and their widgets and support for Links
"""
from __future__ import annotations
@@ -52,13 +53,16 @@ class HoloViews(PaneBase):
"""
backend = param.ObjectSelector(
- default=None, objects=['bokeh', 'plotly', 'matplotlib'], doc="""
+ default=None, objects=['bokeh', 'matplotlib', 'plotly'], doc="""
The HoloViews backend used to render the plot (if None defaults
to the currently selected renderer).""")
center = param.Boolean(default=False, doc="""
Whether to center the plot.""")
+ format = param.Selector(default='png', objects=['png', 'svg'], doc="""
+ The format to render Matplotlib plots with.""")
+
linked_axes = param.Boolean(default=True, doc="""
Whether to link the axes of bokeh plots inside this pane
across a panel layout.""")
@@ -116,10 +120,10 @@ class HoloViews(PaneBase):
'backend': None, 'center': None, 'linked_axes': None,
'renderer': None, 'theme': None, 'widgets': None,
'widget_layout': None, 'widget_location': None,
- 'widget_type': None
+ 'widget_type': None, 'format': None
}
- _rerender_params = ['object', 'backend']
+ _rerender_params = ['object', 'backend', 'format']
_skip_layoutable = (
'background', 'css_classes', 'margin', 'name', 'sizing_mode',
@@ -276,8 +280,10 @@ def _update_widgets(self, *events):
if self.object is None:
widgets, values = [], []
else:
+ direction = getattr(self.widget_layout, '_direction', 'vertical')
widgets, values = self.widgets_from_dimensions(
- self.object, self.widgets, self.widget_type)
+ self.object, self.widgets, self.widget_type, direction
+ )
self._values = values
# Clean up anything models listening to the previous widgets
@@ -475,6 +481,7 @@ def _get_pane(self, backend, state, **kwargs):
if isinstance(pane_type, type):
if issubclass(pane_type, Matplotlib):
kwargs['tight'] = True
+ kwargs['format'] = self.format
if issubclass(pane_type, Bokeh):
kwargs['autodispatch'] = False
return pane_type(state, **kwargs)
@@ -560,7 +567,7 @@ def jslink(self, target, code=None, args=None, bidirectional=False, **links):
jslink.__doc__ = PaneBase.jslink.__doc__
@classmethod
- def widgets_from_dimensions(cls, object, widget_types=None, widgets_type='individual'):
+ def widgets_from_dimensions(cls, object, widget_types=None, widgets_type='individual', direction='vertical'):
from holoviews.core import Dimension, DynamicMap
from holoviews.core.options import SkipRendering
from holoviews.core.traversal import unique_dimkeys
@@ -607,7 +614,7 @@ def widgets_from_dimensions(cls, object, widget_types=None, widgets_type='indivi
for i, dim in enumerate(dims):
widget_type, widget, widget_kwargs = None, None, {}
- if widgets_type == 'individual':
+ if widgets_type == 'individual' and direction == 'vertical':
if i == 0 and i == (len(dims)-1):
margin = (20, 20, 20, 20)
elif i == 0:
@@ -681,6 +688,7 @@ def widgets_from_dimensions(cls, object, widget_types=None, widgets_type='indivi
**widget_kwargs)
widget = widget_type(**widget_kwargs)
if widget is not None:
+ widget.param.name.constant = True
widgets.append(widget)
if widgets_type == 'scrubber':
widgets = [Player(length=nframes, width=550)]