Skip to content

feat(pkg-r): add ggsql visualization tool#224

Merged
cpsievert merged 16 commits into
mainfrom
feat/ggsql-integration-r-v2
May 27, 2026
Merged

feat(pkg-r): add ggsql visualization tool#224
cpsievert merged 16 commits into
mainfrom
feat/ggsql-integration-r-v2

Conversation

@cpsievert
Copy link
Copy Markdown
Contributor

@cpsievert cpsievert commented Apr 28, 2026

Summary

R port of #201. Adds an opt-in visualize tool to querychat's R package, enabling LLM-generated data visualizations via ggsql. When enabled, the LLM can write ggsql queries (SQL + VISUALISE clause) that are executed and rendered as interactive charts inline in the chat.

Usage

library(querychat)

qc <- QueryChat$new(
  palmerpenguins::penguins,
  tools = c("filter", "query", "visualize")
)

qc$app()

The visualize tool is opt-in — include "visualize" in the tools vector alongside "filter" and/or "update" to enable it.

What it looks like

Charts render inline in the chat with a collapsible footer showing the ggsql query (with syntax highlighting), a copy button, and save options:

Screenshot 2026-03-20 at 7 04 42 PM

Key changes

  • visualize tool (opt-in via tools = c("query", "visualize")): The LLM writes a full ggsql query, which is executed against the data source and rendered using ggsql's native Shiny bindings (ggsql::renderGgsql / ggsql::ggsqlOutput).
  • Two-stage ggsql pipeline (querychat_viz.R): Uses DataSource for SQL execution (preserving database pushdown), then feeds results into ggsql's DuckDB reader for VISUALISE processing.
  • Inline chart rendering: Charts render directly in the chat stream via Shiny's dynamic output system, with JS/CSS assets for the footer (show query toggle, save as PNG/SVG).
  • Generated footer assets: pkg-r/inst/htmldep/viz.{js,css} are checked-in package assets, but the shared source/build logic for them already lives on main under js/ (see js/build.mjs). This PR is adding the R package's generated copies, not introducing a second implementation of that browser logic.
  • PNG feedback to LLM: A static PNG is generated (best-effort, requires V8 + rsvg) and sent back to the LLM so it can see what it produced.
  • collapsed parameter on querychat_query: Preparatory queries (e.g., inspecting data before visualizing) can start collapsed so the chart remains the focal point.
  • Prompt restructuring: System and tool prompts were updated to match the Python package — visualization best practices, ggsql syntax reference, and conditional sections based on which tools are enabled.
  • Bookmark support: Viz widget state is saved/restored during Shiny bookmarking.
  • Viz state is internal only: No public accessor methods or reactive values for viz state — consistent with the Python implementation.

Test plan

  • Unit tests for execute_ggsql, extract_visualise_table, has_layer_level_source
  • Unit tests for tool_visualize_dashboard (creation, callback, error handling)
  • Unit tests for truncate_error
  • Unit tests for collapsed parameter on query tool
  • Unit tests for viz prompt conditionals in system prompt
  • Full test suite passes (622 tests, 0 failures)

@cpsievert cpsievert force-pushed the feat/ggsql-integration-r-v2 branch from cd14057 to 5731d0a Compare April 28, 2026 22:54
Comment thread pkg-r/R/querychat_viz.R Outdated
@cpsievert cpsievert marked this pull request as draft April 29, 2026 14:14
Comment thread pkg-r/inst/prompts/ggsql-syntax.md Outdated
@cpsievert cpsievert force-pushed the feat/ggsql-integration-r-v2 branch from f52f440 to afbbfba Compare April 30, 2026 15:54
Comment thread pkg-r/R/QueryChat.R Outdated
Comment thread pkg-py/src/querychat/_viz_tools.py Outdated
Comment thread pkg-py/src/querychat/_viz_tools.py Outdated

This comment was marked as resolved.

@cpsievert cpsievert force-pushed the feat/ggsql-integration-r-v2 branch from 8a1928a to b79b71e Compare May 1, 2026 22:27
For TblSqlSource, execute_query() returns a lazy tbl_sql which
ggsql_register() can't handle. Materialize it first, matching the
existing pattern in app_obj().
@cpsievert cpsievert requested a review from gadenbuie May 1, 2026 22:38
@cpsievert

This comment was marked as outdated.

cpsievert added 2 commits May 4, 2026 10:31
Add a new Visualizations vignette, a Data visualization section to the
Tools vignette, a navbar entry in pkgdown, and a mention in the README,
mirroring the documentation added for the Python package in PR #201.
Add screenshots for bar chart, scatter plot, fullscreen, and show-query
views. Wire them into the Visualizations vignette and the README.
cpsievert and others added 7 commits May 27, 2026 10:11
Resolve conflicts between the ggsql/visualize tool additions on this
branch and main's "filter" rename + suggestion UI changes:

- DESCRIPTION: keep both Remotes (ggsql-r and shinychat/pkg-r)
- QueryChat.R: combine "filter"/"visualize" in arg_match values
- querychat_module.R: use main's heading-grouped GREETING_PROMPT,
  keep branch's restore_viz_widgets helper
- prompt.md: drop nested-list suggestion format per main's change
- QueryChat.Rd: merge filter terminology with visualize/session params
ggsql is now on CRAN — remove posit-dev/ggsql-r from Remotes and
update vignette install instructions to use install.packages().
bslib 0.11.0 supports the "ggsql" language in input_code_editor, so
we can require it directly and remove the runtime packageVersion check.
R CMD check warns about non-ASCII characters in R code files.
Replace em dash with double hyphen in the ggsql tool description string.
Replace 32-bit sample.int with random_hex(8) for collision-resistant
ID generation, matching the Python implementation's approach.
cpsievert and others added 3 commits May 27, 2026 12:15
Make the viz container a fill carrier so the ggsql widget properly
fills the aspect-ratio-driven height instead of using a fixed height.
Also remove the tools default from mod_server() and gracefully skip
viz widget restoration when ggsql is not installed.

This comment was marked as resolved.

cpsievert added 2 commits May 27, 2026 12:59
The "passes the namespaced DOM id into the footer" test was inside the
collapse_validation_errors() describe block but actually exercises
tool_visualize_dashboard(). Move it to the correct group.
Add conditional mustache blocks for tool-aware suggestion groups
that Python already has: "Analyze the data" gated on has_tool_query,
new "Visualize the data" group gated on has_tool_visualize.
@cpsievert cpsievert marked this pull request as ready for review May 27, 2026 18:25
@cpsievert cpsievert merged commit 4e261b0 into main May 27, 2026
13 checks passed
@cpsievert cpsievert deleted the feat/ggsql-integration-r-v2 branch May 27, 2026 19:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants