render_pyvista
render_pyvista class
Reactively render a pyvista 3D plot.
Usage Source
render_pyvista(
_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_pyvista 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 pyvista as pv
from shinywidgets import render_pyvista
pv.OFF_SCREEN = True
@render_pyvista
def plot():
pl = pv.Plotter()
pl.add_mesh(pv.Sphere())
return plThe render function may return either a pyvista.Plotter (which is coerced to an ipywidget via pyvista’s jupyter_backend="html" export; requires pip install 'shinywidgets[pyvista]') or the exported trame_pyvista.jupyter.EmbeddableWidget itself. In a filling layout, the view fills its container unless an explicit height is given. On a headless server, set pyvista.OFF_SCREEN = True before plotting.
Return the Plotter itself – do not call Plotter.show(). Outside Jupyter, show() ignores jupyter_backend, returns None, and the output renders nothing. If you pre-build the widget (e.g., via trame_pyvista.jupyter.show_trame(pl, mode="html")), pass width="100%", height="100%" or it keeps the plotter’s pixel window_size instead of filling the container.
The export is a self-contained, client-side vtk.js view: camera interaction (rotate/zoom/pan) happens entirely in the browser. The vtk.js runtime ships once per session (shared by every pyvista output in the app); each render then embeds only the exported scene in the widget state, so input-driven re-renders are cheap. Still, very large scenes (millions of cells) produce multi-MB exports, so prefer fewer, larger re-renders for those.
Note
Accessing the rendered widget: the render function gains two read-only attributes: .value, the value it most recently returned, and .widget, the rendered EmbeddableWidget instance. Note that, unlike most other render_* decorators, the widget has no live connection to the plotter.
Responding to user interaction: none: no widget state is synced back to Python, so there is nothing to read with reactive_read(). (For server-driven interactivity, use pyvista’s jupyter_backend="trame" with a trame server embedded via shiny.ui.tags.iframe instead – shinywidgets can’t host trame’s websocket server.)
Mutating the widget: the scene can’t be updated in place via .widget; re-render instead.
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.
Examples
import pyvista as pv
from shiny import App, ui
from shinywidgets import output_widget, render_pyvista
pv.OFF_SCREEN = True
app_ui = ui.page_fillable(output_widget("plot"))
def server(input, output, session):
@render_pyvista
def plot():
pl = pv.Plotter()
pl.add_mesh(pv.Sphere(), show_edges=True)
return pl
app = App(app_ui, server)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).