角落缺少geom_tile边框

时间:2018-12-13 18:06:56

标签: r ggplot2

我有以下数据框:

# Dummy data frame
df <- expand.grid(x = 1:3, y = 1:3)

我想像这样使用geom_tile将其绘制为ggplot2

# Tile plot
ggplot(df) + 
  geom_tile(aes(x = x, y = y), 
            fill = NA, colour = "red", size = 3, width = 0.7, height = 0.7)

给出

enter image description here

但是,请注意,在每个图块的左上角都缺少一个缺口,该缺口的边界与边界不完全吻合。如果使用geom_rect,则会得到相同的结果。有一种解决方法可以避免这种情况?


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 

根据以下评论更新的数字

enter image description here

3 个答案:

答案 0 :(得分:4)

我认为这是因为每一行的起点就是这样:一个点。并且由于行的大小使行更粗,因此此起点使该空格成为空白。此图使用四个geom_segment来构成一个正方形,结果表明您遇到了相同的问题:

ggplot(df) + 
   geom_segment(x = 1, y = 1, xend = 2, yend = 1, size = 3) +
   geom_segment(x = 1, y = 1, xend = 1, yend = 2, size = 3) +
   geom_segment(x = 1, y = 2, xend = 2, yend = 2, size = 3) +
   geom_segment(x = 2, y = 2, xend = 2, yend = 1, size = 3) +
   scale_x_continuous(limits = c(0, 3)) + 
   scale_y_continuous(limits = c(0, 3))

square with blank spaces

我能想到的唯一解决方案是使x或y轴之一的起点和终点稍稍落后(起点)和前方(终点)。这种解决方案远非理想,但我只能想到。对于size = 3行,我发现减去和向起点和终点添加0.01可以填充空白:

ggplot(df) + 
 geom_segment(x = 1-0.01, y = 1, xend = 2+0.01, yend = 1, size = 3) +
 geom_segment(x = 1, y = 1, xend = 1, yend = 2, size = 3) +
 geom_segment(x = 1-0.01, y = 2, xend = 2+0.01, yend = 2, size = 3) +
 geom_segment(x = 2, y = 2, xend = 2, yend = 1, size = 3) +
 scale_x_continuous(limits = c(0, 3)) + 
 scale_y_continuous(limits = c(0, 3))

square without blank spaces

但是,该解决方案也不理想,因为该值应根据行的大小和所显示图形的比例而改变。


编辑:geom_path()连接正方形的角而没有留出空格,但是问题仍然存在于直线与原点相交的地方:

 df <- data.frame(
       x = c(1, 1, 2, 2, 1),
       y = c(1, 2, 2, 1, 1)
       )

 ggplot(df, aes(x, y)) + 
       geom_path(size = 3, linejoin = "mitre") +
       scale_x_continuous(limits = c(0, 3)) +
       scale_y_continuous(limits = c(0, 3))

enter image description here

答案 1 :(得分:4)

正如其他人所指出的,这归因于行尾规范,可以在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
    }
}

geom_tile层的创建由rectGrob支持,其硬编码的lineend参数值为“ butt”。下图(找到https://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.peak_widths.html)很好地说明了三个lineend值之间的差异:

here

如果您想深入研究底层GeomTile的功能并更改代码中所有geom_tile层的图形参数,则可以这样做。 (我最近通过该解决方案回答了类似的lineend values。)但是,对于单个绘图,我只是将ggplot转换为grob对象,并使用那里的gp参数搞乱了:

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)

question

# this further "sharpens" the other three corners
gp$grobs[[which(grepl("panel", gp$layout$name))]]$children[[3]]$gp$linejoin <- "mitre"
grid.draw(gp)

plot after changing line end

注意:与geom_tile相对应的正确grob的实际位置不一定是gp$grobs[[which(grepl("panel", gp$layout$name))]]$children[[3]]$gp$linejoin。这里是children[[3]],但是ggplot对象中的其他geom层位于geom_tile层之下或之上,可以移动其相对位置。在这种情况下,您可能需要检查控制台中gp$grobs[[which(grepl("panel", gp$layout$name))]]$children的输出,以识别正确的位置编号。

答案 2 :(得分:1)

此问题已由this update修复为ggplot2