diff --git a/.github/workflows/R-CMD-check.yaml b/.github/workflows/R-CMD-check.yaml
index fd1195d138..275487bf57 100644
--- a/.github/workflows/R-CMD-check.yaml
+++ b/.github/workflows/R-CMD-check.yaml
@@ -26,17 +26,17 @@ jobs:
fail-fast: false
matrix:
config:
+ # vdiffr & shinytest only runs on mac r-release since the results aren't cross-platform
- {os: macOS-latest, r: 'release', visual_tests: true, node: "14.x", shinytest: true}
- {os: windows-latest, r: 'release'}
- {os: windows-latest, r: '4.1'}
- {os: windows-latest, r: '3.6'}
- - {os: ubuntu-18.04, r: 'devel'}
- # vdiffr & shinytest only runs on linux r-release since the results aren't cross-platform
- - {os: ubuntu-18.04, r: 'release'}
- - {os: ubuntu-18.04, r: 'oldrel-1'}
- - {os: ubuntu-18.04, r: 'oldrel-2'}
- - {os: ubuntu-18.04, r: 'oldrel-3'}
- - {os: ubuntu-18.04, r: 'oldrel-4'}
+ - {os: ubuntu-latest, r: 'devel'}
+ - {os: ubuntu-latest, r: 'release'}
+ - {os: ubuntu-latest, r: 'oldrel-1'}
+ - {os: ubuntu-latest, r: 'oldrel-2'}
+ - {os: ubuntu-latest, r: 'oldrel-3'}
+ - {os: ubuntu-latest, r: 'oldrel-4'}
env:
VISUAL_TESTS: ${{ matrix.config.visual_tests }}
diff --git a/DESCRIPTION b/DESCRIPTION
index f2982b5555..5985c2a79c 100644
--- a/DESCRIPTION
+++ b/DESCRIPTION
@@ -85,3 +85,5 @@ Config/Needs/check:
rcmdcheck,
devtools,
reshape2
+Remotes:
+ tidyverse/ggplot2
diff --git a/R/ggplotly.R b/R/ggplotly.R
index 4f4117098a..8ac3cd7ed8 100644
--- a/R/ggplotly.R
+++ b/R/ggplotly.R
@@ -314,7 +314,7 @@ gg2list <- function(p, width = NULL, height = NULL,
})
# Transform all scales
- data <- lapply(data, ggfun("scales_transform_df"), scales = scales)
+ data <- lapply(data, scales_transform_df, scales = scales)
# Map and train positions so that statistics have access to ranges
# and all positions are numeric
@@ -368,7 +368,7 @@ gg2list <- function(p, width = NULL, height = NULL,
data <- by_layer(function(l, d) l$map_statistic(d, plot))
# Make sure missing (but required) aesthetics are added
- ggfun("scales_add_missing")(plot, c("x", "y"), plot$plot_env)
+ scales_add_missing(plot, c("x", "y"))
# Reparameterise geoms from (e.g.) y and width to ymin and ymax
data <- by_layer(function(l, d) l$compute_geom_1(d))
@@ -401,7 +401,7 @@ gg2list <- function(p, width = NULL, height = NULL,
# Train and map non-position scales
npscales <- scales$non_position_scales()
if (npscales$n() > 0) {
- lapply(data, ggfun("scales_train_df"), scales = npscales)
+ lapply(data, scales_train_df, scales = npscales)
# this for loop is unique to plotly -- it saves the "domain"
# of each non-positional scale for display in tooltips
for (sc in npscales$scales) {
@@ -413,7 +413,7 @@ gg2list <- function(p, width = NULL, height = NULL,
d
})
}
- data <- lapply(data, ggfun("scales_map_df"), scales = npscales)
+ data <- lapply(data, scales_map_df, scales = npscales)
}
# Fill in defaults etc.
@@ -1004,12 +1004,12 @@ gg2list <- function(p, width = NULL, height = NULL,
# justification of legend boxes
theme$legend.box.just <- theme$legend.box.just %||% c("center", "center")
# scales -> data for guides
- gdefs <- ggfun("guides_train")(scales, theme, plot$guides, plot$labels)
- if (length(gdefs) > 0) {
- gdefs <- ggfun("guides_merge")(gdefs)
- gdefs <- ggfun("guides_geom")(gdefs, layers, plot$mapping)
+ gdefs <- if (inherits(plot$guides, "ggproto")) {
+ get_gdefs_ggproto(npscales$scales, theme, plot, layers)
+ } else {
+ get_gdefs(scales, theme, plot, layers)
}
-
+
# colourbar -> plotly.js colorbar
colorbar <- compact(lapply(gdefs, gdef2trace, theme, gglayout))
nguides <- length(colorbar) + gglayout$showlegend
@@ -1403,12 +1403,21 @@ gdef2trace <- function(gdef, theme, gglayout) {
if (inherits(gdef, "colorbar")) {
# sometimes the key has missing values, which we can ignore
gdef$key <- gdef$key[!is.na(gdef$key$.value), ]
- rng <- range(gdef$bar$value)
- gdef$bar$value <- scales::rescale(gdef$bar$value, from = rng)
- gdef$key$.value <- scales::rescale(gdef$key$.value, from = rng)
+
+ # Put values on a 0-1 scale
+ # N.B. ggplot2 >v3.4.2 (specifically #4879) renamed bar to decor and also
+ # started returning normalized values for the key field
+ decor <- gdef$decor %||% gdef$bar
+ rng <- range(decor$value)
+ decor$value <- scales::rescale(decor$value, from = rng)
+ if (!"decor" %in% names(gdef)) {
+ gdef$key$.value <- scales::rescale(gdef$key$.value, from = rng)
+ }
+
vals <- lapply(gglayout[c("xaxis", "yaxis")], function(ax) {
if (identical(ax$tickmode, "auto")) ax$ticktext else ax$tickvals
})
+
list(
x = vals[[1]][[1]],
y = vals[[2]][[1]],
@@ -1422,7 +1431,7 @@ gdef2trace <- function(gdef, theme, gglayout) {
# do everything on a 0-1 scale
marker = list(
color = c(0, 1),
- colorscale = setNames(gdef$bar[c("value", "colour")], NULL),
+ colorscale = setNames(decor[c("value", "colour")], NULL),
colorbar = list(
bgcolor = toRGB(theme$legend.background$fill),
bordercolor = toRGB(theme$legend.background$colour),
@@ -1459,3 +1468,72 @@ getAesMap <- function(plot, layer) {
layer$mapping
}
}
+
+# ------------------------------------------------------------------
+# Handle compatibility for changes in ggplot2 >v3.4.2 (specifically #5144),
+# which moved away from scales_transform_df(), scales_train_df(), etc
+# towards ggproto methods attached to `scales`
+# ------------------------------------------------------------------
+scales_transform_df <- function(scales, df) {
+ if (is.function(scales$transform_df)) {
+ scales$transform_df(df)
+ } else {
+ ggfun("scales_transform_df")(df, scales = scales)
+ }
+}
+
+scales_train_df <- function(scales, df) {
+ if (is.function(scales$train_df)) {
+ scales$train_df(df)
+ } else {
+ ggfun("scales_train_df")(df, scales = scales)
+ }
+}
+
+scales_map_df <- function(scales, df) {
+ if (is.function(scales$map_df)) {
+ scales$map_df(df)
+ } else {
+ ggfun("scales_map_df")(df, scales = scales)
+ }
+}
+
+scales_add_missing <- function(plot, aesthetics) {
+ if (is.function(plot$scales$add_missing)) {
+ plot$scales$add_missing(c("x", "y"), plot$plot_env)
+ } else {
+ ggfun("scales_add_missing")(plot, aesthetics, plot$plot_env)
+ }
+}
+
+# -------------------------------------------------------------------------
+# Handle compatibility for changes in ggplot2 >v3.4.2 (specifically #4879),
+# which away from guides_train(), guides_merge(), guides_geom()
+# towards ggproto methods attached to `plot$guides`
+# -------------------------------------------------------------------------
+get_gdefs_ggproto <- function(scales, theme, plot, layers) {
+ guides <- plot$guides$setup(scales)
+ guides$train(scales, theme$legend.direction, plot$labels)
+ if (length(guides$guides) > 0) {
+ guides$merge()
+ guides$process_layers(layers)
+ }
+ # Add old legend/colorbar classes to guide params so that ggplotly() code
+ # can continue to work the same way it always has
+ for (i in which(vapply(guides$guides, inherits, logical(1), "GuideColourbar"))) {
+ guides$params[[i]] <- prefix_class(guides$params[[i]], "colorbar")
+ }
+ for (i in which(vapply(guides$guides, inherits, logical(1), "GuideLegend"))) {
+ guides$params[[i]] <- prefix_class(guides$params[[i]], "legend")
+ }
+ guides$params
+}
+
+get_gdefs <- function(scales, theme, plot, layers) {
+ gdefs <- ggfun("guides_train")(scales, theme, plot$guides, plot$labels)
+ if (length(gdefs) > 0) {
+ gdefs <- ggfun("guides_merge")(gdefs)
+ gdefs <- ggfun("guides_geom")(gdefs, layers, plot$mapping)
+ }
+ gdefs
+}
diff --git a/R/layers2traces.R b/R/layers2traces.R
index 5b110cd56e..e246e85146 100644
--- a/R/layers2traces.R
+++ b/R/layers2traces.R
@@ -103,7 +103,8 @@ layers2traces <- function(data, prestats_data, layout, p) {
# now to the actual layer -> trace conversion
trace.list <- list()
- aes_no_guide <- names(p$guides)[vapply(p$guides, identical, logical(1), "none")]
+ guides <- if (inherits(p$guides, "ggproto")) p$guides$guides else p$guides
+ aes_no_guide <- names(guides)[vapply(guides, identical, logical(1), "none")]
for (i in seq_along(datz)) {
d <- datz[[i]]
diff --git a/tests/testthat/_snaps/ggplot-heatmap/heatmap-discrete.svg b/tests/testthat/_snaps/ggplot-heatmap/heatmap-discrete.svg
index 78366c2ee6..12ac197a96 100644
--- a/tests/testthat/_snaps/ggplot-heatmap/heatmap-discrete.svg
+++ b/tests/testthat/_snaps/ggplot-heatmap/heatmap-discrete.svg
@@ -1 +1 @@
-
+
diff --git a/tests/testthat/_snaps/ggplot-heatmap/heatmap-midpoint.svg b/tests/testthat/_snaps/ggplot-heatmap/heatmap-midpoint.svg
index 9f0074863c..7a2fb04789 100644
--- a/tests/testthat/_snaps/ggplot-heatmap/heatmap-midpoint.svg
+++ b/tests/testthat/_snaps/ggplot-heatmap/heatmap-midpoint.svg
@@ -1 +1 @@
-
+
diff --git a/tests/testthat/_snaps/ggplot-heatmap/heatmap.svg b/tests/testthat/_snaps/ggplot-heatmap/heatmap.svg
index 53c7493737..d6881103cb 100644
--- a/tests/testthat/_snaps/ggplot-heatmap/heatmap.svg
+++ b/tests/testthat/_snaps/ggplot-heatmap/heatmap.svg
@@ -1 +1 @@
-
+
diff --git a/tests/testthat/_snaps/ggplot-hex/hex-basic.svg b/tests/testthat/_snaps/ggplot-hex/hex-basic.svg
index 5ca957f81a..0a6cbd6985 100644
--- a/tests/testthat/_snaps/ggplot-hex/hex-basic.svg
+++ b/tests/testthat/_snaps/ggplot-hex/hex-basic.svg
@@ -1 +1 @@
-
+
diff --git a/tests/testthat/_snaps/ggplot-hex/hex-bins.svg b/tests/testthat/_snaps/ggplot-hex/hex-bins.svg
index 768fc21ffa..ba07778dc8 100644
--- a/tests/testthat/_snaps/ggplot-hex/hex-bins.svg
+++ b/tests/testthat/_snaps/ggplot-hex/hex-bins.svg
@@ -1 +1 @@
-
+
diff --git a/tests/testthat/_snaps/ggplot-hex/hex-binwidth.svg b/tests/testthat/_snaps/ggplot-hex/hex-binwidth.svg
index 01433f0f4f..0faa47f44a 100644
--- a/tests/testthat/_snaps/ggplot-hex/hex-binwidth.svg
+++ b/tests/testthat/_snaps/ggplot-hex/hex-binwidth.svg
@@ -1 +1 @@
-
+
diff --git a/tests/testthat/_snaps/ggplot-histogram/histogram-fill.svg b/tests/testthat/_snaps/ggplot-histogram/histogram-fill.svg
index 8ef8074014..9a6b65a8e9 100644
--- a/tests/testthat/_snaps/ggplot-histogram/histogram-fill.svg
+++ b/tests/testthat/_snaps/ggplot-histogram/histogram-fill.svg
@@ -1 +1 @@
-
+
diff --git a/tests/testthat/_snaps/ggplot-map/map-facet.svg b/tests/testthat/_snaps/ggplot-map/map-facet.svg
index b375480779..010be0473b 100644
--- a/tests/testthat/_snaps/ggplot-map/map-facet.svg
+++ b/tests/testthat/_snaps/ggplot-map/map-facet.svg
@@ -1 +1 @@
-
+
diff --git a/tests/testthat/_snaps/ggplot-path/path-colors.svg b/tests/testthat/_snaps/ggplot-path/path-colors.svg
index fa7349a704..6683900020 100644
--- a/tests/testthat/_snaps/ggplot-path/path-colors.svg
+++ b/tests/testthat/_snaps/ggplot-path/path-colors.svg
@@ -1 +1 @@
-
+
diff --git a/tests/testthat/_snaps/ggplot-segment/segment-multiple-non-numeric.svg b/tests/testthat/_snaps/ggplot-segment/segment-multiple-non-numeric.svg
index 79d8ce82d2..50e1168d0e 100644
--- a/tests/testthat/_snaps/ggplot-segment/segment-multiple-non-numeric.svg
+++ b/tests/testthat/_snaps/ggplot-segment/segment-multiple-non-numeric.svg
@@ -1 +1 @@
-
+
diff --git a/tests/testthat/_snaps/ggplot-sf/sf-fill-text.svg b/tests/testthat/_snaps/ggplot-sf/sf-fill-text.svg
index 2eb8628863..644ffacdb0 100644
--- a/tests/testthat/_snaps/ggplot-sf/sf-fill-text.svg
+++ b/tests/testthat/_snaps/ggplot-sf/sf-fill-text.svg
@@ -1 +1 @@
-
+
diff --git a/tests/testthat/_snaps/ggplot-tooltip/heatmap-discrete-tooltip.svg b/tests/testthat/_snaps/ggplot-tooltip/heatmap-discrete-tooltip.svg
index 8b41c92703..6471d3ab3b 100644
--- a/tests/testthat/_snaps/ggplot-tooltip/heatmap-discrete-tooltip.svg
+++ b/tests/testthat/_snaps/ggplot-tooltip/heatmap-discrete-tooltip.svg
@@ -1 +1 @@
-
+
diff --git a/tests/testthat/_snaps/plotly-linetype/plotly-linetype-manual.new.svg b/tests/testthat/_snaps/plotly-linetype/plotly-linetype-manual.new.svg
deleted file mode 100644
index 0bd90c87e9..0000000000
--- a/tests/testthat/_snaps/plotly-linetype/plotly-linetype-manual.new.svg
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/tests/testthat/_snaps/plotly-linetype/plotly-linetype-manual.svg b/tests/testthat/_snaps/plotly-linetype/plotly-linetype-manual.svg
index b7dd154a44..0bd90c87e9 100644
--- a/tests/testthat/_snaps/plotly-linetype/plotly-linetype-manual.svg
+++ b/tests/testthat/_snaps/plotly-linetype/plotly-linetype-manual.svg
@@ -1 +1 @@
-
+
diff --git a/tests/testthat/_snaps/plotly-subplot/ggally-ggcorr.svg b/tests/testthat/_snaps/plotly-subplot/ggally-ggcorr.svg
index f19e29a9f3..c47cd60883 100644
--- a/tests/testthat/_snaps/plotly-subplot/ggally-ggcorr.svg
+++ b/tests/testthat/_snaps/plotly-subplot/ggally-ggcorr.svg
@@ -1 +1 @@
-
+
diff --git a/tests/testthat/_snaps/plotly-subplot/subplot-reposition-shape-fixed.new.svg b/tests/testthat/_snaps/plotly-subplot/subplot-reposition-shape-fixed.new.svg
deleted file mode 100644
index 1f986bbaf8..0000000000
--- a/tests/testthat/_snaps/plotly-subplot/subplot-reposition-shape-fixed.new.svg
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/tests/testthat/_snaps/plotly-subplot/subplot-reposition-shape-fixed.svg b/tests/testthat/_snaps/plotly-subplot/subplot-reposition-shape-fixed.svg
index 16316e8b7b..1f986bbaf8 100644
--- a/tests/testthat/_snaps/plotly-subplot/subplot-reposition-shape-fixed.svg
+++ b/tests/testthat/_snaps/plotly-subplot/subplot-reposition-shape-fixed.svg
@@ -1 +1 @@
-
+
diff --git a/tests/testthat/test-cookbook-axes.R b/tests/testthat/test-cookbook-axes.R
index db50825360..5c5344ed01 100644
--- a/tests/testthat/test-cookbook-axes.R
+++ b/tests/testthat/test-cookbook-axes.R
@@ -34,13 +34,13 @@ test_that("factor levels determine tick order", {
bp.ylim.hide <- bp + ylim(5, 7.5)
test_that("ylim hides points", {
info <- expect_warning(expect_traces(bp.ylim.hide, 1, "ylim.hide"),
- regexp = "non-finite values")
+ regexp = "non-finite")
})
bp.scale.hide <- bp + scale_y_continuous(limits = c(5, 7.5))
test_that("scale_y(limits) hides points", {
info <- expect_warning(expect_traces(bp.scale.hide, 1, "scale.hide"),
- regexp = "non-finite values")
+ regexp = "non-finite")
expect_equivalent(range(info$layout$yaxis$tickvals), c(5, 7.5))
y <- unlist(lapply(info$data, "[[", "y"))
expect_true(all(5 <= y & y <= 7.5, na.rm = TRUE))
diff --git a/tests/testthat/test-ggplot-dynamicTicks.R b/tests/testthat/test-ggplot-dynamicTicks.R
index 28459e48a6..f50a6b750b 100644
--- a/tests/testthat/test-ggplot-dynamicTicks.R
+++ b/tests/testthat/test-ggplot-dynamicTicks.R
@@ -33,7 +33,7 @@ test_that("Categorical axis reflects custom scale mapping", {
scale_x_discrete(limits = lims)
expect_warning(p <- ggplotly(g, dynamicTicks = "x"),
- regexp = "non-finite values")
+ regexp = "non-finite")
axisActual <- with(
p$x$layout$xaxis, list(type, tickmode, categoryorder, categoryarray)
@@ -49,7 +49,7 @@ test_that("Categorical axis reflects custom scale mapping", {
geom_bar() +
scale_x_discrete(limits = lims, labels = labs)
expect_warning(p <- ggplotly(g, dynamicTicks = "x"),
- regexp = "non-finite values")
+ regexp = "non-finite")
axisActual <- with(
p$x$layout$xaxis, list(type, tickmode, categoryorder, categoryarray)