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
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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant