Skip to content

Commit 73bd179

Browse files
cpsievertclaude
andauthored
Updates for new kaleido release (save_image()) (#2447)
* Pin kaleido to 0.2.1; get CI passing again * First pass at kaleido 1.0 support * Apply suggestions from code review * Add plotly_build method for ggmatrix objects plotly_build() now works with ggmatrix objects (e.g., from GGally::ggpairs()). Previously, ggplotly() worked but plotly_build() did not have a method for this class. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * Update roxygen * Fix skipping of shiny test * Approve new snapshots * Update API domain * Update shinytest tests * Skip API tests * Update news * Update tests again * Support mapbox and provide actual plotly.js bundle * Install latest kaleido * Skip Gally install on R 4.2 * kaleido 1.0 seems to be mostly working, but it seems broken for some tests :sigh: * Fix GGally exclusion for R 4.2 (oldrel-3) Use matrix variable with fallback instead of ternary expression that was passing literal 'NULL' string to pak. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * Not worth the effort --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
1 parent e3ea0c2 commit 73bd179

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+159
-78
lines changed

.github/workflows/R-CMD-check.yaml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ jobs:
3434
- {os: ubuntu-latest, r: 'release'}
3535
- {os: ubuntu-latest, r: 'oldrel-1'}
3636
- {os: ubuntu-latest, r: 'oldrel-2'}
37-
- {os: ubuntu-latest, r: 'oldrel-3'}
37+
# - {os: ubuntu-latest, r: 'oldrel-3'} # dependency issues with oldrel-3
3838
# - {os: ubuntu-latest, r: 'oldrel-4'} # dependency issues with oldrel-4
3939

4040
env:
@@ -72,7 +72,8 @@ jobs:
7272
- name: Install kaleido
7373
if: matrix.config.visual_tests == true
7474
run: |
75-
Rscript -e 'library(reticulate); use_python(Sys.which("python")); py_install(c("kaleido", "plotly"))'
75+
# We pin kaleido to v0.2.1 here since >=v1.0 doesn't appear to be correctly rendering some plots
76+
Rscript -e 'library(reticulate); use_python(Sys.which("python")); py_install(c("kaleido==0.2.1", "plotly"))'
7677
7778
# Run test() before R CMD check since, for some reason, rcmdcheck::rcmdcheck() skips vdiffr tests
7879
- name: Run Tests

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ Rapp.history
44
*.RData
55
*.Rproj.user
66
*.DS_Store
7+
.venv
78
node_modules/
89
build_site.R
910
revdep_email.R

DESCRIPTION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ Suggests:
7878
rsvg,
7979
ggridges
8080
LazyData: true
81-
RoxygenNote: 7.3.2
81+
RoxygenNote: 7.3.3
8282
Encoding: UTF-8
8383
Roxygen: list(markdown = TRUE)
8484
Config/Needs/check:

NAMESPACE

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ S3method(linewidth_or_size,default)
3232
S3method(linewidth_or_size,element)
3333
S3method(plotly_build,"NULL")
3434
S3method(plotly_build,gg)
35+
S3method(plotly_build,ggmatrix)
3536
S3method(plotly_build,list)
3637
S3method(plotly_build,plotly)
3738
S3method(print,api)

NEWS.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
# plotly (development version)
2+
3+
## Improvements
4+
5+
* `save_image()` now works with kaleido v1.0 and higher. (#2447)
6+
7+
## Bug fixes
8+
9+
* `plotly_build()` now works with `ggmatrix` objects (e.g., from `GGally::ggpairs()`). (#2447)
10+
111
# plotly 4.11.0
212

313
## New features

R/kaleido.R

Lines changed: 61 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ kaleido <- function(...) {
7070

7171
call_env <- rlang::caller_env()
7272

73-
if (!reticulate::py_available()) {
73+
if (!reticulate::py_available(TRUE)) {
7474
rlang::abort(c("`{reticulate}` wasn't able to find a Python environment.",
7575
i = "If you have an existing Python installation, use `reticulate::use_python()` to inform `{reticulate}` of it.",
7676
i = "To have `{reticulate}` install Python for you, `reticulate::install_python()`."
@@ -97,6 +97,66 @@ kaleido <- function(...) {
9797
}
9898
)
9999

100+
res <- if (is.null(tryNULL(kaleido$scopes))) {
101+
newKaleidoScope(kaleido)
102+
} else {
103+
legacyKaleidoScope(kaleido)
104+
}
105+
106+
class(res) <- "kaleidoScope"
107+
res
108+
}
109+
110+
newKaleidoScope <- function(kaleido) {
111+
list(
112+
scopes = NULL,
113+
transform = function(p, file, ..., width = NULL, height = NULL, scale = NULL) {
114+
# Perform JSON conversion exactly how the R package would do it
115+
fig_data <- plotly_build(p)$x[c("data", "layout", "config")]
116+
117+
# Inject mapbox token into layout.mapbox.accesstoken if available
118+
# We use layout instead of config because Kaleido's parser preserves
119+
# layout but drops config. This handles the case where users set
120+
# MAPBOX_TOKEN env var but don't use plot_mapbox()
121+
mapbox <- Sys.getenv("MAPBOX_TOKEN", NA)
122+
if (!is.na(mapbox) && is.null(fig_data$layout$mapbox$accesstoken)) {
123+
fig_data$layout$mapbox$accesstoken <- mapbox
124+
}
125+
126+
fig <- to_JSON(fig_data)
127+
128+
# Write to JSON file
129+
tmp_json <- tempfile(fileext = ".json")
130+
on.exit(unlink(tmp_json))
131+
writeLines(fig, tmp_json)
132+
133+
# Import it as a fig (dict)
134+
load_json <- sprintf(
135+
"import json; fig = json.load(open('%s'))",
136+
tmp_json
137+
)
138+
reticulate::py_run_string(load_json)
139+
140+
# Gather figure-level options
141+
opts <- list(
142+
format = tools::file_ext(file),
143+
width = reticulate::r_to_py(width),
144+
height = reticulate::r_to_py(height),
145+
scale = reticulate::r_to_py(scale)
146+
)
147+
148+
# Pass the R plotly.js bundle path to Kaleido
149+
kopts <- list(plotlyjs = plotlyMainBundlePath())
150+
151+
# Write the figure to a file using kaleido
152+
kaleido$write_fig_sync(reticulate::py$fig, file, opts = opts, kopts = kopts)
153+
},
154+
shutdown = function() {}
155+
)
156+
}
157+
158+
159+
legacyKaleidoScope <- function(kaleido) {
100160
py <- reticulate::py
101161
scope_name <- paste0("scope_", new_id())
102162
py[[scope_name]] <- kaleido$scopes$plotly$PlotlyScope(
@@ -151,7 +211,6 @@ kaleido <- function(...) {
151211
reticulate::py_run_string(paste("del", scope_name))
152212
})
153213

154-
class(res) <- "kaleidoScope"
155214
res
156215
}
157216

R/plotly_build.R

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,11 @@ plotly_build.gg <- function(p, registerFrames = TRUE) {
3737
plotly_build(ggplotly(p))
3838
}
3939

40+
#' @export
41+
plotly_build.ggmatrix <- function(p, registerFrames = TRUE) {
42+
plotly_build(ggplotly(p))
43+
}
44+
4045
#' @export
4146
plotly_build.plotly <- function(p, registerFrames = TRUE) {
4247

inst/examples/shiny/event_data/tests/testthat/_snaps/shinytest2/001.json

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -185,9 +185,9 @@
185185
],
186186
"layout": {
187187
"margin": {
188-
"t": 25.74124809741248,
188+
"t": 23.305936073059364,
189189
"r": 7.3059360730593621,
190-
"b": 39.69558599695587,
190+
"b": 37.260273972602747,
191191
"l": 31.415525114155255
192192
},
193193
"plot_bgcolor": "rgba(235,235,235,1)",
@@ -239,7 +239,7 @@
239239
"ticks": "outside",
240240
"tickcolor": "rgba(51,51,51,1)",
241241
"ticklen": 3.6529680365296811,
242-
"tickwidth": 0.66417600664176002,
242+
"tickwidth": 0,
243243
"showticklabels": true,
244244
"tickfont": {
245245
"color": "rgba(77,77,77,1)",
@@ -252,7 +252,7 @@
252252
"linewidth": 0,
253253
"showgrid": true,
254254
"gridcolor": "rgba(255,255,255,1)",
255-
"gridwidth": 0.66417600664176002,
255+
"gridwidth": 0,
256256
"zeroline": false,
257257
"anchor": "y",
258258
"title": {
@@ -301,7 +301,7 @@
301301
"ticks": "outside",
302302
"tickcolor": "rgba(51,51,51,1)",
303303
"ticklen": 3.6529680365296811,
304-
"tickwidth": 0.66417600664176002,
304+
"tickwidth": 0,
305305
"showticklabels": true,
306306
"tickfont": {
307307
"color": "rgba(77,77,77,1)",
@@ -314,7 +314,7 @@
314314
"linewidth": 0,
315315
"showgrid": true,
316316
"gridcolor": "rgba(255,255,255,1)",
317-
"gridwidth": 0.66417600664176002,
317+
"gridwidth": 0,
318318
"zeroline": false,
319319
"anchor": "x",
320320
"title": {
@@ -340,6 +340,7 @@
340340
},
341341
"yref": "paper",
342342
"xref": "paper",
343+
"layer": "below",
343344
"x0": 0,
344345
"x1": 1,
345346
"y0": 0,
@@ -350,7 +351,7 @@
350351
"legend": {
351352
"bgcolor": "rgba(255,255,255,1)",
352353
"bordercolor": "transparent",
353-
"borderwidth": 1.8897637795275593,
354+
"borderwidth": 0,
354355
"font": {
355356
"color": "rgba(0,0,0,1)",
356357
"family": "",
@@ -445,9 +446,9 @@
445446
},
446447
{
447448
"name": "crosstalk",
448-
"version": "1.2.1",
449+
"version": "1.2.2",
449450
"src": {
450-
"href": "crosstalk-1.2.1"
451+
"href": "crosstalk-1.2.2"
451452
},
452453
"meta": null,
453454
"script": "js/crosstalk.min.js",
-18 KB
Loading

inst/examples/shiny/event_data/tests/testthat/_snaps/shinytest2/002.json

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -188,9 +188,9 @@
188188
],
189189
"layout": {
190190
"margin": {
191-
"t": 25.74124809741248,
191+
"t": 23.305936073059364,
192192
"r": 7.3059360730593621,
193-
"b": 39.69558599695587,
193+
"b": 37.260273972602747,
194194
"l": 31.415525114155255
195195
},
196196
"plot_bgcolor": "rgba(235,235,235,1)",
@@ -242,7 +242,7 @@
242242
"ticks": "outside",
243243
"tickcolor": "rgba(51,51,51,1)",
244244
"ticklen": 3.6529680365296811,
245-
"tickwidth": 0.66417600664176002,
245+
"tickwidth": 0,
246246
"showticklabels": true,
247247
"tickfont": {
248248
"color": "rgba(77,77,77,1)",
@@ -255,7 +255,7 @@
255255
"linewidth": 0,
256256
"showgrid": true,
257257
"gridcolor": "rgba(255,255,255,1)",
258-
"gridwidth": 0.66417600664176002,
258+
"gridwidth": 0,
259259
"zeroline": false,
260260
"anchor": "y",
261261
"title": {
@@ -304,7 +304,7 @@
304304
"ticks": "outside",
305305
"tickcolor": "rgba(51,51,51,1)",
306306
"ticklen": 3.6529680365296811,
307-
"tickwidth": 0.66417600664176002,
307+
"tickwidth": 0,
308308
"showticklabels": true,
309309
"tickfont": {
310310
"color": "rgba(77,77,77,1)",
@@ -317,7 +317,7 @@
317317
"linewidth": 0,
318318
"showgrid": true,
319319
"gridcolor": "rgba(255,255,255,1)",
320-
"gridwidth": 0.66417600664176002,
320+
"gridwidth": 0,
321321
"zeroline": false,
322322
"anchor": "x",
323323
"title": {
@@ -343,6 +343,7 @@
343343
},
344344
"yref": "paper",
345345
"xref": "paper",
346+
"layer": "below",
346347
"x0": 0,
347348
"x1": 1,
348349
"y0": 0,
@@ -353,7 +354,7 @@
353354
"legend": {
354355
"bgcolor": "rgba(255,255,255,1)",
355356
"bordercolor": "transparent",
356-
"borderwidth": 1.8897637795275593,
357+
"borderwidth": 0,
357358
"font": {
358359
"color": "rgba(0,0,0,1)",
359360
"family": "",
@@ -448,9 +449,9 @@
448449
},
449450
{
450451
"name": "crosstalk",
451-
"version": "1.2.1",
452+
"version": "1.2.2",
452453
"src": {
453-
"href": "crosstalk-1.2.1"
454+
"href": "crosstalk-1.2.2"
454455
},
455456
"meta": null,
456457
"script": "js/crosstalk.min.js",

0 commit comments

Comments
 (0)