render_pythreejs
render_pythreejs class
Reactively render a pythreejs 3D scene.
Usage Source
render_pythreejs(
_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_pythreejs is a decorator that creates a render function – a function that returns the scene to display and re-runs when the reactive values it reads change:
import pythreejs as p3
from shinywidgets import render_pythreejs
@render_pythreejs
def scene():
mesh = p3.Mesh(p3.BoxGeometry(1, 1, 1), p3.MeshBasicMaterial(color="#1f77b4"))
camera = p3.PerspectiveCamera(position=[2, 2, 2])
return p3.Renderer(
scene=p3.Scene(children=[mesh]),
camera=camera,
controls=[p3.OrbitControls(controlling=camera)],
)The render function should return a pythreejs.Renderer widget (i.e., a Scene plus a camera, with meshes/lights added to the scene; requires pip install 'shinywidgets[pythreejs]'). By default, the scene fills its container (the canvas and camera aspect resize with it); give the Renderer an explicit width or height (or a layout height) to use a fixed pixel size instead.
Note
Accessing the rendered widget: the render function gains two read-only attributes: .value, the value it most recently returned, and .widget, the rendered Renderer instance. Widget state can also be read reactively with .read("some_trait") (a shortcut for reactive_read() on .widget).
Responding to user interaction: scene.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. Until the first orbit it reports the Python-side camera as constructed (pythreejs doesn’t sync it at mount). For a single trait, reactive_read(scene.widget.camera, "position") is the per-trait alternative. With pythreejs.OrbitControls (or TrackballControls), the camera’s position, quaternion, and zoom sync back to Python each time the user finishes orbiting.
Mutating the widget: use .widget to update the rendered scene 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 (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. rate_policy : Optional[RatePolicy] = None-
How to rate-limit
reactive_read()on the widget:"debounce"or"throttle".None(the default) debouncesreactive_read()only ifrate_delayis given; no accessor on this renderer declares a default. rate_delay : Optional[float] = None-
The rate-limit window in seconds (default 0.25).
0disables rate limiting.
Notes
- Scene background: set
pythreejs.Scene(background=...)(it defaults to white and overridesRenderer(background=...)). - Give
pythreejs.DirectionalLight/pythreejs.SpotLightan explicittarget(added to the scene) andshadow(with a camera) – pythreejs creates defaults for them in the browser otherwise, and browser-created widgets live until the session ends, so every re-render would leak 3 models per light (and log a transient console error). - Rotate objects via
mesh.quaternion; pythreejs’srotation(Euler) updates don’t render (an upstream pythreejs bug).
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 scene’s live pythreejs.Camera (a PerspectiveCamera by default). |
camera()
render_pythreejs.camera()The scene’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)). Until the first orbit, this is the Python-side camera as constructed (pythreejs doesn’t sync it at mount). The returned object is the same mutable instance across reads – copy what you keep. Not rate-limited (the browser syncs once per orbit).