render_holoviews
render_holoviews class
Reactively render a holoviews, hvPlot, or geoviews object.
Usage Source
render_holoviews(
_fn: Optional[ValueFn[ValueT]] = None,
*,
width: Optional[str] = None,
height: Optional[str] = None,
fill: Optional[bool] = None,
fillable: Optional[bool] = None,
rate_policy: Optional[RatePolicy] = None,
rate_delay: Optional[float] = None,
)@render_holoviews is a decorator that creates a render function – a function that returns the plot to display and re-runs when the reactive values it reads change:
import holoviews as hv
from shinywidgets import render_holoviews
@render_holoviews
def curve():
return hv.Curve([1, 2, 3])The render function may return either a holoviews/hvplot/geoviews object (which is rendered through panel; requires pip install 'shinywidgets[holoviews]') or the underlying jupyter_bokeh.BokehModel widget. For geoviews objects, also pip install geoviews 'cartopy<0.26' (geoviews 1.15/1.16 breaks with cartopy 0.26, and cartopy 0.25 has no Python 3.14 wheels). If you call .opts() without importing hvplot, call hv.extension("bokeh") first. Plots rasterized with datashader are supported too (e.g., hvPlot’s rasterize=True or holoviews’ rasterize() operation; requires pip install datashader): they re-aggregate the data on the server for the visible region whenever the user zooms or pans. Build such plots inside the render function rather than once at module level: holoviews links every display of the same object, so a shared plot would apply one user’s zoom to every session’s plot. Also note that re-aggregation runs on the server’s event loop, so a slow aggregation delays every session served by that process.
Linked streams (e.g., holoviews.streams.Tap or BoundsXY) run their callbacks outside Shiny’s reactive cycle: with shiny < 1.9, the updates they trigger only reach the browser after the next unrelated input. And because .opts() styles shared objects such as gv.tile_sources.OSM or gv.feature.coastline in place, use .opts(..., clone=True) on them, or one session’s styling will show up in every session.
HoloViews and hvPlot plots have a fixed size by default (and get clipped by a smaller container). To make a plot fill its output, pass responsive=True (e.g., df.hvplot.line(..., responsive=True) or .opts(responsive=True)), optionally with a fixed height. If you give the output a fixed height, set fillable=True too (e.g., output_widget("map", height="400px", fillable=True)); otherwise a responsive plot collapses to a thin strip.
Note
Accessing the rendered widget: the render function gains two read-only attributes: .value, the holoviews/hvplot object it most recently returned, and .widget, the rendered BokehModel instance.
Responding to user interaction: HoloViews’ own Python-side interactivity (e.g., widgets for a HoloMap or DynamicMap, streams such as Selection1D or BoundsXY, and hv.link_selections) works without a Bokeh server. To react to it in Shiny, set a reactive.value from a stream subscriber or a .param.watch() callback (e.g., links.param.watch(lambda e: selection.set(e.new), "selection_expr")) instead of using reactive_read().
Mutating the widget: to update a plot without re-rendering, drive a DynamicMap with a stream (e.g., call stream.event(...) or pipe.send(...) in a reactive.effect).
Create streams and link_selections instances per session (e.g., in the server function, or anywhere in a Shiny Express app), not at the top level of a Shiny Core app, where every visitor would share them (and see each other’s selections).
Parameters
width : Optional[str] = None-
A CSS length unit (e.g.,
"400px"or"100%") for the output’s width. height : Optional[str] = None-
A CSS length unit for the output’s height. When
None(the default), the output is designed to fill the height of its parent container (seefillandfillable). fill : Optional[bool] = None-
Whether the output should grow or shrink to fit its parent container. When
None(the default), this isTrueifheightis not specified. fillable : Optional[bool] = None-
Whether the output container should fill available space (scrolling its contents on overflow). When
None(the default), this isTrueifheightis not specified.
See also
output_widget(): in Shiny Core, the UI needs this to hold the output (Shiny Express displays it where the render function is defined).