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