Repository navigation
feat: add render_mosaic_widget() for Mosaic dashboards - #285
Merged
Merged
Conversation
Adds a typed @render_mosaic_widget renderer for mosaic_widget.MosaicWidget (linked, DuckDB-backed views), with an example app, unit tests and Playwright coverage for fill, explicit height, a brush round trip through reactive_read(), and re-render cleanup.
…er_mosaic_widget Mosaic answers browser queries in the server's DuckDB connection, so the connection a MosaicWidget holds decides which data each Shiny session sees. Passing a shared con= or a duckdb relation (which mosaic-widget registers on DuckDB's process-wide default connection) lets one session's table replace another's, and Mosaic's non-temporary mosaic.preagg_* cubes are reused across sessions with matching queries. Nothing in the docstring hinted at this. Also note that re-rendering keeps the old widget and its connection alive (anywidget holds a strong reference to every file-based instance) and that in-place `.widget.spec` updates avoid that.
…ion in DuckDB Brushing the scatter plot rescaled the histogram's x-axis (170-230 became 186-200) underneath its own brush, so the example taught a crossfilter whose brushes drift away from their data. Fixed domains keep both axes stable. The selection is now a reactive.calc returning the lazy DuckDB relation, so one brush move runs one query per output instead of pulling every selected row into pandas twice; that is the pattern that scales to the large data Mosaic is for.
# Conflicts: # shinywidgets/_render_widget.py # uv.lock
Resolve conflicts in CHANGELOG.md (keep both sides' renderer entries, dropping install-command mentions to match main's style) and shinywidgets/_render_widget.py (union of TYPE_CHECKING stubs). Add the mosaic_widget optional-dependency extra, point the @render_mosaic_widget docstring and README extras table at pip install 'shinywidgets[mosaic_widget]', and use the extra in examples/mosaic_widget/requirements.txt.
# Conflicts: # shinywidgets/_render_widget.py
# Conflicts: # shinywidgets/_render_widget.py
The sandbox/ scripts (probe.py, smoke.py, typecheck.py, app.py) and their screenshots were local debugging helpers unrelated to the shipped renderer. Ignore sandbox/ going forward so local scratch work can't be committed. The files remain on disk locally.
cpsievert
marked this pull request as ready for review
October 23, 2026 21:59
cpsievert
added a commit
that referenced
this pull request
Oct 23, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Mosaic (
mosaic_widget.MosaicWidget) builds dashboards of linked, cross-filtering views backed by DuckDB. With this PR you can drop one into a Shiny app with a dedicated, typed@render_mosaic_widgetdecorator, and use the user's brush selection from Python:reactive_read(widget, "params")re-runs your code whenever the user brushes, andwidget.data()hands back the selected rows as a DuckDB relation to drive other outputs. An example app (examples/mosaic_widget) shows a scatterplot and histogram that cross-filter each other, with a Shiny summary table of the selection.Part of #278.
Notes
height), but the plots inside keep the spec'swidth/height, because Mosaic specs have no responsive sizing. With an explicit height smaller than the plots, they overflow visibly rather than being clipped. Measured in a 500px fillable card, the output, its container and the widget element have identical boxes (480x466, and 480x316 after shrinking the card to 350px);output_widget(height="260px")gives exactly 260px. No sizing code was needed: the existing.mosaic-widgetCSS already handles it.MosaicWidgetis already an ipywidget, so there is no coercion; the decorator types the return value (and.widget/.value) asMosaicWidget, and type checkers reject other return values.mosaic-widget0.33.0 declaresnarwhals>=2.8but importsis_into_lazyframe, which only exists in narwhals 2.22+. A[tool.uv] constraint-dependenciesentry (with a comment to remove it once upstream fixes its metadata) keeps the lock on a working narwhals, souv.lockbumps narwhals 2.19.0 -> 2.27.1 for everything. The example'srequirements.txtcarries the same pin. Dependencies resolve for Python 3.10-3.14 (duckdb 1.5.6 / 2.0.0 and pyarrow wheels cover the range).Verification
make py-check-format,make pyright,make test-unit(186 passed)render_mosaic_widget: 5 passed (renders without console errors, fill + resize, explicit height, brush round trip to Python, re-render lifecycle with one view per output)🤖 Generated with Claude Code