Skip to content

feat(pkg-py): add ggsql visualization tool#201

Draft
cpsievert wants to merge 3 commits intomainfrom
feat/ggsql-integration
Draft

feat(pkg-py): add ggsql visualization tool#201
cpsievert wants to merge 3 commits intomainfrom
feat/ggsql-integration

Conversation

@cpsievert
Copy link
Copy Markdown
Contributor

@cpsievert cpsievert commented Jan 21, 2026

Summary

Adds an opt-in visualize_query tool to querychat's Python 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 Altair charts inline in the chat.

Usage

Install

pip install querychat[viz]

This installs the optional dependencies: ggsql, altair, and shinywidgets.

Example app

from querychat import QueryChat from querychat.data import titanic qc = QueryChat( titanic(), "titanic", tools=("query", "visualize_query"), ) app = qc.app()

The visualize_query tool is opt-in — include it in the tools tuple alongside "query" 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_query tool (opt-in via tools=("query", "visualize_query")): The LLM writes a full ggsql query, which is executed against the data source and rendered as an Altair chart.
  • Two-stage ggsql pipeline (_viz_ggsql.py): Uses DataSource for SQL execution (preserving database pushdown), then feeds results into ggsql for VISUALISE processing → Altair chart.
  • Inline chart rendering (_viz_altair_widget.py): Custom AltairWidget for rendering charts directly in the chat stream, with JS/CSS assets for interactive display.
  • ggsql prompt & syntax reference (tool-visualize-query.md): Detailed tool prompt with ggsql syntax guidance, plus filter-awareness instructions added to the query tool prompt.
  • Viz state is internal only: No public accessor methods or reactive values for viz state — it's managed entirely by the module/app internals via a private _ServerValues subclass.
  • R prompt changes: Minor updates to pkg-r/inst/prompts/prompt.md and tool-query.md for filter-awareness guidance (keeping prompts in sync).

Test coverage

  • test_ggsql.py — ggsql execution pipeline, spec-to-Altair conversion, title extraction, validation
  • test_viz_tools.py — Tool creation, rendering, error handling
  • test_viz_footer.py — Footer HTML structure, icons, JS invariants
  • playwright/test_10_viz_inline.py — Inline chart Playwright tests
  • playwright/test_11_viz_footer.py — Footer interaction Playwright tests

Before Merging

  • Add dependency requirements (ggsql latest, shinychat card footer/full-screen, py-shiny ggsql code editor, bslib ggsql code editor)
  • Update user-facing docs with visualization examples
  • Update changelog

🤖 Generated with Claude Code

@cpsievert cpsievert force-pushed the feat/ggsql-integration branch from a21712c to 05687d5 Compare March 3, 2026 20:34
@cpsievert cpsievert force-pushed the feat/ggsql-integration branch from 05687d5 to 8f33d70 Compare March 3, 2026 20:38
@cpsievert cpsievert force-pushed the feat/ggsql-integration branch from 8f33d70 to a3bdcbd Compare March 3, 2026 20:40
@cpsievert cpsievert force-pushed the feat/ggsql-integration branch from a3bdcbd to 3e15610 Compare March 3, 2026 20:52
@cpsievert cpsievert force-pushed the feat/ggsql-integration branch from 3e15610 to ac299be Compare March 4, 2026 00:04
@cpsievert cpsievert force-pushed the feat/ggsql-integration branch from 1450755 to a711326 Compare March 4, 2026 01:10
@cpsievert cpsievert force-pushed the feat/ggsql-integration branch from a711326 to 8696fca Compare March 4, 2026 01:15
@cpsievert cpsievert force-pushed the feat/ggsql-integration branch from 8696fca to db264dd Compare March 4, 2026 01:16
@cpsievert cpsievert force-pushed the feat/ggsql-integration branch from db264dd to 5a7e9de Compare March 4, 2026 01:19
@cpsievert cpsievert force-pushed the feat/ggsql-integration branch from 5a7e9de to 9160e24 Compare March 4, 2026 01:23
@cpsievert cpsievert force-pushed the feat/ggsql-integration branch from f1aef08 to 1c3c8e3 Compare March 5, 2026 23:42
@cpsievert cpsievert force-pushed the feat/ggsql-integration branch 6 times, most recently from 0d1fc4d to 3998d6a Compare March 19, 2026 20:52
@cpsievert cpsievert force-pushed the feat/ggsql-integration branch 3 times, most recently from 8aaab35 to 98c097f Compare March 20, 2026 21:11
@cpsievert cpsievert changed the title feat(pkg-py): Add ggsql visualization integration feat(pkg-py): add ggsql visualization tool Mar 20, 2026
@cpsievert cpsievert force-pushed the feat/ggsql-integration branch 2 times, most recently from 108b063 to d2e5c7e Compare March 20, 2026 23:24
cpsievert and others added 3 commits March 20, 2026 19:10
Add ggsql-powered visualization support including: - Visualization tool with inline chart rendering via Altair/ipywidgets - ggsql prompt, syntax reference, and filter-awareness guidance - Visualization tests and example app - UI components (CSS/JS) for chart display, save, and query toggle Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add unit tests for extract_visualise_table() covering bare/quoted identifiers, no-FROM, DRAW-level FROM false positive, CTE names, and case insensitivity - Add integration test for the VISUALISE FROM code path - Document upstream gaps in ggsql Python bindings - Stop re-exporting VisualizeQueryData from tools.py Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@cpsievert cpsievert force-pushed the feat/ggsql-integration branch from d2e5c7e to 8478082 Compare March 21, 2026 00:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

1 participant