diff --git a/NEWS.md b/NEWS.md index b264b645fb..4699714a4a 100644 --- a/NEWS.md +++ b/NEWS.md @@ -161,6 +161,10 @@ core developer team. * `geom_*()` and `stat_*()` now accepts purrr-style lambda notation (@yutannihilation, #3138). +* `geom_tile()` and `geom_rect()` now draw rectangles without notches at the + corners. The style of the corner can be controlled by `linejoin` parameters + (@yutannihilation, #3050). + # ggplot2 3.1.0 ## Breaking changes diff --git a/R/geom-rect.r b/R/geom-rect.r index c8d03e5121..95cf0383e6 100644 --- a/R/geom-rect.r +++ b/R/geom-rect.r @@ -3,6 +3,7 @@ geom_rect <- function(mapping = NULL, data = NULL, stat = "identity", position = "identity", ..., + linejoin = "mitre", na.rm = FALSE, show.legend = NA, inherit.aes = TRUE) { @@ -15,6 +16,7 @@ geom_rect <- function(mapping = NULL, data = NULL, show.legend = show.legend, inherit.aes = inherit.aes, params = list( + linejoin = linejoin, na.rm = na.rm, ... ) @@ -31,7 +33,7 @@ GeomRect <- ggproto("GeomRect", Geom, required_aes = c("xmin", "xmax", "ymin", "ymax"), - draw_panel = function(self, data, panel_params, coord) { + draw_panel = function(self, data, panel_params, coord, linejoin = "mitre") { if (!coord$is_linear()) { aesthetics <- setdiff( names(data), c("x", "y", "xmin", "xmax", "ymin", "ymax") @@ -58,7 +60,10 @@ GeomRect <- ggproto("GeomRect", Geom, fill = alpha(coords$fill, coords$alpha), lwd = coords$size * .pt, lty = coords$linetype, - lineend = "butt" + linejoin = linejoin, + # `lineend` is a workaround for Windows and intentionally kept unexposed + # as an argument. (c.f. https://github.com/tidyverse/ggplot2/issues/3037#issuecomment-457504667) + lineend = if (identical(linejoin, "round")) "round" else "square" ) )) } @@ -69,7 +74,10 @@ GeomRect <- ggproto("GeomRect", Geom, # Convert rectangle to polygon -# Useful for non-Cartesian coordinate systems where it's easy to work purely in terms of locations, rather than locations and dimensions. +# Useful for non-Cartesian coordinate systems where it's easy to work purely in +# terms of locations, rather than locations and dimensions. Note that, though +# `polygonGrob()` expects an open form, closed form is needed for correct +# munching (c.f. https://github.com/tidyverse/ggplot2/issues/3037#issuecomment-458406857). # # @keyword internal rect_to_poly <- function(xmin, xmax, ymin, ymax) { diff --git a/R/geom-tile.r b/R/geom-tile.r index 3ffb97ae03..8c31e32148 100644 --- a/R/geom-tile.r +++ b/R/geom-tile.r @@ -10,6 +10,7 @@ #' @eval rd_aesthetics("geom", "tile") #' @inheritParams layer #' @inheritParams geom_point +#' @inheritParams geom_segment #' @export #' @examples #' # The most common use for rectangles is to draw a surface. You always want @@ -57,6 +58,7 @@ geom_tile <- function(mapping = NULL, data = NULL, stat = "identity", position = "identity", ..., + linejoin = "mitre", na.rm = FALSE, show.legend = NA, inherit.aes = TRUE) { @@ -69,6 +71,7 @@ geom_tile <- function(mapping = NULL, data = NULL, show.legend = show.legend, inherit.aes = inherit.aes, params = list( + linejoin = linejoin, na.rm = na.rm, ... ) diff --git a/R/legend-draw.r b/R/legend-draw.r index cca41531c1..6e51a63488 100644 --- a/R/legend-draw.r +++ b/R/legend-draw.r @@ -80,7 +80,10 @@ draw_key_polygon <- function(data, params, size) { fill = alpha(data$fill %||% "grey20", data$alpha), lty = data$linetype %||% 1, lwd = lwd * .pt, - linejoin = "mitre" + linejoin = params$linejoin %||% "mitre", + # `lineend` is a workaround for Windows and intentionally kept unexposed + # as an argument. (c.f. https://github.com/tidyverse/ggplot2/issues/3037#issuecomment-457504667) + lineend = if (identical(params$linejoin, "round")) "round" else "square" )) } diff --git a/man/geom_tile.Rd b/man/geom_tile.Rd index ad8ff55ec6..cf24a3e510 100644 --- a/man/geom_tile.Rd +++ b/man/geom_tile.Rd @@ -12,12 +12,12 @@ geom_raster(mapping = NULL, data = NULL, stat = "identity", inherit.aes = TRUE) geom_rect(mapping = NULL, data = NULL, stat = "identity", - position = "identity", ..., na.rm = FALSE, show.legend = NA, - inherit.aes = TRUE) + position = "identity", ..., linejoin = "mitre", na.rm = FALSE, + show.legend = NA, inherit.aes = TRUE) geom_tile(mapping = NULL, data = NULL, stat = "identity", - position = "identity", ..., na.rm = FALSE, show.legend = NA, - inherit.aes = TRUE) + position = "identity", ..., linejoin = "mitre", na.rm = FALSE, + show.legend = NA, inherit.aes = TRUE) } \arguments{ \item{mapping}{Set of aesthetic mappings created by \code{\link[=aes]{aes()}} or @@ -71,6 +71,8 @@ display.} rather than combining with them. This is most useful for helper functions that define both data and aesthetics and shouldn't inherit behaviour from the default plot specification, e.g. \code{\link[=borders]{borders()}}.} + +\item{linejoin}{Line join style (round, mitre, bevel).} } \description{ \code{geom_rect} and \code{geom_tile} do the same thing, but are diff --git a/tests/figs/creating-aesthetic-mappings/stat-count-width-0-5.svg b/tests/figs/creating-aesthetic-mappings/stat-count-width-0-5.svg index 361a604464..03be4ea394 100644 --- a/tests/figs/creating-aesthetic-mappings/stat-count-width-0-5.svg +++ b/tests/figs/creating-aesthetic-mappings/stat-count-width-0-5.svg @@ -19,9 +19,9 @@ - - - + + + diff --git a/tests/figs/creating-aesthetic-mappings/stat-count.svg b/tests/figs/creating-aesthetic-mappings/stat-count.svg index 9d7a1ecd7d..f6dc541233 100644 --- a/tests/figs/creating-aesthetic-mappings/stat-count.svg +++ b/tests/figs/creating-aesthetic-mappings/stat-count.svg @@ -19,9 +19,9 @@ - - - + + + diff --git a/tests/figs/creating-aesthetic-mappings/stat-identity-width-0-5.svg b/tests/figs/creating-aesthetic-mappings/stat-identity-width-0-5.svg index c210c3e35a..255ecba122 100644 --- a/tests/figs/creating-aesthetic-mappings/stat-identity-width-0-5.svg +++ b/tests/figs/creating-aesthetic-mappings/stat-identity-width-0-5.svg @@ -19,9 +19,9 @@ - - - + + + diff --git a/tests/figs/creating-aesthetic-mappings/stat-identity.svg b/tests/figs/creating-aesthetic-mappings/stat-identity.svg index 74ae75acc8..c767412876 100644 --- a/tests/figs/creating-aesthetic-mappings/stat-identity.svg +++ b/tests/figs/creating-aesthetic-mappings/stat-identity.svg @@ -19,9 +19,9 @@ - - - + + + diff --git a/tests/figs/geom-hline-vline-abline/cartesian-lines-intersect-mid-bars.svg b/tests/figs/geom-hline-vline-abline/cartesian-lines-intersect-mid-bars.svg index 033d756bac..36e6c691c0 100644 --- a/tests/figs/geom-hline-vline-abline/cartesian-lines-intersect-mid-bars.svg +++ b/tests/figs/geom-hline-vline-abline/cartesian-lines-intersect-mid-bars.svg @@ -19,11 +19,11 @@ - - - - - + + + + + diff --git a/tests/figs/geom-hline-vline-abline/flipped-lines-intersect-mid-bars.svg b/tests/figs/geom-hline-vline-abline/flipped-lines-intersect-mid-bars.svg index 1cf2e02a61..c542172c56 100644 --- a/tests/figs/geom-hline-vline-abline/flipped-lines-intersect-mid-bars.svg +++ b/tests/figs/geom-hline-vline-abline/flipped-lines-intersect-mid-bars.svg @@ -19,11 +19,11 @@ - - - - - + + + + + diff --git a/tests/figs/geom-violin/dodging-and-coord-flip.svg b/tests/figs/geom-violin/dodging-and-coord-flip.svg index b45e5a0e65..13d66d5863 100644 --- a/tests/figs/geom-violin/dodging-and-coord-flip.svg +++ b/tests/figs/geom-violin/dodging-and-coord-flip.svg @@ -49,11 +49,11 @@ x - + - + - + A B C diff --git a/tests/figs/geom-violin/dodging.svg b/tests/figs/geom-violin/dodging.svg index b37ca45d19..6de498da6c 100644 --- a/tests/figs/geom-violin/dodging.svg +++ b/tests/figs/geom-violin/dodging.svg @@ -49,11 +49,11 @@ x - + - + - + A B C diff --git a/tests/figs/geom-violin/grouping-on-x-and-fill-dodge-width-0-5.svg b/tests/figs/geom-violin/grouping-on-x-and-fill-dodge-width-0-5.svg index dada178542..0bb611dbc4 100644 --- a/tests/figs/geom-violin/grouping-on-x-and-fill-dodge-width-0-5.svg +++ b/tests/figs/geom-violin/grouping-on-x-and-fill-dodge-width-0-5.svg @@ -48,9 +48,9 @@ g - + - + e f grouping on x and fill, dodge width = 0.5 diff --git a/tests/figs/geom-violin/grouping-on-x-and-fill.svg b/tests/figs/geom-violin/grouping-on-x-and-fill.svg index a9d84cbf57..5e1615e261 100644 --- a/tests/figs/geom-violin/grouping-on-x-and-fill.svg +++ b/tests/figs/geom-violin/grouping-on-x-and-fill.svg @@ -48,9 +48,9 @@ g - + - + e f grouping on x and fill diff --git a/tests/figs/guides/legend-inside-plot-bottom-left-of-legend-at-center.svg b/tests/figs/guides/legend-inside-plot-bottom-left-of-legend-at-center.svg index a35ee3aedb..3ac5878494 100644 --- a/tests/figs/guides/legend-inside-plot-bottom-left-of-legend-at-center.svg +++ b/tests/figs/guides/legend-inside-plot-bottom-left-of-legend-at-center.svg @@ -19,9 +19,9 @@ - - - + + + @@ -49,11 +49,11 @@ x - + - + - + A B C diff --git a/tests/figs/guides/legend-inside-plot-bottom-left.svg b/tests/figs/guides/legend-inside-plot-bottom-left.svg index 1a08268309..5a975fe381 100644 --- a/tests/figs/guides/legend-inside-plot-bottom-left.svg +++ b/tests/figs/guides/legend-inside-plot-bottom-left.svg @@ -19,9 +19,9 @@ - - - + + + @@ -49,11 +49,11 @@ x - + - + - + A B C diff --git a/tests/figs/guides/legend-inside-plot-centered.svg b/tests/figs/guides/legend-inside-plot-centered.svg index 6274018d88..158ab3abe2 100644 --- a/tests/figs/guides/legend-inside-plot-centered.svg +++ b/tests/figs/guides/legend-inside-plot-centered.svg @@ -19,9 +19,9 @@ - - - + + + @@ -49,11 +49,11 @@ x - + - + - + A B C diff --git a/tests/figs/guides/legend-inside-plot-top-right.svg b/tests/figs/guides/legend-inside-plot-top-right.svg index 1f74bf01be..0fe7c38b9c 100644 --- a/tests/figs/guides/legend-inside-plot-top-right.svg +++ b/tests/figs/guides/legend-inside-plot-top-right.svg @@ -19,9 +19,9 @@ - - - + + + @@ -49,11 +49,11 @@ x - + - + - + A B C diff --git a/tests/figs/guides/padding-in-legend-box.svg b/tests/figs/guides/padding-in-legend-box.svg index f018da9241..8f1ff61213 100644 --- a/tests/figs/guides/padding-in-legend-box.svg +++ b/tests/figs/guides/padding-in-legend-box.svg @@ -19,9 +19,9 @@ - - - + + + @@ -49,11 +49,11 @@ x - + - + - + A B C diff --git a/tests/figs/legend-key-glyphs/time-series-and-polygon-key-glyphs.svg b/tests/figs/legend-key-glyphs/time-series-and-polygon-key-glyphs.svg index 01e6331fe9..9d4ae8141d 100644 --- a/tests/figs/legend-key-glyphs/time-series-and-polygon-key-glyphs.svg +++ b/tests/figs/legend-key-glyphs/time-series-and-polygon-key-glyphs.svg @@ -59,11 +59,11 @@ z - + - + - + a b c diff --git a/tests/figs/scales-breaks-and-labels/functional-limits.svg b/tests/figs/scales-breaks-and-labels/functional-limits.svg index 961969a880..b240537285 100644 --- a/tests/figs/scales-breaks-and-labels/functional-limits.svg +++ b/tests/figs/scales-breaks-and-labels/functional-limits.svg @@ -19,18 +19,18 @@ - - - - - - - - - - - - + + + + + + + + + + + + @@ -66,11 +66,11 @@ drv - + - + - + 4 f r diff --git a/tests/testthat/test-geom-tile.R b/tests/testthat/test-geom-tile.R index 46ee3094e9..f3ac11d189 100644 --- a/tests/testthat/test-geom-tile.R +++ b/tests/testthat/test-geom-tile.R @@ -26,3 +26,13 @@ test_that("accepts width and height aesthetics", { )) expect_equal(out[c("xmin", "xmax", "ymin", "ymax")], boundary) }) + +test_that("accepts linejoin parameter", { + df <- data_frame(x = c("a", "b"), y = c("a", "b")) + + gp1 <- layer_grob(ggplot(df, aes(x, y)) + geom_tile())[[1]]$gp + expect_equal(gp1$linejoin, "mitre") + + gp2 <- layer_grob(ggplot(df, aes(x, y)) + geom_tile(linejoin = "round"))[[1]]$gp + expect_equal(gp2$linejoin, "round") +})