Skip to content

Commit

Permalink
Non-orthogonal coords preserve AsIs x/y variables (#6206)
Browse files Browse the repository at this point in the history
* exempt some coords from transforming x/y AsIs variables

* add tests

* add news bullet

* throw warning when only one of two variables is AsIs

* update snapshot
  • Loading branch information
teunbrand authored Nov 27, 2024
1 parent 949d359 commit 4193a50
Show file tree
Hide file tree
Showing 8 changed files with 81 additions and 0 deletions.
3 changes: 3 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -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
Expand Down
21 changes: 21 additions & 0 deletions R/coord-.R
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
4 changes: 4 additions & 0 deletions R/coord-polar.R
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
4 changes: 4 additions & 0 deletions R/coord-radial.R
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
4 changes: 4 additions & 0 deletions R/coord-sf.R
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 4 additions & 0 deletions tests/testthat/_snaps/coord-polar.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 <AsIs> class of `x` when `y` is not also <AsIs>.

25 changes: 25 additions & 0 deletions tests/testthat/test-coord-polar.R
Original file line number Diff line number Diff line change
Expand Up @@ -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 ------------------------------------------------------------

Expand Down
16 changes: 16 additions & 0 deletions tests/testthat/test-coord_sf.R
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down

0 comments on commit 4193a50

Please sign in to comment.