diff --git a/R/geom-curve.R b/R/geom-curve.R index dcb7b18003..66442c662b 100644 --- a/R/geom-curve.R +++ b/R/geom-curve.R @@ -6,8 +6,8 @@ GeomCurve <- ggproto( "GeomCurve", GeomSegment, - draw_panel = function(data, panel_params, coord, curvature = 0.5, angle = 90, - ncp = 5, arrow = NULL, arrow.fill = NULL, lineend = "butt", na.rm = FALSE) { + draw_panel = function(data, panel_params, coord, curvature = 0.5, angle = 90, ncp = 5, shape = 0.5, + arrow = NULL, arrow.fill = NULL, lineend = "butt", na.rm = FALSE) { if (!coord$is_linear()) { cli::cli_warn("{.fn geom_curve} is not implemented for non-linear coordinates") @@ -31,11 +31,13 @@ GeomCurve <- ggproto( arrow.fill <- arrow.fill %||% trans$colour + square <- (ncp == 1 && angle == 90) + curveGrob( trans$x, trans$y, trans$xend, trans$yend, default.units = "native", - curvature = curvature, angle = angle, ncp = ncp, - square = FALSE, squareShape = 1, inflect = FALSE, open = TRUE, + curvature = curvature, angle = angle, ncp = ncp, shape = shape, + square = square, squareShape = 1, inflect = FALSE, open = TRUE, gp = gg_par( col = alpha(trans$colour, trans$alpha), fill = alpha(arrow.fill, trans$alpha), diff --git a/R/geom-segment.R b/R/geom-segment.R index 77ca127a44..9a52429659 100644 --- a/R/geom-segment.R +++ b/R/geom-segment.R @@ -94,6 +94,23 @@ GeomSegment <- ggproto( #' arrow = arrow(length = unit(0.03, "npc")) #' ) #' +#' # The `shape` and `ncp` arguments of geom_curve control the sharpness of the spline +#' b + +#' geom_curve( +#' aes(x = x1, y = y1, xend = x2, yend = y2, colour = "ncp = 5"), +#' data = df, +#' curvature = 1, +#' shape = 0, +#' ncp = 5 +#' ) + +#' geom_curve( +#' aes(x = x1, y = y1, xend = x2, yend = y2, colour = "ncp = 1"), +#' data = df, +#' curvature = 1, +#' shape = 0, +#' ncp = 1 +#' ) +#' #' if (requireNamespace('maps', quietly = TRUE)) { #' ggplot(seals, aes(long, lat)) + #' geom_segment(aes(xend = long + delta_long, yend = lat + delta_lat), diff --git a/man/geom_segment.Rd b/man/geom_segment.Rd index 3ea613864a..65b7fc7da3 100644 --- a/man/geom_segment.Rd +++ b/man/geom_segment.Rd @@ -29,6 +29,7 @@ geom_curve( curvature = 0.5, angle = 90, ncp = 5, + shape = 0.5, arrow = NULL, arrow.fill = NULL, lineend = "butt", @@ -149,6 +150,10 @@ the default plot specification, e.g. \code{\link[=annotation_borders]{annotation \item{ncp}{The number of control points used to draw the curve. More control points creates a smoother curve.} + +\item{shape}{A numeric vector of values between -1 and 1, which + control the shape of the curve relative to its control points. + See \code{grid.xspline} for more details.} } \description{ \code{geom_segment()} draws a straight line between points (x, y) and @@ -177,6 +182,23 @@ b + geom_curve( arrow = arrow(length = unit(0.03, "npc")) ) +# The `shape` and `ncp` arguments of geom_curve control the sharpness of the spline +b + + geom_curve( + aes(x = x1, y = y1, xend = x2, yend = y2, colour = "ncp = 5"), + data = df, + curvature = 1, + shape = 0, + ncp = 5 + ) + + geom_curve( + aes(x = x1, y = y1, xend = x2, yend = y2, colour = "ncp = 1"), + data = df, + curvature = 1, + shape = 0, + ncp = 1 + ) + if (requireNamespace('maps', quietly = TRUE)) { ggplot(seals, aes(long, lat)) + geom_segment(aes(xend = long + delta_long, yend = lat + delta_lat), diff --git a/tests/testthat/_snaps/geom-curve/multishape-geom-curve.svg b/tests/testthat/_snaps/geom-curve/multishape-geom-curve.svg new file mode 100644 index 0000000000..3d276e0ff0 --- /dev/null +++ b/tests/testthat/_snaps/geom-curve/multishape-geom-curve.svg @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +0.0 +0.5 +1.0 +1.5 +2.0 + + + + + + + + + +1 +2 +3 +4 +x +y + +colour + + + + + + + + +spline cubic +spline interpolating +square +square tilted +multishape geom_curve + + diff --git a/tests/testthat/test-geom-curve.R b/tests/testthat/test-geom-curve.R index 05f959916e..0e0aa41c15 100644 --- a/tests/testthat/test-geom-curve.R +++ b/tests/testthat/test-geom-curve.R @@ -9,3 +9,42 @@ test_that("geom_curve flipping works", { expect_doppelganger("flipped geom_curve", p + scale_y_reverse()) }) + +test_that("geom_curve shape works", { + + df <- data.frame(x = c(1, 3), xend = c(2, 4), y = c(0, 1), yend = c(2, 1.5)) + + p <- ggplot(df) + + geom_curve( + aes(x, y, xend = xend, yend = yend, color = "square"), + curvature = 1, + shape = 0, + ncp = 1 + ) + + geom_curve( + # This layer will use `square = FALSE` in curveGrob because angle != 90 + aes(x, y, xend = xend, yend = yend, color = "square tilted"), + angle = 60, + curvature = 1, + shape = 0, + ncp = 1 + ) + + geom_curve( + aes(x, y, xend = xend, yend = yend, color = "spline cubic"), + curvature = -.5, + angle = 40, + shape = 1, + ncp = 1 + ) + + geom_curve( + aes(x, y, xend = xend, yend = yend, color = "spline interpolating"), + curvature = -.5, + angle = 40, + shape = -1, + ncp = 1 + ) + + NULL + + expect_doppelganger("multishape geom_curve", p) + +})