From 36ffe7edc07eb3b6b01189452d3f5d490dea06dd Mon Sep 17 00:00:00 2001 From: Teun van den Brand Date: Tue, 12 Nov 2024 14:26:58 +0100 Subject: [PATCH 1/8] helper for annotation ranges --- R/annotation-custom.R | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/R/annotation-custom.R b/R/annotation-custom.R index 4261526b89..d8d16c4d7c 100644 --- a/R/annotation-custom.R +++ b/R/annotation-custom.R @@ -99,3 +99,17 @@ annotation_id <- local({ i } }) + +ranges_annotation <- function(coord, panel_params, x, y, fun) { + if (!inherits(coord, "CoordCartesian")) { + cli::cli_abort("{.fn {fun}} only works with {.fn coord_cartesian}.") + } + if (!inherits(x, "AsIs")) { + x <- panel_params$x$scale$transform(x) + } + if (!inherits(y, "AsIs")) { + y <- panel_params$y$scale$transform(y) + } + data <- coord$transform(data_frame0(x = x, y = y, .size = 2), panel_params) + list(x = range(data$x, na.rm = TRUE), y = range(data$y, na.rm = TRUE)) +} From 332dfc93d946e583d93c7f7b93805b9f5bf5109d Mon Sep 17 00:00:00 2001 From: Teun van den Brand Date: Tue, 12 Nov 2024 14:27:10 +0100 Subject: [PATCH 2/8] use helper --- R/annotation-custom.R | 19 +++++-------------- R/annotation-raster.R | 22 +++++++--------------- 2 files changed, 12 insertions(+), 29 deletions(-) diff --git a/R/annotation-custom.R b/R/annotation-custom.R index d8d16c4d7c..b363333fd2 100644 --- a/R/annotation-custom.R +++ b/R/annotation-custom.R @@ -70,21 +70,12 @@ GeomCustomAnn <- ggproto("GeomCustomAnn", Geom, draw_panel = function(data, panel_params, coord, grob, xmin, xmax, ymin, ymax) { - if (!inherits(coord, "CoordCartesian")) { - cli::cli_abort("{.fn annotation_custom} only works with {.fn coord_cartesian}.") - } - corners <- data_frame0( - x = c(xmin, xmax), - y = c(ymin, ymax), - .size = 2 + range <- ranges_annotation( + coord, panel_params, c(xmin, xmax), c(ymin, ymax), + fun = "annotation_custom" ) - data <- coord$transform(corners, panel_params) - - x_rng <- range(data$x, na.rm = TRUE) - y_rng <- range(data$y, na.rm = TRUE) - - vp <- viewport(x = mean(x_rng), y = mean(y_rng), - width = diff(x_rng), height = diff(y_rng), + vp <- viewport(x = mean(range$x), y = mean(range$y), + width = diff(range$x), height = diff(range$y), just = c("center","center")) editGrob(grob, vp = vp, name = paste(grob$name, annotation_id())) }, diff --git a/R/annotation-raster.R b/R/annotation-raster.R index 8eb8685883..5aec771ead 100644 --- a/R/annotation-raster.R +++ b/R/annotation-raster.R @@ -73,21 +73,13 @@ GeomRasterAnn <- ggproto("GeomRasterAnn", Geom, draw_panel = function(data, panel_params, coord, raster, xmin, xmax, ymin, ymax, interpolate = FALSE) { - if (!inherits(coord, "CoordCartesian")) { - cli::cli_abort("{.fn annotation_raster} only works with {.fn coord_cartesian}.") - } - corners <- data_frame0( - x = c(xmin, xmax), - y = c(ymin, ymax), - .size = 2 + range <- ranges_annotation( + coord, panel_params, c(xmin, xmax), c(ymin, ymax), + fun = "annotation_raster" + ) + rasterGrob(raster, range$x[1], range$y[1], + diff(range$x), diff(range$y), default.units = "native", + just = c("left","bottom"), interpolate = interpolate ) - data <- coord$transform(corners, panel_params) - - x_rng <- range(data$x, na.rm = TRUE) - y_rng <- range(data$y, na.rm = TRUE) - - rasterGrob(raster, x_rng[1], y_rng[1], - diff(x_rng), diff(y_rng), default.units = "native", - just = c("left","bottom"), interpolate = interpolate) } ) From 12939de2dfcf251a2aa29f3efc56c94024cfc8bd Mon Sep 17 00:00:00 2001 From: Teun van den Brand Date: Tue, 12 Nov 2024 14:27:18 +0100 Subject: [PATCH 3/8] update snapshots --- tests/testthat/_snaps/annotate.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/testthat/_snaps/annotate.md b/tests/testthat/_snaps/annotate.md index 23c8e0df43..abf4bb83e7 100644 --- a/tests/testthat/_snaps/annotate.md +++ b/tests/testthat/_snaps/annotate.md @@ -2,14 +2,14 @@ Problem while converting geom to grob. i Error occurred in the 1st layer. - Caused by error in `draw_panel()`: + Caused by error in `ranges_annotation()`: ! `annotation_raster()` only works with `coord_cartesian()`. --- Problem while converting geom to grob. i Error occurred in the 1st layer. - Caused by error in `draw_panel()`: + Caused by error in `ranges_annotation()`: ! `annotation_custom()` only works with `coord_cartesian()`. # annotation_map() checks the input data From 7141435163c735535bc18c8cc224ab09f71a3ca3 Mon Sep 17 00:00:00 2001 From: Teun van den Brand Date: Tue, 12 Nov 2024 14:31:11 +0100 Subject: [PATCH 4/8] use vctrs rules to preserve AsIs --- R/annotation-custom.R | 2 +- R/annotation-raster.R | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/R/annotation-custom.R b/R/annotation-custom.R index b363333fd2..571404a5f4 100644 --- a/R/annotation-custom.R +++ b/R/annotation-custom.R @@ -71,7 +71,7 @@ GeomCustomAnn <- ggproto("GeomCustomAnn", Geom, draw_panel = function(data, panel_params, coord, grob, xmin, xmax, ymin, ymax) { range <- ranges_annotation( - coord, panel_params, c(xmin, xmax), c(ymin, ymax), + coord, panel_params, vec_c(xmin, xmax), vec_c(ymin, ymax), fun = "annotation_custom" ) vp <- viewport(x = mean(range$x), y = mean(range$y), diff --git a/R/annotation-raster.R b/R/annotation-raster.R index 5aec771ead..f91786212a 100644 --- a/R/annotation-raster.R +++ b/R/annotation-raster.R @@ -74,7 +74,7 @@ GeomRasterAnn <- ggproto("GeomRasterAnn", Geom, draw_panel = function(data, panel_params, coord, raster, xmin, xmax, ymin, ymax, interpolate = FALSE) { range <- ranges_annotation( - coord, panel_params, c(xmin, xmax), c(ymin, ymax), + coord, panel_params, vec_c(xmin, xmax), vec_c(ymin, ymax), fun = "annotation_raster" ) rasterGrob(raster, range$x[1], range$y[1], From c5712fc78ac95a2a30ce61aecbbce4997d9473db Mon Sep 17 00:00:00 2001 From: Teun van den Brand Date: Tue, 12 Nov 2024 14:39:40 +0100 Subject: [PATCH 5/8] add test --- tests/testthat/test-annotate.R | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/tests/testthat/test-annotate.R b/tests/testthat/test-annotate.R index 129b5b6720..a0200a82d3 100644 --- a/tests/testthat/test-annotate.R +++ b/tests/testthat/test-annotate.R @@ -86,3 +86,32 @@ test_that("annotate() warns about `stat` or `position` arguments", { annotate("point", 1:3, 1:3, stat = "density", position = "dodge") ) }) + +test_that("annotation_custom() and annotation_raster() adhere to scale transforms", { + rast <- matrix(rainbow(10), nrow = 1) + + p <- ggplot() + + annotation_raster(rast, 1, 10, 1, 9) + + scale_x_continuous(transform = "log10", limits = c(0.1, 100), expand = FALSE) + + scale_y_continuous(limits = c(0, 10), expand = FALSE) + ann <- get_layer_grob(p)[[1]] + + expect_equal(as.numeric(ann$x), 1/3) + expect_equal(as.numeric(ann$y), 1/10) + expect_equal(as.numeric(ann$width), 1/3) + expect_equal(as.numeric(ann$height), 8/10) + + rast <- rasterGrob(rast, width = 1, height = 1) + + p <- ggplot() + + annotation_custom(rast, 1, 10, 1, 9) + + scale_x_continuous(transform = "log10", limits = c(0.1, 100), expand = FALSE) + + scale_y_continuous(limits = c(0, 10), expand = FALSE) + ann <- get_layer_grob(p)[[1]]$vp + + expect_equal(as.numeric(ann$x), 1/2) + expect_equal(as.numeric(ann$y), 1/2) + expect_equal(as.numeric(ann$width), 1/3) + expect_equal(as.numeric(ann$height), 8/10) + +}) From a6c96136b0d1ba4b62117aa4a1e9179afb65cd28 Mon Sep 17 00:00:00 2001 From: Teun van den Brand Date: Tue, 12 Nov 2024 14:41:35 +0100 Subject: [PATCH 6/8] add news bullet --- NEWS.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/NEWS.md b/NEWS.md index 081504c782..152288187f 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,7 @@ # ggplot2 (development version) +* Custom and raster annotation now respond to scale transformations + (@teunbrand based on @yutannihilation's prior work, #3120) * When discrete breaks have names, they'll be used as labels by default (@teunbrand, #6147). * The helper function `is.waiver()` is now exported to help extensions to work From 9ab0a6de2ac9bcdc6d9889117eba7f68fc12febe Mon Sep 17 00:00:00 2001 From: Teun van den Brand Date: Tue, 12 Nov 2024 15:13:57 +0100 Subject: [PATCH 7/8] allow mixing AsIs and numeric --- R/annotation-custom.R | 24 ++++++++++++++---------- R/annotation-raster.R | 2 +- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/R/annotation-custom.R b/R/annotation-custom.R index 571404a5f4..76cb26ac2c 100644 --- a/R/annotation-custom.R +++ b/R/annotation-custom.R @@ -71,7 +71,7 @@ GeomCustomAnn <- ggproto("GeomCustomAnn", Geom, draw_panel = function(data, panel_params, coord, grob, xmin, xmax, ymin, ymax) { range <- ranges_annotation( - coord, panel_params, vec_c(xmin, xmax), vec_c(ymin, ymax), + coord, panel_params, xmin, xmax, ymin, ymax, fun = "annotation_custom" ) vp <- viewport(x = mean(range$x), y = mean(range$y), @@ -91,16 +91,20 @@ annotation_id <- local({ } }) -ranges_annotation <- function(coord, panel_params, x, y, fun) { +ranges_annotation <- function(coord, panel_params, xmin, xmax, ymin, ymax, fun) { if (!inherits(coord, "CoordCartesian")) { cli::cli_abort("{.fn {fun}} only works with {.fn coord_cartesian}.") } - if (!inherits(x, "AsIs")) { - x <- panel_params$x$scale$transform(x) - } - if (!inherits(y, "AsIs")) { - y <- panel_params$y$scale$transform(y) - } - data <- coord$transform(data_frame0(x = x, y = y, .size = 2), panel_params) - list(x = range(data$x, na.rm = TRUE), y = range(data$y, na.rm = TRUE)) + data <- data_frame0(xmin = xmin, xmax = xmax, ymin = ymin, ymax = ymax) + data <- .ignore_data(data)[[1]] + x <- panel_params$x$scale$transform_df(data) + data[names(x)] <- x + y <- panel_params$y$scale$transform_df(data) + data[names(y)] <- y + data <- .expose_data(data)[[1]] + data <- coord$transform(data, panel_params) + list( + x = range(data$xmin, data$xmax, na.rm = TRUE), + y = range(data$ymin, data$ymax, na.rm = TRUE) + ) } diff --git a/R/annotation-raster.R b/R/annotation-raster.R index f91786212a..2635cf05de 100644 --- a/R/annotation-raster.R +++ b/R/annotation-raster.R @@ -74,7 +74,7 @@ GeomRasterAnn <- ggproto("GeomRasterAnn", Geom, draw_panel = function(data, panel_params, coord, raster, xmin, xmax, ymin, ymax, interpolate = FALSE) { range <- ranges_annotation( - coord, panel_params, vec_c(xmin, xmax), vec_c(ymin, ymax), + coord, panel_params, xmin, xmax, ymin, ymax, fun = "annotation_raster" ) rasterGrob(raster, range$x[1], range$y[1], From 64dc15fdb874a43e0a2ab1050c1311bc795de719 Mon Sep 17 00:00:00 2001 From: Teun van den Brand Date: Wed, 13 Nov 2024 09:05:01 +0100 Subject: [PATCH 8/8] clarify AsIs change in news --- NEWS.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/NEWS.md b/NEWS.md index 152288187f..0c493a8f58 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,7 +1,8 @@ # ggplot2 (development version) -* Custom and raster annotation now respond to scale transformations - (@teunbrand based on @yutannihilation's prior work, #3120) +* Custom and raster annotation now respond to scale transformations, and can + use AsIs variables for relative placement (@teunbrand based on + @yutannihilation's prior work, #3120) * When discrete breaks have names, they'll be used as labels by default (@teunbrand, #6147). * The helper function `is.waiver()` is now exported to help extensions to work