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 all 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
Expand Up @@ -327,6 +327,7 @@
to retrieve the class via constructor functions (@teunbrand).
* (internal) The ViewScale class has a `make_fixed_copy()` method to permit
copying trained position scales (#3441).
* Improved consistency of curve direction in `geom_curve()` (@teunbrand, #5069)

# ggplot2 3.5.1

Expand Down
47 changes: 47 additions & 0 deletions R/geom-curve.R
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,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 @@ -72,3 +81,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 92 in R/geom-curve.R

View check run for this annotation

Codecov / codecov/patch

R/geom-curve.R#L92

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

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

View check run for this annotation

Codecov / codecov/patch

R/geom-curve.R#L94-L95

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

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

View check run for this annotation

Codecov / codecov/patch

R/geom-curve.R#L97-L98

Added lines #L97 - L98 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 104 in R/geom-curve.R

View check run for this annotation

Codecov / codecov/patch

R/geom-curve.R#L104

Added line #L104 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 112 in R/geom-curve.R

View check run for this annotation

Codecov / codecov/patch

R/geom-curve.R#L112

Added line #L112 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