Skip to content

Commit 4594408

Browse files
authored
Handle recent changes to ggplot2's plot_build() logic (#2262)
1 parent 9ee5480 commit 4594408

23 files changed

+121
-42
lines changed

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

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,17 +26,17 @@ jobs:
2626
fail-fast: false
2727
matrix:
2828
config:
29+
# vdiffr & shinytest only runs on mac r-release since the results aren't cross-platform
2930
- {os: macOS-latest, r: 'release', visual_tests: true, node: "14.x", shinytest: true}
3031
- {os: windows-latest, r: 'release'}
3132
- {os: windows-latest, r: '4.1'}
3233
- {os: windows-latest, r: '3.6'}
33-
- {os: ubuntu-18.04, r: 'devel'}
34-
# vdiffr & shinytest only runs on linux r-release since the results aren't cross-platform
35-
- {os: ubuntu-18.04, r: 'release'}
36-
- {os: ubuntu-18.04, r: 'oldrel-1'}
37-
- {os: ubuntu-18.04, r: 'oldrel-2'}
38-
- {os: ubuntu-18.04, r: 'oldrel-3'}
39-
- {os: ubuntu-18.04, r: 'oldrel-4'}
34+
- {os: ubuntu-latest, r: 'devel'}
35+
- {os: ubuntu-latest, r: 'release'}
36+
- {os: ubuntu-latest, r: 'oldrel-1'}
37+
- {os: ubuntu-latest, r: 'oldrel-2'}
38+
- {os: ubuntu-latest, r: 'oldrel-3'}
39+
- {os: ubuntu-latest, r: 'oldrel-4'}
4040

4141
env:
4242
VISUAL_TESTS: ${{ matrix.config.visual_tests }}

DESCRIPTION

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,3 +85,5 @@ Config/Needs/check:
8585
rcmdcheck,
8686
devtools,
8787
reshape2
88+
Remotes:
89+
tidyverse/ggplot2

R/ggplotly.R

Lines changed: 91 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,7 @@ gg2list <- function(p, width = NULL, height = NULL,
314314
})
315315

316316
# Transform all scales
317-
data <- lapply(data, ggfun("scales_transform_df"), scales = scales)
317+
data <- lapply(data, scales_transform_df, scales = scales)
318318

