diff --git a/NEWS.md b/NEWS.md index 42b1bfaa98..65e8c9fc48 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,8 @@ # ggplot2 (development version) +* In non-orthogonal coordinate systems (`coord_sf()`, `coord_polar()` and + `coord_radial()`), using 'AsIs' variables escape transformation when + both `x` and `y` is an 'AsIs' variable (@teunbrand, #6205). * The following methods have been deprecated: `fortify.lm()`, `fortify.glht()`, `fortify.confint.glht()`, `fortify.summary.glht()` and `fortify.cld()`. It is recommend to use `broom::augment()` and `broom::tidy()` instead diff --git a/R/coord-.R b/R/coord-.R index 5e711cf95c..6aa113d3ff 100644 --- a/R/coord-.R +++ b/R/coord-.R @@ -284,3 +284,24 @@ check_coord_limits <- function( check_object(limits, is_vector, "a vector", arg = arg, call = call) check_length(limits, 2L, arg = arg, call = call) } + +is_transform_immune <- function(data, coord_name) { + x <- inherits(data$x, "AsIs") + y <- inherits(data$y, "AsIs") + if (!(x || y)) { + # Neither variable is AsIs, so we need to transform + return(FALSE) + } + if (x && y) { + # Both variables are AsIs, so no need to transform + return(TRUE) + } + # We're now in the `xor(x, y)` case + var <- if (x) "x" else "y" + alt <- if (x) "y" else "x" + cli::cli_warn( + "{.fn {coord_name}} cannot respect the {.cls AsIs} class of {.var {var}} \\ + when {.var {alt}} is not also {.cls AsIs}." + ) + return(FALSE) +} diff --git a/R/coord-polar.R b/R/coord-polar.R index f1c8108ddf..aa5e7c538b 100644 --- a/R/coord-polar.R +++ b/R/coord-polar.R @@ -180,6 +180,10 @@ CoordPolar <- ggproto("CoordPolar", Coord, }, transform = function(self, data, panel_params) { + if (is_transform_immune(data, snake_class(self))) { + return(data) + } + arc <- self$start + c(0, 2 * pi) dir <- self$direction data <- rename_data(self, data) diff --git a/R/coord-radial.R b/R/coord-radial.R index 3a5ccf1ee2..b028822f0e 100644 --- a/R/coord-radial.R +++ b/R/coord-radial.R @@ -275,6 +275,10 @@ CoordRadial <- ggproto("CoordRadial", Coord, }, transform = function(self, data, panel_params) { + if (is_transform_immune(data, snake_class(self))) { + return(data) + } + data <- rename_data(self, data) bbox <- panel_params$bbox %||% list(x = c(0, 1), y = c(0, 1)) arc <- panel_params$arc %||% c(0, 2 * pi) diff --git a/R/coord-sf.R b/R/coord-sf.R index 45cc7a90fb..2a43d2e5ef 100644 --- a/R/coord-sf.R +++ b/R/coord-sf.R @@ -77,6 +77,10 @@ CoordSf <- ggproto("CoordSf", CoordCartesian, }, transform = function(self, data, panel_params) { + if (is_transform_immune(data, snake_class(self))) { + return(data) + } + # we need to transform all non-sf data into the correct coordinate system source_crs <- panel_params$default_crs target_crs <- panel_params$crs diff --git a/tests/testthat/_snaps/coord-polar.md b/tests/testthat/_snaps/coord-polar.md index 1e43119dbe..62138ccf99 100644 --- a/tests/testthat/_snaps/coord-polar.md +++ b/tests/testthat/_snaps/coord-polar.md @@ -12,3 +12,7 @@ No appropriate placement found for `r_axis_inside`. i Axis will be placed at panel edge. +# when both x and y are AsIs, they are not transformed + + `coord_radial()` cannot respect the class of `x` when `y` is not also . + diff --git a/tests/testthat/test-coord-polar.R b/tests/testthat/test-coord-polar.R index da49368108..27b641f964 100644 --- a/tests/testthat/test-coord-polar.R +++ b/tests/testthat/test-coord-polar.R @@ -155,6 +155,31 @@ test_that("bounding box calculations are sensible", { ) }) +test_that("when both x and y are AsIs, they are not transformed", { + + p <- ggplot() + + annotate("text", x = I(0.75), y = I(0.25), label = "foo") + + scale_x_continuous(limits = c(0, 10)) + + scale_y_continuous(limits = c(0, 10)) + + grob <- get_layer_grob(p + coord_polar())[[1]] + location <- c(as.numeric(grob$x), as.numeric(grob$y)) + expect_equal(location, c(0.75, 0.25)) + + grob <- get_layer_grob(p + coord_radial())[[1]] + location <- c(as.numeric(grob$x), as.numeric(grob$y)) + expect_equal(location, c(0.75, 0.25)) + + # Check warning is thrown if only one is AsIs + p <- ggplot() + + annotate("text", x = I(0.75), y = 2.5, label = "foo") + + scale_x_continuous(limits = c(0, 10)) + + scale_y_continuous(limits = c(0, 10)) + + coord_radial() + + expect_snapshot_warning(ggplotGrob(p)) + +}) # Visual tests ------------------------------------------------------------ diff --git a/tests/testthat/test-coord_sf.R b/tests/testthat/test-coord_sf.R index a25d470e3b..70cdbb9d20 100644 --- a/tests/testthat/test-coord_sf.R +++ b/tests/testthat/test-coord_sf.R @@ -314,6 +314,22 @@ test_that("sf_transform_xy() works", { }) +test_that("when both x and y are AsIs, they are not transformed", { + + skip_if_not_installed("sf") + + p <- ggplot() + + annotate("text", x = I(0.75), y = I(0.25), label = "foo") + + scale_x_continuous(limits = c(-180, 180)) + + scale_y_continuous(limits = c(-80, 80)) + + coord_sf(default_crs = 4326, crs = 3857) + + grob <- get_layer_grob(p)[[1]] + location <- c(as.numeric(grob$x), as.numeric(grob$y)) + expect_equal(location, c(0.75, 0.25)) + +}) + test_that("coord_sf() can use function breaks and n.breaks", { polygon <- sf::st_sfc(