Repository navigation
Expand file tree
/
Copy pathREADME.Rmd
More file actions
198 lines (155 loc) · 7.6 KB
/
Copy pathREADME.Rmd
File metadata and controls
198 lines (155 loc) · 7.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
---
output: github_document
---
<!-- README.md is generated from README.Rmd. Please edit that file -->
```{r, include = FALSE}
knitr::opts_chunk$set(
collapse = TRUE,
comment = "#>",
fig.path = "man/figures/README-",
out.width = "100%"
)
```
# gg2d3
<!-- badges: start -->
<!-- [](https://github.com/DavidZenz/gg2d3/actions/workflows/R-CMD-check.yaml) -->
<!-- [](https://lifecycle.r-lib.org/articles/stages.html) -->
<!-- badges: end -->
**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.
## Installation
Install the development version from GitHub:
```r
# install.packages("devtools")
devtools::install_github("DavidZenz/gg2d3")
```
## Quick start
```r
library(ggplot2)
library(gg2d3)
p <- ggplot(mtcars, aes(wt, mpg, color = factor(cyl))) +
geom_point() +
ggtitle("mpg vs wt")
gg2d3(p)
```
## v1.13 support and validation contract
The v1.13 release track adds regression confidence and bounded geometry polish
without broadening gg2d3 into a full ggplot2 or GIS topology clone.
- The main and interactivity vignettes provide public examples for Cartesian
geoms, ordinary polygons, SF maps and annotations, tooltips, hover, zoom,
brush selection, and linked Crosstalk views.
- The support boundary is intentionally bounded: gg2d3 does not provide tile
basemaps, slippy controls, JavaScript-side CRS reprojection, topology or
hole repair, true geometry-overlap brushing, or ggrepel-style placement.
- The examples below describe the supported behavior and the relevant caveats
where users encounter them.
- pkgdown visual regression adds representative browser evidence through named
visual DOM region and live-payload checks, plus a D-05 full-page PNG and JSON
artifacts under `test_output/pkgdown-visual/`; see the visual maintainer runbook
[d3-drawing-diagnostics.md](vignettes/d3-drawing-diagnostics.md) for local/CI
visual commands and skip interpretation.
## Features
### Geoms
| 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.
### Scales & Coordinates
- Continuous and categorical x/y scales with full parity
- Advanced scale configuration: `breaks`, `minor_breaks`, `expand`, and `oob` (squish/censor) logic
- Log, sqrt, and reverse scale transforms
- Date and datetime (POSIXct) scales with timezone parity
- `coord_flip`, `coord_fixed`, and **`coord_polar`** (pie, coxcomb, radar)
### Layout & Guides
- 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)
### Theming
- 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
### Interactivity
Composable pipe-based API:
```r
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
## Troubleshooting
- **Blank widget / only axes**
Ensure D3 is bundled correctly in the package (`inst/htmlwidgets/lib/d3/d3.v7.min.js`) and `inst/htmlwidgets/gg2d3.yaml` declares it.
- **Console says "no marks drawn"**
Your layer may be missing a recognized `geom` or data columns. Start with a simple scatter and inspect the IR:
```r
ir <- gg2d3:::as_d3_ir(p)
str(ir$layers[[1]], max.level = 1)
```
## Development (for contributors)
Vendor D3 v7 locally:
```r
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:
```r
devtools::document()
devtools::load_all()
devtools::test()
```
---
*Note:* `README.md` is generated from `README.Rmd`. Use `devtools::build_readme()` to re-render.