render_ipyvolume

render_ipyvolume class

Reactively render an ipyvolume 3D plot.

Usage Source

render_ipyvolume(
    _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_ipyvolume 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 ipyvolume as ipv

from shinywidgets import render_ipyvolume


@render_ipyvolume
def plot():
    return ipv.quickscatter([0, 1, 2], [0, 1, 0], [1, 0, 1])

The render function may return an ipyvolume.Figure widget (requires pip install 'shinywidgets[ipyvolume]'; ipyvolume 0.6.3 also needs ipython_genutils, which it doesn’t declare, so the extra installs it for you). Both ways of getting one work: the pylab API (return ipv.gcf() after drawing, or the container returned by ipv.quickscatter()/ ipv.gcc(), which is unwrapped to its figure) or direct construction (ipyvolume.Figure, with ipyvolume.widgets.Scatter and friends added to fig.scatters). Either way, call the constructors inside the render function: the pylab functions draw on a module-level “current figure”, so figures created elsewhere can end up shared across sessions. With direct construction, set size_selected/color_selected explicitly on scatters – their trait defaults are 0-d numpy arrays, which don’t JSON-serialize – and set fig.xlim/fig.ylim/fig.zlim, since directly constructed figures default to a [0, 1]^3 axis box with no auto-fit. In a filling layout, the figure’s WebGL canvas is resized to fill its container (and tracks container resizes) unless the figure has an explicit width or height.

Note

Accessing the rendered widget: the render function gains two read-only attributes: .value, the value it most recently returned, and .widget, the rendered ipyvolume.Figure instance.

Responding to user interaction: plot.camera() reads the live camera after every orbit, much like input.my_slider() reads an input. Call it in a reactive function (a @render.* function, @reactive.calc, or @reactive.effect), which then re-runs whenever the camera changes. (reactive_read(plot.widget.camera, "position") is the per-trait alternative, since the camera instance never changes.) For selections, register a callback with plot.widget.on_selection(fn) (selections arrive as custom messages, not trait changes) and set a reactive.value inside it.

Mutating the widget: use .widget to update the rendered figure in place; trait changes on the widget are synced to the browser.

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 (see fill and fillable).

fill : Optional[bool] = None

Whether the output should grow or shrink to fit its parent container. When None (the default), this is True if height is not specified.

fillable : Optional[bool] = None

Whether the output container should fill available space (scrolling its contents on overflow). When None (the default), this is True if height is not specified.

rate_policy : Optional[RatePolicy] = None

How to rate-limit reactive_read() on the widget: "debounce" or "throttle". None (the default) debounces reactive_read() only if rate_delay is given; no accessor on this renderer declares a default.

rate_delay : Optional[float] = None

The rate-limit window in seconds (default 0.25). 0 disables rate limiting.

Examples

import ipyvolume as ipv
import numpy as np
from shiny import App, ui
from shinywidgets import output_widget, render_ipyvolume

app_ui = ui.page_fillable(output_widget("plot"))


def server(input, output, session):
    @render_ipyvolume
    def plot():
        x, y, z = np.random.normal(size=(3, 1000))
        ipv.quickscatter(x, y, z, size=1, marker="sphere")
        return ipv.gcf()


app = App(app_ui, server)

out.read("camera") also works, but returns the raw camera snapshot tuple; prefer camera(), which returns the live Camera object.

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).

Methods

camera() The figure’s live pythreejs.Camera (a PerspectiveCamera by default).

camera()

render_ipyvolume.camera()

The figure’s live pythreejs.Camera (a PerspectiveCamera by default).

Readers are invalidated when its position/quaternion/zoom change (at the end of each orbit) or the camera is replaced. Reading before the first render cancels silently (like req(False)), as does reading while the figure has no camera (fig.camera = None). The returned object is the same mutable instance across reads – copy what you keep. Not rate-limited (the browser syncs once per orbit); the renderer’s rate_policy/rate_delay affect only reactive_read() – no accessor on this renderer declares a default rate limit.