Skip to content

Add Shiny output binding with g2output() and renderG2()#6

Merged
yihui-bot merged 3 commits intomainfrom
copilot/add-examples-for-render-shiny
Mar 31, 2026
Merged

Add Shiny output binding with g2output() and renderG2()#6
yihui-bot merged 3 commits intomainfrom
copilot/add-examples-for-render-shiny

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 31, 2026

gglite had no idiomatic Shiny integration — users had to manually wire up CDN scripts, a message handler, and bare <div> containers. This PR replaces the low-level render_shiny() with a proper Shiny output binding following the standard fooOutput() / renderFoo() pattern.

Changes

R/shiny.R — new file

  • g2output(outputId, width, height) — creates the placeholder <div> and automatically injects the G2 CDN, column-major data helper, and output binding as htmlDependency objects; no manual tags$head() wiring needed
  • renderG2(expr, ...) — standard output$ID = renderG2({...}) pattern using shiny::markRenderFunction

inst/www/g2-binding.js — new file

Shiny output binding (gglite.g2) that finds .gglite-output elements, creates/destroys G2 chart instances on each render, and stores the instance on the element for cleanup on reactive updates.

R/render.R

Removed render_shiny() (superseded by g2output() / renderG2()).

DESCRIPTION

Added shiny and htmltools to Suggests.

examples/shiny.Rmd — new example page

Three sections with prose explanations:

  • Basic exampleg2output('chart1') in the UI, output$chart1 = renderG2({...}) in the server
  • Reactive exampleselectInput drives chart updates automatically
  • Multiple charts — independent outputs side-by-side in a fluidRow

Usage

ui = fluidPage(
  g2output('chart1')
)
server = function(input, output, session) {
  output$chart1 = renderG2({
    g2(mtcars, x = 'mpg', y = 'hp') |> mark_point()
  })
}
shinyApp(ui, server)

Agent-Logs-Url: https://github.com/yihui/gglite/sessions/761adebb-cd4a-4204-9b05-27bd8cf72e48

Co-authored-by: yihui-bot <264330240+yihui-bot@users.noreply.github.com>
Copy link
Copy Markdown
Collaborator

@yihui-bot yihui-bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if you haven't, please test all shiny apps you provided in browser and make sure they work

Comment thread NEWS.md Outdated
Comment on lines +3 to +5
- Added Shiny examples in `examples/shiny.Rmd`.
- Added a `\dontrun{}` example to `render_shiny()` showing minimal Shiny app setup.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't include news

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 78c79dd — NEWS.md is back to just the # gglite 0.1 heading.

Comment thread examples/shiny.Rmd Outdated
Comment on lines +19 to +25
tags$head(
tags$script(src = 'https://unpkg.com/@antv/g2@5/dist/g2.min.js'),
tags$script(
src = 'https://cdn.jsdelivr.net/npm/@xiee/utils/js/g2-column.min.js'
),
includeScript(system.file('www/g2-handler.js', package = 'gglite'))
)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's tedious to repeat these lines in every shiny app, and these are also deep technical details that end-users shouldn't worry about; can we provide the traditional shiny syntax like g2output() and renderG2()? g2output() will make sure to include the JS dependencies into shiny's meta, and output$ID = renderG2() feels more familiar to shiny users

if that's possible, we can get rid of render_shiny()

i don't want to introduce hard dependencies for this task; dependencies in Suggests will be fine

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 78c79dd. render_shiny() is removed and replaced with a proper Shiny output binding:

  • g2output(outputId) — creates the placeholder div and automatically injects the G2 CDN, column-major helper, and the new output binding JS as htmlDependencies; no manual tags$head(...) needed
  • output$ID = renderG2({...}) — standard Shiny render pattern; uses markRenderFunction so reactivity works out of the box

examples/shiny.Rmd now shows just g2output('chart1') in the UI and output$chart1 = renderG2({...}) in the server, with three examples (basic, reactive, multiple charts).

Tested the binding in headless Playwright: element found with shiny-bound-output class, spec delivered correctly as a JS object (Shiny embeds xfun_raw_string json as raw JSON preserving column-major format), chart renders and old chart is properly destroyed on re-render.

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Mar 31, 2026

if you haven't, please test all shiny apps you provided in browser and make sure they work

Tested in commit 78c79dd. Started the basic app, confirmed the Shiny output binding (gglite.g2) correctly finds the #chart1.gglite-output element, receives the chart spec as a JS object (column-major format preserved via Shiny's raw-JSON embedding of xfun::tojson output), calls G2.Chart with the right container ID, renders the chart, and properly destroys the previous chart on reactive re-renders. The CDN URLs are blocked in the sandbox so G2 doesn't actually paint pixels, but the full binding pipeline was verified with a mock G2.Chart.

Copilot AI changed the title Add Shiny examples for render_shiny() Add Shiny output binding with g2output() and renderG2() Mar 31, 2026
Copilot AI requested a review from yihui-bot March 31, 2026 02:31
@yihui-bot yihui-bot marked this pull request as ready for review March 31, 2026 03:16
@yihui-bot yihui-bot merged commit 97e2c59 into main Mar 31, 2026
5 checks passed
@yihui-bot yihui-bot deleted the copilot/add-examples-for-render-shiny branch March 31, 2026 03:36
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.

3 participants