render_obsplot

render_obsplot class

Reactively render an Observable Plot chart, created with pyobsplot.

Usage Source

render_obsplot(
    _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_obsplot is a decorator that creates a render function – a function that returns the chart to display and re-runs when the reactive values it reads change:

import pandas as pd
from pyobsplot import Plot

from shinywidgets import render_obsplot

df = pd.DataFrame({"x": [1, 2, 3], "y": [1, 4, 9]})


@render_obsplot
def plot():
    return Plot.plot({"marks": [Plot.dot(df, {"x": "x", "y": "y"})]})

The render function should return a pyobsplot.widget.ObsplotWidget (requires pip install 'shinywidgets[obsplot]'), as produced by Plot.plot() (or by calling an Obsplot() creator). The Plot/Obsplot object itself is a plot creator, not a chart – calling it with a plot specification produces the chart. Only the default format='widget' produces a chart; the other formats ('html', 'svg', 'png') return None, which renders as an empty output.

Observable Plot charts have a fixed pixel width: they shrink proportionally (preserving aspect ratio) to fit a narrower container, but never grow past the specification’s width. Control the size with width (and, if needed, height) in the plot specification.

Note

Accessing the rendered widget: the render function gains two read-only attributes: .value and .widget, which are both the rendered ObsplotWidget instance.

Responding to user interaction: pyobsplot’s interactions (tips, crosshairs) run entirely in the browser; nothing is synced back to Python, so there’s no widget state to reactive_read().

Mutating the widget: to change a chart without re-rendering, assign a new specification to .widget.spec (the same dictionary you’d pass to Plot.plot()).

pandas and polars DataFrames in the specification are serialized to Arrow IPC and sent to the browser with the widget state, so a chart over a large dataset makes for a large message (and pyobsplot’s JavaScript bundle is sent to the browser again on each render). For large data, aggregate before plotting.

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.

Examples

import polars as pl
from pyobsplot import Plot
from shiny.express import ui
from shinywidgets import render_obsplot

penguins = pl.read_csv(
    "https://github.com/juba/pyobsplot/raw/main/doc/data/penguins.csv"
)


@render_obsplot
def penguin_plot():
    return Plot.plot(
        {
            "grid": True,
            "color": {"legend": True},
            "marks": [
                Plot.dot(
                    penguins,
                    {
                        "x": "flipper_length_mm",
                        "y": "body_mass_g",
                        "fill": "species",
                    },
                )
            ],
        }
    )

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