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")
+})