render_altair
render_altair class
Reactively render an altair chart.
Usage Source
render_altair(
_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_altair 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 altair as alt
from shiny.express import render
from vega_datasets import data
from shinywidgets import render_altair
cars = data.cars()
@render_altair
def chart():
brush = alt.selection_interval(name="brush")
return (
alt.Chart(cars)
.mark_point()
.encode(x="Horsepower", y="Miles_per_Gallon")
.add_params(brush)
)
@render.data_frame
def selected_cars():
# an empty frame until the user brushes on the chart
return chart.selected_rows("brush")The render function may return either an altair.Chart (coerced to an altair.JupyterChart widget) or an altair.JupyterChart widget (requires pip install 'shinywidgets[altair]').
Note
Accessing the rendered widget: the render function gains two read-only attributes: .value, the value it most recently returned, and .widget, the rendered JupyterChart instance. Widget state can also be read reactively with .read("some_trait") (a shortcut for reactive_read() on .widget).
Responding to user interaction: as in the example, read a selection from a reactive function (a @render.* function, @reactive.calc, or @reactive.effect), which re-runs whenever the user changes it, much like input.my_slider():
chart.selected("brush"): the selection’s current state.chart.selected_rows("brush"): the rows of the chart’s data it selects, evaluated the way Vega-Lite does (including binned and date fields).
Always give selections a name (alt.selection_interval(name="brush")) and pass it to these methods; the name may be omitted only when the chart has a single selection.
Mutating the widget: trait changes on .widget are synced to the browser. Selections can’t be set from Python, but params can: setting chart.widget.params.<name> = value from a @reactive.effect updates the chart in place without re-sending its data. Prefer params (or a re-render) over replacing chart.widget.chart, which re-sends the data, drops the container sizing described below, and replaces chart.widget.selections and chart.widget.params with new objects – so observers registered on the old ones (altair’s documented jchart.selections.observe(...) idiom) silently stop firing. Register observers on chart.widget, and re-register them if you do replace chart.widget.chart.
Sizing: a chart without an explicit width or height is sized to fill its output ("container"). Concatenated, faceted, and repeated charts keep their natural size.
Offline use: JupyterChart loads its JavaScript from a CDN; call alt.JupyterChart.enable_offline() (requires vl-convert-python) for apps that run without internet access.
Behavior details:
- Unlike other renderers’ accessors,
selected()isn’tNoneonce the chart has rendered: altair reports its selections from the start, so it’s an empty selection (andselected_rows()an empty frame) until the user selects. - A re-render (e.g. when the render function reads an input) gives the user a new chart, whose selections start out empty.
- While the user drags, they update at most once the user pauses for 250 ms (see
rate_policyandrate_delay). - They can’t be read inside this output’s own render function, which builds a new chart each time it runs. To change the chart in response, set a param (above) from a
@reactive.effect.
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
selected()(debounced by default) andreactive_read()on the widget:"debounce"or"throttle".None(the default) keeps the debounce, and debouncesreactive_read()only ifrate_delayis given. rate_delay : Optional[float] = None-
The rate-limit window in seconds (default 0.25).
0disables rate limiting. Each :which :
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
selected() |
The current state of one of the chart’s selections: an altair IntervalSelection, PointSelection, or IndexSelection (see altair.utils.selection), whose .value holds what’s selected. |
selected_rows() |
The rows of df in a selection (see selected()), evaluated the way Vega-Lite does (including binned and temporal fields). |
selected()
render_altair.selected(name: Optional[str] = None)The current state of one of the chart’s selections: an altair IntervalSelection, PointSelection, or IndexSelection (see altair.utils.selection), whose .value holds what’s selected.
Unlike other renderers’ accessors, this is never None once the chart has rendered: until the user selects, it’s an empty selection. name is the name given to the selection (e.g. alt.selection_interval(name="brush")), and may be omitted when the chart has only one. Always name selections: altair’s generated names change between renders. Debounced (250 ms) by default; see the rate_policy and rate_delay parameters. Prefer declaring selections with fields= or encodings=: a bare alt.selection_point() selects positional row indices, which are only meaningful for non-aggregated charts and can silently point at different rows after a re-render with new data.
selected_rows()
render_altair.selected_rows(
name: Optional[str] = None,
*,
df: Optional[IntoDataFrameT] = None,
)The rows of df in a selection (see selected()), evaluated the way Vega-Lite does (including binned and temporal fields).
df defaults to the chart’s own data frame (pandas or polars); pass it for charts whose data is a URL, or that concatenate charts with different data. For a layered chart, the default only resolves when every layer uses the identical data frame object (the same object, not an equal copy) – otherwise pass df explicitly. Returns an empty frame while nothing is selected. Dates are compared in UTC, reading time-zone-naive columns in the browser’s time zone, as Vega-Lite does.