render_ipydatagrid

render_ipydatagrid class

Reactively render a pandas DataFrame as an interactive ipydatagrid data grid.

Usage Source

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

import pandas as pd
from ipydatagrid import DataGrid

from shinywidgets import render_ipydatagrid

df = pd.DataFrame({"a": [1, 2, 3], "b": ["x", "y", "z"]})


@render_ipydatagrid
def grid():
    return DataGrid(df, selection_mode="row")

The render function may return either a pandas.DataFrame (which is coerced to an ipydatagrid.DataGrid; requires pip install 'shinywidgets[ipydatagrid]') or an ipydatagrid.DataGrid widget. Pass a DataGrid to customize the grid (e.g., selection_mode, editable, or cell renderers).

Note

Accessing the rendered widget: the render function gains two read-only attributes: .value, the value it most recently returned, and .widget, the rendered DataGrid instance. Widget state (e.g., selections) can also be read reactively with .read("some_trait") (a shortcut for reactive_read() on .widget).

Responding to user interaction: read what the user does in the grid with .selected(), .clicked_cell(), and .edited_cell().

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

Some ipydatagrid behaviors worth knowing about:

  • A returned DataFrame uses ipydatagrid’s default selection_mode="none", so selections stays empty; return DataGrid(df, selection_mode="row") (or "cell"/"column") to let users select.
  • selections index the grid as displayed (after any sort or filter), so map them through .widget.get_visible_data(); .visible_data() returns those displayed rows as a data frame, reactively.
  • The grid’s light/dark palette follows the app’s bslib color mode (e.g., ui.input_dark_mode). ipydatagrid freezes the palette when a grid view is created, so toggling dark mode re-themes only grids rendered after the toggle (re-render the output to re-theme an existing grid).
  • DataGrid.select(), DataGrid.clear_selection() and cell edits modify the widget’s state in place, which doesn’t trigger reactive_read(). Assign a new list to .widget.selections instead, and use .widget.on_cell_change() to react to edits.
  • Cell renderers and scales are widgets too, so create them inside the render function rather than at import time.

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 selected() (debounced by default) and reactive_read() on the widget: "debounce" or "throttle". None (the default) keeps the debounce, and debounces reactive_read() only if rate_delay is given.

rate_delay : Optional[float] = None

The rate-limit window in seconds (default 0.25). 0 disables 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

clicked_cell() The most recently clicked cell, or None until the first click: {"region", "column", "column_index", "row", "primary_key_row", "cell_value"}, where row is the visible row and primary_key_row the data row (they differ after a sort). Kept across re-renders until the user clicks the new grid.
edited_cell() The most recent cell edit, or None until the first edit: {"row", "column", "column_index", "value"}, where row is the data row. The widget’s data is already updated when this fires. Kept across re-renders until the next edit – after a re-render or data replacement with new rows, a retained row position can point at a different record, so key follow-up lookups off .widget.data’s index at read time rather than the position.
selected() The grid’s current selection rectangles, as [{"r1", "r2", "c1", "c2"}, ...] (inclusive), in visible row/column coordinates — i.e., after any sort or filter. Map them to data rows with .widget.get_visible_data() (or use visible_data()).
visible_data() The grid’s rows as currently displayed (after its sort and filter), as a pandas data frame — the selected() rectangles’ coordinate space, so visible_data().iloc[r1:r2 + 1] maps a selection to rows.

clicked_cell()

render_ipydatagrid.clicked_cell()

The most recently clicked cell, or None until the first click: {"region", "column", "column_index", "row", "primary_key_row", "cell_value"}, where row is the visible row and primary_key_row the data row (they differ after a sort). Kept across re-renders until the user clicks the new grid.

Fires in any selection_mode, including "none", and for column-header clicks (region="column-header"). Not rate-limited.

edited_cell()

render_ipydatagrid.edited_cell()

The most recent cell edit, or None until the first edit: {"row", "column", "column_index", "value"}, where row is the data row. The widget’s data is already updated when this fires. Kept across re-renders until the next edit – after a re-render or data replacement with new rows, a retained row position can point at a different record, so key follow-up lookups off .widget.data’s index at read time rather than the position.

Requires editable=True. Also fires for Python-side set_cell_value*() calls. Not rate-limited.

selected()

render_ipydatagrid.selected()

The grid’s current selection rectangles, as [{"r1", "r2", "c1", "c2"}, ...] (inclusive), in visible row/column coordinates — i.e., after any sort or filter. Map them to data rows with .widget.get_visible_data() (or use visible_data()).

[] while nothing is selected, and after a sort (sorting clears the selection). Requires selection_mode other than "none"; a plain data frame return uses "none", so return DataGrid(df, selection_mode="row") to let users select.

Dragging a selection rectangle reports continuously (on every pointer move), so this accessor is debounced by default (0.25 s; see the renderer’s rate_policy/rate_delay).

On re-render, the new grid re-seeds this from its own selections trait ([] unless the render function pre-selects). But replacing the data in place (grid.data = df) does not clear the selection – ipydatagrid keeps it, so the rectangles then refer to positions in the old frame. Clear it yourself when replacing data (grid.selections = []), and prefer keying selected rows by the frame’s index (via visible_data()) over positions, so lookups survive data changes.

visible_data()

render_ipydatagrid.visible_data()

The grid’s rows as currently displayed (after its sort and filter), as a pandas data frame — the selected() rectangles’ coordinate space, so visible_data().iloc[r1:r2 + 1] maps a selection to rows.

The whole frame until the user sorts, filters, or edits, and an empty frame when the filter matches nothing. May be briefly stale after a Python-side data replacement (grid.data = df) while a filter/sort is active, until the browser re-syncs the row map. Not rate-limited.