Skip to content

Flip geom_curve() direction in some circumstances #6332

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Mar 25, 2025
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# ggplot2 (development version)

* Improved consistency of curve direction in `geom_curve()` (@teunbrand, #5069)
* New parameters for `geom_label()` (@teunbrand and @steveharoz, #5365):
* The `linewidth` aesthetic is now applied and replaces the `label.size`
argument.
Expand Down
47 changes: 47 additions & 0 deletions R/geom-curve.R
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,15 @@

trans <- coord$transform(data, panel_params)

flip <- flip_curve(trans, coord, panel_params)
if (flip) {
trans <- rename(trans, c(x = "xend", xend = "x", y = "yend", yend = "y"))
if (!is.null(arrow)) {
# Flip end where arrow appears (2 = last, 1 = first, 3 = both)
arrow$ends <- match(arrow$ends, c(2, 1, 3))
}
}

arrow.fill <- arrow.fill %||% trans$colour

curveGrob(
Expand All @@ -79,3 +88,41 @@
)
}
)

# Helper function for determining whether curves should swap segment ends to
# keep curvature consistent over transformations
flip_curve <- function(data, coord, params) {
flip <- FALSE

# Figure implicit flipping transformations in coords
if (inherits(coord, "CoordFlip")) {
flip <- !flip

Check warning on line 99 in R/geom-curve.R

View check run for this annotation

Codecov / codecov/patch

R/geom-curve.R#L99

Added line #L99 was not covered by tests
} else if (inherits(coord, "CoordTrans")) {
if (identical(coord$trans$x$name, "reverse")) {
flip <- !flip

Check warning on line 102 in R/geom-curve.R

View check run for this annotation

Codecov / codecov/patch

R/geom-curve.R#L101-L102

Added lines #L101 - L102 were not covered by tests
}
if (identical(coord$trans$y$name, "reverse")) {
flip <- !flip

Check warning on line 105 in R/geom-curve.R

View check run for this annotation

Codecov / codecov/patch

R/geom-curve.R#L104-L105

Added lines #L104 - L105 were not covered by tests
}
}

# We don't flip when none or both directions are reversed
if ((coord$reverse %||% "none") %in% c("x", "y")) {
flip <- !flip

Check warning on line 111 in R/geom-curve.R

View check run for this annotation

Codecov / codecov/patch

R/geom-curve.R#L111

Added line #L111 was not covered by tests
}

# Check scales for reverse transforms
# Note that polar coords do not have x/y scales, but these are unsupported
# anyway
fn <- params$x$get_transformation
if (is.function(fn) && identical(fn()$name, "reverse")) {
flip <- !flip

Check warning on line 119 in R/geom-curve.R

View check run for this annotation

Codecov / codecov/patch

R/geom-curve.R#L119

Added line #L119 was not covered by tests
}

fn <- params$y$get_transformation
if (is.function(fn) && identical(fn()$name, "reverse")) {
flip <- !flip
}

flip
}
61 changes: 61 additions & 0 deletions tests/testthat/_snaps/geom-curve/flipped-geom-curve.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
61 changes: 61 additions & 0 deletions tests/testthat/_snaps/geom-curve/standard-geom-curve.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11 changes: 11 additions & 0 deletions tests/testthat/test-geom-curve.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
test_that("geom_curve flipping works", {

df <- data.frame(x = c(1, 2), xend = c(2, 3), y = 1, yend = c(2, 1.5))

p <- ggplot(df, aes(x, y, xend = xend, yend = yend)) +
geom_curve(arrow = arrow())

expect_doppelganger("standard geom_curve", p)
expect_doppelganger("flipped geom_curve", p + scale_y_reverse())

})
Loading