gg2d3 renders ggplot2 objects with D3 in the browser (via htmlwidgets). Under the hood, gg2d3 converts a ggplot into a small intermediate representation (IR) and draws it in SVG with D3.
Install the development version from GitHub:
# install.packages("devtools")
devtools::install_github("DavidZenz/gg2d3")library(ggplot2)
library(gg2d3)
p <- ggplot(mtcars, aes(wt, mpg, color = factor(cyl))) +
geom_point() +
ggtitle("mpg vs wt")
gg2d3(p)The v1.13 release track adds regression confidence and bounded geometry polish without broadening gg2d3 into a full ggplot2 or GIS topology clone.
- Browser visual validation has a dedicated GitHub Actions workflow and
a CI-equivalent local mode. It writes inspectable
index.html,index.json, fixture HTML, screenshot, DOM-summary, and browser-log artifacts undertest_output/browser-visual-smoke/when enabled, while local runs may skip cleanly if optional browser tooling is unavailable. - Pkgdown site evidence has a separate release role: source docs define
the intended public support contract, generated
docs/proves local/pkgdown rendering, GitHub Pages output proves publication, and browser visual smoke artifacts prove representative browser behavior. - Generated-site validation is available with
rtk Rscript --vanilla tools/validate-pkgdown-site.R --mode quick; use release mode before shipping when source docs may have changed. Publication artifacts orgh-pagescheckouts can be inspected withrtk Rscript --vanilla tools/inspect-pkgdown-publication.R --site-root <site-root>; seevignettes/d3-drawing-diagnostics.mdfor thegh workflow run, artifact download, andgh-pagesfallback flow. - Local sf/GDAL setup can be diagnosed with
rtk Rscript --vanilla tools/diagnose-spatial-stack.R; seevignettes/d3-drawing-diagnostics.mdfor how to distinguish local environment repair from gg2d3 regressions when pkgdown reportsclassified_skip. - Renderer wiring is guarded by
inst/htmlwidgets/modules/geom-contracts.jsand source tests for module load order, render/update selectors, interactivity selectors, and public payload sanitization. Selected IR helper-boundary tests cover theme extraction and geom parameter routing while fullas_d3_ir()modularization remains future work. - Geometry support is bounded: ordinary
geom_label()renders SVG label boxes; ordinarygeom_polygon()keeps grouped closed-path behavior and explicitly does not infer topology or holes;geom_rect()andgeom_tile()filter non-finite transformed SVG bounds before emitting rect attributes. - Deferred work remains explicit in diagnostics, including future pixel-diff thresholds, public hosted visual reports, full IR modularization, generated renderer documentation, repelled label placement, and broad GIS-style topology repair.
See vignettes/d3-drawing-diagnostics.md for validation commands,
pkgdown artifact taxonomy, artifact paths, CI-mode behavior,
architecture boundaries, geometry caveats, and future work IDs.
| Category | Geoms |
|---|---|
| Basic | geom_point, geom_line, geom_path, geom_bar, geom_col, geom_rect, geom_tile, geom_text, geom_label, geom_polygon |
| Area/Ribbon | geom_area, geom_ribbon |
| Intervals | geom_segment, geom_errorbar, geom_linerange, geom_pointrange |
| Annotation | geom_hline, geom_vline, geom_abline, geom_rug |
| Statistical | geom_boxplot, geom_violin, geom_density, geom_smooth (loess, gam, lm), geom_dotplot |
Ordinary geom_polygon() renders as grouped closed SVG paths with
ggplot2 built row order preserved inside each group. The shipped
contract covers core fill/stroke/alpha/linewidth/linetype styling,
facets, zoom/update behavior, and the existing tooltip, hover, brush,
handler, and linked-view hooks. Brush selection is path-bounds based and
callback payloads use sanitized representative source rows.
geom_rect() and geom_tile() support distinguishes scale-limit
censoring from coord_cartesian() panel clipping: scale limits can
remove or censor bounds before gg2d3 sees them, while coordinate limits
keep finite rect/tile bounds and clip in the SVG panel. Discrete tile
geometry is closed for initial render and update paths. Log, sqrt, and
reverse transformed rect/tile bounds use ggplot2 built values directly,
and non-finite scaled SVG bounds are filtered before rect attributes are
emitted.
Ordinary geom_label() renders bounded SVG label groups with a backing
rect and text, including useful support for fill, stroke/colour, alpha,
size, numeric padding, hjust, vjust, angle, and family. Ordinary
geom_text() shares the small placement support for hjust, vjust,
angle, and family.
gg2d3 also supports geom_sf() for polygon-family (POLYGON,
MULTIPOLYGON), point-family (POINT, MULTIPOINT), and line-family
(LINESTRING, MULTILINESTRING) geometries, plus geom_sf_text() and
geom_sf_label() annotations at projected anchors aligned with those
accepted sf families. Rows that are unsupported, empty, invalid, or
missing are skipped with warnings while accepted rows render; known CRS
inputs are normalized in R before serialization, and missing CRS
coordinates are serialized as-is with a warning. Optional browser
validation is R/testthat/chromote based and may skip cleanly; when
available, it covers sf family interactivity, stacked overlays, faceted
and empty panels, projected anchor placement, sanitized interactivity
payloads, and zoom suppression.
These support claims are intentionally scoped. gg2d3 does not claim
complete ggplot2 parity for polygon topology/hole repair beyond grouped
closed paths, ordinary polygon subgroup / rule compound-path
rendering, tile basemaps, slippy controls, JavaScript-side CRS
reprojection, repelled label placement, rich text, or path-following
annotation placement. See vignettes/d3-drawing-diagnostics.md for
detailed geometry caveats.
- Continuous and categorical x/y scales with full parity
- Advanced scale configuration:
breaks,minor_breaks,expand, andoob(squish/censor) logic - Log, sqrt, and reverse scale transforms
- Date and datetime (POSIXct) scales with timezone parity
coord_flip,coord_fixed, andcoord_polar(pie, coxcomb, radar)
- Centralized layout engine for high-fidelity panel, axis, and header positioning
- Interactive Legends: Click to toggle, Double-click to solo, Hover to preview
- Legends for color, fill, size, shape, and alpha aesthetics
- Continuous colorbars with gradient rendering
- Support for hierarchical facet headers (nested variables)
- Deep theme inheritance (matches ggplot2 parent-child element tree)
- Full support for
element_blank()and detailed element styling - Text justifications (
hjust,vjust), margins, and rotations - Legend box backgrounds and borders
Composable pipe-based API:
gg2d3(p) |>
d3_tooltip() |>
d3_hover() |>
d3_zoom() |>
d3_brush() |>
d3_transitions() |>
d3_handlers(click = "console.log(d)")- Tooltips — hover to see data values (with date/time and custom formatting)
- Hover highlighting — dim non-hovered groups with configurable styles
- Zoom & pan — scroll to zoom, drag to pan (smooth transitions)
- Brush selection — drag to select data regions (rectangular or axis-only)
- Animated Transitions — smooth, object-constant enter/update/exit animations
- Custom Handlers — execute custom JavaScript on mark interaction
- Shiny Sync — automatic synchronization of plot interactions with Shiny inputs
- Linked views — Crosstalk integration for cross-widget brushing
-
Blank widget / only axes Ensure D3 is bundled correctly in the package (
inst/htmlwidgets/lib/d3/d3.v7.min.js) andinst/htmlwidgets/gg2d3.yamldeclares it. -
Console says “no marks drawn” Your layer may be missing a recognized
geomor data columns. Start with a simple scatter and inspect the IR:ir <- gg2d3:::as_d3_ir(p) str(ir$layers[[1]], max.level = 1)
Vendor D3 v7 locally:
dir.create("inst/htmlwidgets/lib/d3", recursive = TRUE, showWarnings = FALSE)
download.file(
"https://d3js.org/d3.v7.min.js",
destfile = "inst/htmlwidgets/lib/d3/d3.v7.min.js",
mode = "wb"
)Iterate:
devtools::document()
devtools::load_all()
devtools::test()Note: README.md is generated from README.Rmd. Use
devtools::build_readme() to re-render.