From a43539e006db42fb30b33812489c02070066a57b Mon Sep 17 00:00:00 2001 From: Teun van den Brand Date: Tue, 21 Jan 2025 15:08:14 +0100 Subject: [PATCH 1/5] add freeze method to viewscales --- R/scale-view.R | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/R/scale-view.R b/R/scale-view.R index 350d27e9c0..423aaceee9 100644 --- a/R/scale-view.R +++ b/R/scale-view.R @@ -150,5 +150,21 @@ ViewScale <- ggproto("ViewScale", NULL, } self$rescale(b) + }, + freeze = function(self) { + if (self$scale$is_discrete()) { + limits <- self$get_limits() + } else { + limits <- self$continuous_range + } + ggproto( + NULL, self$scale, + breaks = self$get_breaks(), + minor_breaks = self$get_breaks_minor(), + limits = limits, + expand = c(0, 0, 0, 0), + continuous_limits = self$continuous_range, + train = function (...) NULL + ) } ) From 5645702cb16b57b95212c68762b2c6479ce14ef3 Mon Sep 17 00:00:00 2001 From: Teun van den Brand Date: Tue, 21 Jan 2025 15:08:21 +0100 Subject: [PATCH 2/5] add test --- tests/testthat/test-scales.R | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/tests/testthat/test-scales.R b/tests/testthat/test-scales.R index 514cb392a3..23c98e863b 100644 --- a/tests/testthat/test-scales.R +++ b/tests/testthat/test-scales.R @@ -782,3 +782,30 @@ test_that("discrete scales work with NAs in arbitrary positions", { expect_equal(test, output) }) + +test_that("ViewScales can be frozen", { + + p1 <- ggplot(mpg, aes(drv, displ)) + + geom_boxplot() + + annotate("point", x = 5, y = 10) + + scale_x_discrete(labels = c("four-wheel", "forward", "reverse")) + + b1 <- ggplot_build(p1)$layout$panel_params[[1]] + + # We build a second plot with the first plot's scales + p2 <- ggplot(mpg, aes(drv, cyl)) + + geom_violin() + + annotate("point", x = 15, y = 100) + + b1$x$freeze() + + b1$y$freeze() + b2 <- ggplot_build(p2) + + # Breaks and labels should respect p1's limits + x <- get_guide_data(b2, "x") + expect_equal(x$x, 0.6:2.6 / diff(b1$x.range)) + expect_equal(x$.label, c("four-wheel", "forward", "reverse")) + + y <- get_guide_data(b2, "y") + expect_equal(y$y, rescale(seq(2.5, 10, by = 2.5), from = b1$y.range)) + +}) From c06675e454aaae413a04ca563d02f10e50b0770b Mon Sep 17 00:00:00 2001 From: Teun van den Brand Date: Tue, 21 Jan 2025 15:21:22 +0100 Subject: [PATCH 3/5] inverse transform breaks --- R/scale-view.R | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/R/scale-view.R b/R/scale-view.R index 423aaceee9..3e873a5793 100644 --- a/R/scale-view.R +++ b/R/scale-view.R @@ -152,15 +152,25 @@ ViewScale <- ggproto("ViewScale", NULL, self$rescale(b) }, freeze = function(self) { + breaks <- self$get_breaks() + minor <- self$get_breaks_minor() + transform <- self$scale$get_transformation() + if (self$scale$is_discrete()) { limits <- self$get_limits() } else { limits <- self$continuous_range } + + if (!is.null(transform)) { + breaks <- transform$inverse(breaks) + minor <- transform$inverse(minor) + } + ggproto( NULL, self$scale, - breaks = self$get_breaks(), - minor_breaks = self$get_breaks_minor(), + breaks = breaks, + minor_breaks = minor, limits = limits, expand = c(0, 0, 0, 0), continuous_limits = self$continuous_range, From cdec593928ec060b5afd7476c7f1a58b8b2959d4 Mon Sep 17 00:00:00 2001 From: Teun van den Brand Date: Tue, 21 Jan 2025 15:42:48 +0100 Subject: [PATCH 4/5] add news bullet --- NEWS.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/NEWS.md b/NEWS.md index 539dee258c..46baa47d68 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,7 @@ # ggplot2 (development version) +* (internal) The ViewScale class has a `freeze()` method to permit copying + trained position scales (#3441). * `scale_{x/y}_discrete(continuous.limits)` is a new argument to control the display range of discrete scales (@teunbrand, #4174, #6259). * `geom_ribbon()` now appropriately warns about, and removes, missing values From f34e0eb2684d84ff407fe40f16ec3830cd12df1a Mon Sep 17 00:00:00 2001 From: Teun van den Brand Date: Tue, 28 Jan 2025 15:16:51 +0100 Subject: [PATCH 5/5] change `freeze()` to `make_fixed_copy()` --- NEWS.md | 4 ++-- R/scale-view.R | 2 +- tests/testthat/test-scales.R | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/NEWS.md b/NEWS.md index b2aba51e19..9e0997dc85 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,7 +1,7 @@ # ggplot2 (development version) -* (internal) The ViewScale class has a `freeze()` method to permit copying - trained position scales (#3441). +* (internal) The ViewScale class has a `make_fixed_copy()` method to permit + copying trained position scales (#3441). * New parameters for `geom_label()` (@teunbrand and @steveharoz, #5365): * The `linewidth` aesthetic is now applied and replaces the `label.size` argument. diff --git a/R/scale-view.R b/R/scale-view.R index 576b890947..a926084cd8 100644 --- a/R/scale-view.R +++ b/R/scale-view.R @@ -151,7 +151,7 @@ ViewScale <- ggproto("ViewScale", NULL, self$rescale(b) }, - freeze = function(self) { + make_fixed_copy = function(self) { breaks <- self$get_breaks() minor <- self$get_breaks_minor() transform <- self$scale$get_transformation() diff --git a/tests/testthat/test-scales.R b/tests/testthat/test-scales.R index d2f7ae6924..5f14a7189c 100644 --- a/tests/testthat/test-scales.R +++ b/tests/testthat/test-scales.R @@ -748,7 +748,7 @@ test_that("discrete scales work with NAs in arbitrary positions", { }) -test_that("ViewScales can be frozen", { +test_that("ViewScales can make fixed copies", { p1 <- ggplot(mpg, aes(drv, displ)) + geom_boxplot() + @@ -761,8 +761,8 @@ test_that("ViewScales can be frozen", { p2 <- ggplot(mpg, aes(drv, cyl)) + geom_violin() + annotate("point", x = 15, y = 100) + - b1$x$freeze() + - b1$y$freeze() + b1$x$make_fixed_copy() + + b1$y$make_fixed_copy() b2 <- ggplot_build(p2) # Breaks and labels should respect p1's limits