319319
# Map and train positions so that statistics have access to ranges
320320
# and all positions are numeric
@@ -368,7 +368,7 @@ gg2list <- function(p, width = NULL, height = NULL,
368368
data <- by_layer(function(l, d) l$map_statistic(d, plot))
369369

370370
# Make sure missing (but required) aesthetics are added
371-
ggfun("scales_add_missing")(plot, c("x", "y"), plot$plot_env)
371+
scales_add_missing(plot, c("x", "y"))
372372

373373
# Reparameterise geoms from (e.g.) y and width to ymin and ymax
374374
data <- by_layer(function(l, d) l$compute_geom_1(d))
@@ -401,7 +401,7 @@ gg2list <- function(p, width = NULL, height = NULL,
401401
# Train and map non-position scales
402402
npscales <- scales$non_position_scales()
403403
if (npscales$n() > 0) {
404-
lapply(data, ggfun("scales_train_df"), scales = npscales)
404+
lapply(data, scales_train_df, scales = npscales)
405405
# this for loop is unique to plotly -- it saves the "domain"
406406
# of each non-positional scale for display in tooltips
407407
for (sc in npscales$scales) {
@@ -413,7 +413,7 @@ gg2list <- function(p, width = NULL, height = NULL,
413413
d
414414
})
415415
}
416-
data <- lapply(data, ggfun("scales_map_df"), scales = npscales)
416+
data <- lapply(data, scales_map_df, scales = npscales)
417417
}
418418

419419
# Fill in defaults etc.
@@ -1004,12 +1004,12 @@ gg2list <- function(p, width = NULL, height = NULL,
10041004
# justification of legend boxes
10051005
theme$legend.box.just <- theme$legend.box.just %||% c("center", "center")
10061006
# scales -> data for guides
1007-
gdefs <- ggfun("guides_train")(scales, theme, plot$guides, plot$labels)
1008-
if (length(gdefs) > 0) {
1009-
gdefs <- ggfun("guides_merge")(gdefs)
1010-
gdefs <- ggfun("guides_geom")(gdefs, layers, plot$mapping)
1007+
gdefs <- if (inherits(plot$guides, "ggproto")) {
1008+
get_gdefs_ggproto(npscales$scales, theme, plot, layers)
1009+
} else {
1010+
get_gdefs(scales, theme, plot, layers)
10111011
}
1012-
1012+
10131013
# colourbar -> plotly.js colorbar
10141014
colorbar <- compact(lapply(gdefs, gdef2trace, theme, gglayout))
10151015
nguides <- length(colorbar) + gglayout$showlegend
@@ -1403,12 +1403,21 @@ gdef2trace <- function(gdef, theme, gglayout) {
14031403
if (inherits(gdef, "colorbar")) {
14041404
# sometimes the key has missing values, which we can ignore
14051405
gdef$key <- gdef$key[!is.na(gdef$key$.value), ]
1406-
rng <- range(gdef$bar$value)
1407-
gdef$bar$value <- scales::rescale(gdef$bar$value, from = rng)
1408-
gdef$key$.value <- scales::rescale(gdef$key$.value, from = rng)
1406+
1407+
# Put values on a 0-1 scale
1408+
# N.B. ggplot2 >v3.4.2 (specifically #4879) renamed bar to decor and also
1409+
# started returning normalized values for the key field
1410+
decor <- gdef$decor %||% gdef$bar
1411+
rng <- range(decor$value)
1412+
decor$value <- scales::rescale(decor$value, from = rng)
1413+
if (!"decor" %in% names(gdef)) {
1414+
gdef$key$.value <- scales::rescale(gdef$key$.value, from = rng)
1415+
}
1416+
14091417
vals <- lapply(gglayout[c("xaxis", "yaxis")], function(ax) {
14101418
if (identical(ax$tickmode, "auto")) ax$ticktext else ax$tickvals
14111419
})
1420+
14121421
list(
14131422
x = vals[[1]][[1]],
14141423
y = vals[[2]][[1]],
@@ -1422,7 +1431,7 @@ gdef2trace <- function(gdef, theme, gglayout) {
14221431
# do everything on a 0-1 scale
14231432
marker = list(
14241433
color = c(0, 1),
1425-
colorscale = setNames(gdef$bar[c("value", "colour")], NULL),
1434+
colorscale = setNames(decor[c("value", "colour")], NULL),
14261435
colorbar = list(
14271436
bgcolor = toRGB(theme$legend.background$fill),
14281437
bordercolor = toRGB(theme$legend.background$colour),
@@ -1459,3 +1468,72 @@ getAesMap <- function(plot, layer) {
14591468
layer$mapping
14601469
}
14611470
}
1471+
1472+
# ------------------------------------------------------------------
1473+
# Handle compatibility for changes in ggplot2 >v3.4.2 (specifically #5144),
1474+
# which moved away from scales_transform_df(), scales_train_df(), etc
1475+
# towards ggproto methods attached to `scales`
1476+
# ------------------------------------------------------------------
1477+
scales_transform_df <- function(scales, df) {
1478+
if (is.function(scales$transform_df)) {
1479+
scales$transform_df(df)
1480+
} else {
1481+
ggfun("scales_transform_df")(df, scales = scales)
1482+
}
1483+
}
1484+
1485+
scales_train_df <- function(scales, df) {
1486+
if (is.function(scales$train_df)) {
1487+
scales$train_df(df)
1488+
} else {
1489+
ggfun("scales_train_df")(df, scales = scales)
1490+
}
1491+
}
1492+
1493+
scales_map_df <- function(scales, df) {
1494+
if (is.function(scales$map_df)) {
1495+
scales$map_df(df)
1496+
} else {
1497+
ggfun("scales_map_df")(df, scales = scales)
1498+
}
1499+
}
1500+
1501+
scales_add_missing <- function(plot, aesthetics) {
1502+
if (is.function(plot$scales$add_missing)) {
1503+
plot$scales$add_missing(c("x", "y"), plot$plot_env)
1504+
} else {
1505+
ggfun("scales_add_missing")(plot, aesthetics, plot$plot_env)
1506+
}
1507+
}
1508+
1509+
# -------------------------------------------------------------------------
1510+
# Handle compatibility for changes in ggplot2 >v3.4.2 (specifically #4879),
1511+
# which away from guides_train(), guides_merge(), guides_geom()
1512+
# towards ggproto methods attached to `plot$guides`
1513+
# -------------------------------------------------------------------------
1514+
get_gdefs_ggproto <- function(scales, theme, plot, layers) {
1515+
guides <- plot$guides$setup(scales)
1516+
guides$train(scales, theme$legend.direction, plot$labels)
1517+
if (length(guides$guides) > 0) {
1518+
guides$merge()
1519+
guides$process_layers(layers)
1520+
}
1521+
# Add old legend/colorbar classes to guide params so that ggplotly() code
1522+
# can continue to work the same way it always has
1523+
for (i in which(vapply(guides$guides, inherits, logical(1), "GuideColourbar"))) {
1524+
guides$params[[i]] <- prefix_class(guides$params[[i]], "colorbar")
1525+
}
1526+
for (i in which(vapply(guides$guides, inherits, logical(1), "GuideLegend"))) {
1527+
guides$params[[i]] <- prefix_class(guides$params[[i]], "legend")
1528+
}
1529+
guides$params
1530+
}
1531+
1532+
get_gdefs <- function(scales, theme, plot, layers) {
1533+
gdefs <- ggfun("guides_train")(scales, theme, plot$guides, plot$labels)
1534+
if (length(gdefs) > 0) {
1535+
gdefs <- ggfun("guides_merge")(gdefs)
1536+
gdefs <- ggfun("guides_geom")(gdefs, layers, plot$mapping)
1537+
}
1538+
gdefs
1539+
}

R/layers2traces.R

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,8 @@ layers2traces <- function(data, prestats_data, layout, p) {
103103
# now to the actual layer -> trace conversion
104104
trace.list <- list()
105105

106-
aes_no_guide <- names(p$guides)[vapply(p$guides, identical, logical(1), "none")]
106+
guides <- if (inherits(p$guides, "ggproto")) p$guides$guides else p$guides
107+
aes_no_guide <- names(guides)[vapply(guides, identical, logical(1), "none")]
107108

108109
for (i in seq_along(datz)) {
109110
d <- datz[[i]]

tests/testthat/_snaps/ggplot-heatmap/heatmap-discrete.svg

Lines changed: 1 addition & 1 deletion
Loading

tests/testthat/_snaps/ggplot-heatmap/heatmap-midpoint.svg

Lines changed: 1 addition & 1 deletion
Loading

tests/testthat/_snaps/ggplot-heatmap/heatmap.svg

Lines changed: 1 addition & 1 deletion
Loading

tests/testthat/_snaps/ggplot-hex/hex-basic.svg

Lines changed: 1 addition & 1 deletion
Loading

tests/testthat/_snaps/ggplot-hex/hex-bins.svg

Lines changed: 1 addition & 1 deletion
Loading

tests/testthat/_snaps/ggplot-hex/hex-binwidth.svg

Lines changed: 1 addition & 1 deletion
Loading

tests/testthat/_snaps/ggplot-histogram/histogram-fill.svg

Lines changed: 1 addition & 1 deletion
Loading

tests/testthat/_snaps/ggplot-map/map-facet.svg

Lines changed: 1 addition & 1 deletion
Loading

tests/testthat/_snaps/ggplot-path/path-colors.svg

Lines changed: 1 addition & 1 deletion
Loading

tests/testthat/_snaps/ggplot-segment/segment-multiple-non-numeric.svg

Lines changed: 1 addition & 1 deletion
Loading

tests/testthat/_snaps/ggplot-sf/sf-fill-text.svg

Lines changed: 1 addition & 1 deletion
Loading

tests/testthat/_snaps/ggplot-tooltip/heatmap-discrete-tooltip.svg

Lines changed: 1 addition & 1 deletion
Loading

tests/testthat/_snaps/plotly-linetype/plotly-linetype-manual.new.svg

Lines changed: 0 additions & 1 deletion
This file was deleted.

tests/testthat/_snaps/plotly-linetype/plotly-linetype-manual.svg

Lines changed: 1 addition & 1 deletion
Loading

tests/testthat/_snaps/plotly-subplot/ggally-ggcorr.svg

Lines changed: 1 addition & 1 deletion
Loading

tests/testthat/_snaps/plotly-subplot/subplot-reposition-shape-fixed.new.svg

Lines changed: 0 additions & 1 deletion
This file was deleted.

0 commit comments

Comments
 (0)