I have the following data frame:
# Dummy data frame
df <- expand.grid(x = 1:3, y = 1:3)
I would like to plot it as a geom_tile
using ggplot2
like so:
# Tile plot
ggplot(df) +
geom_tile(aes(x = x, y = y),
fill = NA, colour = "red", size = 3, width = 0.7, height = 0.7)
which gives,
Notice, however, that in the top left corner of each tile there is a notch missing where the border doesn't quite dovetail correctly. I get the same result if I use geom_rect
. Is there a workaround to avoid this?
R version 3.5.1 (2018-07-02)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows 7 x64 (build 7601) Service Pack 1
Matrix products: default
attached base packages:
[1] stats graphics grDevices utils datasets methods base
other attached packages:
[1] ggplot2_3.1.0 kitchendraw_0.1.0
loaded via a namespace (and not attached):
[1] Rcpp_1.0.0 rstudioapi_0.8 bindr_0.1.1 magrittr_1.5 tidyselect_0.2.5 munsell_0.5.0 colorspace_1.3-2
[8] R6_2.3.0 rlang_0.3.0.1 plyr_1.8.4 dplyr_0.7.7 tools_3.5.1 grid_3.5.1 gtable_0.2.0
[15] withr_2.1.2 yaml_2.2.0 lazyeval_0.2.1 assertthat_0.2.0 tibble_1.4.2 crayon_1.3.4 bindrcpp_0.2.2
[22] purrr_0.2.5 glue_1.3.0 labeling_0.3 compiler_3.5.1 pillar_1.3.0 scales_1.0.0 pkgconfig_2.0.2
As others have noted, this is due to the lineend specification, which can be found in environment(GeomTile$draw_panel)$f
:
function (self, data, panel_params, coord)
{
if (!coord$is_linear()) {
... #omitted for space
}
else {
coords <- coord$transform(data, panel_params)
ggname("geom_rect",
rectGrob(coords$xmin, coords$ymax,
width = coords$xmax - coords$xmin, height = coords$ymax -
coords$ymin, default.units = "native", just = c("left", "top"),
gp = gpar(col = coords$colour,
fill = alpha(coords$fill, coords$alpha),
lwd = coords$size * .pt,
lty = coords$linetype,
lineend = "butt"))) # look here
}
}
The creation of a geom_tile
layer is powered by rectGrob
, with a hard-coded lineend
parameter value of "butt". The graphic below (found here) illustrates the difference between the 3 lineend
values nicely:
If you feel like digging into the underlying GeomTile
's functions and changing the graphics parameters for all geom_tile
layers in your code, you can do that. (I answered a similar question recently with that solution.) For a single plot, though, I'd just convert the ggplot to a grob object, & mess with the gp
parameters there instead:
library(grid)
gp <- ggplotGrob(p)
grid.draw(gp)
# this "sharpens" the top left corner
gp$grobs[[which(grepl("panel", gp$layout$name))]]$children[[3]]$gp$lineend <- "square"
grid.draw(gp)
# this further "sharpens" the other three corners
gp$grobs[[which(grepl("panel", gp$layout$name))]]$children[[3]]$gp$linejoin <- "mitre"
grid.draw(gp)
Note: the actual location of the correct grob corresponding to geom_tile
is not necessarily going to be gp$grobs[[which(grepl("panel", gp$layout$name))]]$children[[3]]$gp$linejoin
. It's children[[3]]
here, but having other geom layers in the ggplot object, either under or above the geom_tile
layer, can shift its relative position. In that case, you may want to check the output from gp$grobs[[which(grepl("panel", gp$layout$name))]]$children
in the console to identify the correct position number.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With