From 8266af7114cc98cfe09e39ac4725c252cde5d898 Mon Sep 17 00:00:00 2001 From: Teun van den Brand <tahvdbrand@gmail.com> Date: Wed, 7 May 2025 10:51:25 +0200 Subject: [PATCH 1/7] incorporate `coord_cartesian(ratio)` --- R/coord-cartesian-.R | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/R/coord-cartesian-.R b/R/coord-cartesian-.R index 350e9bfd86..894842b33b 100644 --- a/R/coord-cartesian-.R +++ b/R/coord-cartesian-.R @@ -68,15 +68,18 @@ #' # displayed bigger #' d + coord_cartesian(xlim = c(0, 1)) coord_cartesian <- function(xlim = NULL, ylim = NULL, expand = TRUE, - default = FALSE, clip = "on", reverse = "none") { + default = FALSE, clip = "on", reverse = "none", + ratio = NULL) { check_coord_limits(xlim) check_coord_limits(ylim) + check_number_decimal(ratio, allow_infinite = FALSE, allow_null = TRUE) ggproto(NULL, CoordCartesian, limits = list(x = xlim, y = ylim), reverse = reverse, expand = expand, default = default, - clip = clip + clip = clip, + ratio = ratio ) } @@ -87,7 +90,13 @@ coord_cartesian <- function(xlim = NULL, ylim = NULL, expand = TRUE, CoordCartesian <- ggproto("CoordCartesian", Coord, is_linear = function() TRUE, - is_free = function() TRUE, + is_free = function(self) is.null(self$ratio), + aspect = function(self, ranges) { + if (is.null(self$ratio)) { + return(NULL) + } + diff(ranges$y.range) / diff(ranges$x.range) * self$ratio + }, distance = function(x, y, panel_params) { max_dist <- dist_euclidean(panel_params$x$dimension(), panel_params$y$dimension()) From bd5418fe5470874108cb4be570e4424d3e8494ae Mon Sep 17 00:00:00 2001 From: Teun van den Brand <tahvdbrand@gmail.com> Date: Wed, 7 May 2025 10:51:45 +0200 Subject: [PATCH 2/7] simplify `coord_fixed()` --- R/coord-fixed.R | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/R/coord-fixed.R b/R/coord-fixed.R index d48824cfc4..df4011e1bc 100644 --- a/R/coord-fixed.R +++ b/R/coord-fixed.R @@ -22,17 +22,8 @@ #' p + coord_fixed(xlim = c(15, 30)) #' #' # Resize the plot to see that the specified aspect ratio is maintained -coord_fixed <- function(ratio = 1, xlim = NULL, ylim = NULL, expand = TRUE, - clip = "on", reverse = "none") { - check_coord_limits(xlim) - check_coord_limits(ylim) - ggproto(NULL, CoordFixed, - limits = list(x = xlim, y = ylim), - ratio = ratio, - expand = expand, - reverse = reverse, - clip = clip - ) +coord_fixed <- function(ratio = 1, ...) { + coord_cartesian(ratio = ratio, ...) } #' @export From 2a5c70031580c24ec4abdf1868dd69408defe45f Mon Sep 17 00:00:00 2001 From: Teun van den Brand <tahvdbrand@gmail.com> Date: Wed, 7 May 2025 10:52:17 +0200 Subject: [PATCH 3/7] improve information in error message --- R/facet-.R | 12 +++++++----- tests/testthat/_snaps/facet-layout.md | 4 ++-- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/R/facet-.R b/R/facet-.R index 94b75148ee..8acb95d2d5 100644 --- a/R/facet-.R +++ b/R/facet-.R @@ -161,7 +161,7 @@ Facet <- ggproto("Facet", NULL, params ) - # Draw individual panels, then call `$draw_panels()` method to + # Draw individual panels, then call `$draw_panels()` method to # assemble into gtable lapply(seq_along(panels[[1]]), function(i) { panel <- lapply(panels, `[[`, i) @@ -185,10 +185,12 @@ Facet <- ggproto("Facet", NULL, if (space$x && space$y) { aspect_ratio <- aspect_ratio %||% coord$ratio } else if (free$x || free$y) { - cli::cli_abort( - "{.fn {snake_class(self)}} can't use free scales with \\ - {.fn {snake_class(coord)}}." - ) + msg <- paste0("{.fn {snake_class(self)}} can't use free scales with ", + "{.fn {snake_class(coord)}}") + if (!is.null(coord$ratio)) { + msg <- paste0(msg, " with a fixed {.arg ratio} argument") + } + cli::cli_abort(paste0(msg, ".")) } } diff --git a/tests/testthat/_snaps/facet-layout.md b/tests/testthat/_snaps/facet-layout.md index 1ab4474443..2df447c705 100644 --- a/tests/testthat/_snaps/facet-layout.md +++ b/tests/testthat/_snaps/facet-layout.md @@ -33,11 +33,11 @@ --- - `facet_wrap()` can't use free scales with `coord_fixed()`. + `facet_wrap()` can't use free scales with `coord_cartesian()` with a fixed `ratio` argument. # facet_grid throws errors at bad layout specs - `facet_grid()` can't use free scales with `coord_fixed()`. + `facet_grid()` can't use free scales with `coord_cartesian()` with a fixed `ratio` argument. --- From fca4be59a8c5b922f51310dce23ad5fb7de751f6 Mon Sep 17 00:00:00 2001 From: Teun van den Brand <tahvdbrand@gmail.com> Date: Wed, 7 May 2025 10:57:46 +0200 Subject: [PATCH 4/7] adjust documentation --- R/coord-cartesian-.R | 4 ++++ R/coord-fixed.R | 4 +++- man/coord_cartesian.Rd | 8 +++++++- man/coord_fixed.Rd | 35 +++++++++++++++++++---------------- 4 files changed, 33 insertions(+), 18 deletions(-) diff --git a/R/coord-cartesian-.R b/R/coord-cartesian-.R index 894842b33b..f71abe1490 100644 --- a/R/coord-cartesian-.R +++ b/R/coord-cartesian-.R @@ -29,6 +29,10 @@ #' (default) keeps directions as is. `"x"` and `"y"` can be used to reverse #' their respective directions. `"xy"` can be used to reverse both #' directions. +#' @param ratio aspect ratio, expressed as `y / x`. Can be `NULL` (default) to +#' not use an aspect ratio. Using `1` ensures that one unit on the x-axis +#' is the same length as one unit on the y-axis. Ratios higher than one make +#' units on the y-axis longer than units on the x-axis, and vice versa. #' @export #' @examples #' # There are two ways of zooming the plot display: with scales or diff --git a/R/coord-fixed.R b/R/coord-fixed.R index df4011e1bc..db1a502b91 100644 --- a/R/coord-fixed.R +++ b/R/coord-fixed.R @@ -1,5 +1,7 @@ #' Cartesian coordinates with fixed "aspect ratio" #' +#' `r lifecycle::badge("superseded")` This coordinate system can be replaced by +#' using the `coord_cartesian(ratio)` argument.\cr\cr #' A fixed scale coordinate system forces a specified ratio between the #' physical representation of data units on the axes. The ratio represents the #' number of units on the y-axis equivalent to one unit on the x-axis. The @@ -10,7 +12,7 @@ #' #' @export #' @inheritParams coord_cartesian -#' @param ratio aspect ratio, expressed as `y / x` +#' @inheritDotParams coord_cartesian #' @examples #' # ensures that the ranges of axes are equal to the specified ratio by #' # adjusting the plot aspect ratio diff --git a/man/coord_cartesian.Rd b/man/coord_cartesian.Rd index 15afad523a..474088475f 100644 --- a/man/coord_cartesian.Rd +++ b/man/coord_cartesian.Rd @@ -10,7 +10,8 @@ coord_cartesian( expand = TRUE, default = FALSE, clip = "on", - reverse = "none" + reverse = "none", + ratio = NULL ) } \arguments{ @@ -42,6 +43,11 @@ legend, the plot title, or the plot margins.} (default) keeps directions as is. \code{"x"} and \code{"y"} can be used to reverse their respective directions. \code{"xy"} can be used to reverse both directions.} + +\item{ratio}{aspect ratio, expressed as \code{y / x}. Can be \code{NULL} (default) to +not use an aspect ratio. Using \code{1} ensures that one unit on the x-axis +is the same length as one unit on the y-axis. Ratios higher than one make +units on the y-axis longer than units on the x-axis, and vice versa.} } \description{ The Cartesian coordinate system is the most familiar, and common, type of diff --git a/man/coord_fixed.Rd b/man/coord_fixed.Rd index a3d8d358b7..4f918a9894 100644 --- a/man/coord_fixed.Rd +++ b/man/coord_fixed.Rd @@ -5,29 +5,30 @@ \alias{coord_equal} \title{Cartesian coordinates with fixed "aspect ratio"} \usage{ -coord_fixed( - ratio = 1, - xlim = NULL, - ylim = NULL, - expand = TRUE, - clip = "on", - reverse = "none" -) +coord_fixed(ratio = 1, ...) } \arguments{ -\item{ratio}{aspect ratio, expressed as \code{y / x}} +\item{ratio}{aspect ratio, expressed as \code{y / x}. Can be \code{NULL} (default) to +not use an aspect ratio. Using \code{1} ensures that one unit on the x-axis +is the same length as one unit on the y-axis. Ratios higher than one make +units on the y-axis longer than units on the x-axis, and vice versa.} -\item{xlim, ylim}{Limits for the x and y axes.} - -\item{expand}{If \code{TRUE}, the default, adds a small expansion factor to +\item{...}{ + Arguments passed on to \code{\link[=coord_cartesian]{coord_cartesian}} + \describe{ + \item{\code{xlim,ylim}}{Limits for the x and y axes.} + \item{\code{expand}}{If \code{TRUE}, the default, adds a small expansion factor to the limits to ensure that data and axes don't overlap. If \code{FALSE}, limits are taken exactly from the data or \code{xlim}/\code{ylim}. Giving a logical vector will separately control the expansion for the four directions (top, left, bottom and right). The \code{expand} argument will be recycled to length 4 if necessary. Alternatively, can be a named logical vector to control a single direction, e.g. \code{expand = c(bottom = FALSE)}.} - -\item{clip}{Should drawing be clipped to the extent of the plot panel? A + \item{\code{default}}{Is this the default coordinate system? If \code{FALSE} (the default), +then replacing this coordinate system with another one creates a message alerting +the user that the coordinate system is being replaced. If \code{TRUE}, that warning +is suppressed.} + \item{\code{clip}}{Should drawing be clipped to the extent of the plot panel? A setting of \code{"on"} (the default) means yes, and a setting of \code{"off"} means no. In most cases, the default of \code{"on"} should not be changed, as setting \code{clip = "off"} can cause unexpected results. It allows @@ -35,13 +36,15 @@ drawing of data points anywhere on the plot, including in the plot margins. If limits are set via \code{xlim} and \code{ylim} and some data points fall outside those limits, then those data points may show up in places such as the axes, the legend, the plot title, or the plot margins.} - -\item{reverse}{A string giving which directions to reverse. \code{"none"} + \item{\code{reverse}}{A string giving which directions to reverse. \code{"none"} (default) keeps directions as is. \code{"x"} and \code{"y"} can be used to reverse their respective directions. \code{"xy"} can be used to reverse both directions.} + }} } \description{ +\ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#superseded}{\figure{lifecycle-superseded.svg}{options: alt='[Superseded]'}}}{\strong{[Superseded]}} This coordinate system can be replaced by +using the \code{coord_cartesian(ratio)} argument.\cr\cr A fixed scale coordinate system forces a specified ratio between the physical representation of data units on the axes. The ratio represents the number of units on the y-axis equivalent to one unit on the x-axis. The From 9988f5b587ab53959855f3cf43345071f30cfdde Mon Sep 17 00:00:00 2001 From: Teun van den Brand <tahvdbrand@gmail.com> Date: Wed, 7 May 2025 11:00:53 +0200 Subject: [PATCH 5/7] add example --- R/coord-cartesian-.R | 4 ++++ man/coord_cartesian.Rd | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/R/coord-cartesian-.R b/R/coord-cartesian-.R index f71abe1490..c3d719377e 100644 --- a/R/coord-cartesian-.R +++ b/R/coord-cartesian-.R @@ -59,6 +59,10 @@ #' # default limits #' p + coord_cartesian(expand = FALSE) #' +#' # Using a fixed ratio: 1 y-axis unit is 100 x-axis units +#' # Plot window can be resized and aspect ratio will be maintained +#' p + coord_cartesian(ratio = 100) +#' #' # You can see the same thing with this 2d histogram #' d <- ggplot(diamonds, aes(carat, price)) + #' stat_bin_2d(bins = 25, colour = "white") diff --git a/man/coord_cartesian.Rd b/man/coord_cartesian.Rd index 474088475f..a670baff6c 100644 --- a/man/coord_cartesian.Rd +++ b/man/coord_cartesian.Rd @@ -80,6 +80,10 @@ p + coord_cartesian(xlim = c(325, 500), expand = FALSE) # default limits p + coord_cartesian(expand = FALSE) +# Using a fixed ratio: 1 y-axis unit is 100 x-axis units +# Plot window can be resized and aspect ratio will be maintained +p + coord_cartesian(ratio = 100) + # You can see the same thing with this 2d histogram d <- ggplot(diamonds, aes(carat, price)) + stat_bin_2d(bins = 25, colour = "white") From 4675fc7efb34de84ebcbb83ae3a0092cef40e7c4 Mon Sep 17 00:00:00 2001 From: Teun van den Brand <tahvdbrand@gmail.com> Date: Wed, 7 May 2025 11:01:34 +0200 Subject: [PATCH 6/7] add news bullet --- NEWS.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/NEWS.md b/NEWS.md index 272f551ca3..1caca611c1 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,7 @@ # ggplot2 (development version) +* New `coord_cartesian(ratio)` argument that supersedes `coord_fixed()` and + `coord_equal()`. * (internal) New `Facet$draw_panel_content()` method for delegating panel assembly (@Yunuuuu, #6406). * Facet gains a new method `setup_panel_params` to interact with the From 2b8029e9736d844b8ce270decd213f6bb3cbc924 Mon Sep 17 00:00:00 2001 From: Teun van den Brand <tahvdbrand@gmail.com> Date: Mon, 19 May 2025 14:44:28 +0200 Subject: [PATCH 7/7] Don't officially supersede `coord_fixed()`/`coord_equal()` --- NEWS.md | 5 +++-- R/coord-fixed.R | 2 -- man/coord_fixed.Rd | 2 -- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/NEWS.md b/NEWS.md index ba40b46e11..778997dce8 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,7 +1,8 @@ # ggplot2 (development version) -* New `coord_cartesian(ratio)` argument that supersedes `coord_fixed()` and - `coord_equal()`. +* New `coord_cartesian(ratio)` argument that absorbs the aspect ratio + functionality from `coord_equal()` and `coord_fixed()`, which are now + wrappers for `coord_cartesian()`. * `annotation_borders()` replaces the now-deprecated `borders()` (@teunbrand, #6392) * New `make_constructor()` function that builds a standard constructor for diff --git a/R/coord-fixed.R b/R/coord-fixed.R index 8063f4aa16..8485220c3f 100644 --- a/R/coord-fixed.R +++ b/R/coord-fixed.R @@ -1,7 +1,5 @@ #' Cartesian coordinates with fixed "aspect ratio" #' -#' `r lifecycle::badge("superseded")` This coordinate system can be replaced by -#' using the `coord_cartesian(ratio)` argument.\cr\cr #' A fixed scale coordinate system forces a specified ratio between the #' physical representation of data units on the axes. The ratio represents the #' number of units on the y-axis equivalent to one unit on the x-axis. The diff --git a/man/coord_fixed.Rd b/man/coord_fixed.Rd index 4f918a9894..59a7b6753c 100644 --- a/man/coord_fixed.Rd +++ b/man/coord_fixed.Rd @@ -43,8 +43,6 @@ directions.} }} } \description{ -\ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#superseded}{\figure{lifecycle-superseded.svg}{options: alt='[Superseded]'}}}{\strong{[Superseded]}} This coordinate system can be replaced by -using the \code{coord_cartesian(ratio)} argument.\cr\cr A fixed scale coordinate system forces a specified ratio between the physical representation of data units on the axes. The ratio represents the number of units on the y-axis equivalent to one unit on the x-axis. The