Grobs 根本没有绘制或位置错误

Grobs are not plotted at all or in wrong position

我无法理解如何将 grob 放入绘图区域。 这是我的意思的一个例子。 假设我有以下情节。

library(tidyverse)
p <- mpg %>%
  ggplot(aes(year)) +
  geom_bar() 
p

我知道我可以从中得到一个 grobs 列表并像这样绘制它。

l <- ggplotGrob(p)
grid::grid.newpage()
grid::grid.draw(l)

从列表l的结构我也了解到矩形是画成rectGrob的。我在

中找到了这些
grobs <- l$grobs[[6]]
rect_grobs <- grobs$children[[3]]

但是如果我想使用直接来自 rect_grobs 的数据绘制至少一个矩形,什么也不会发生。这与我是否使用 grid::grid.newpage() 创建新的 canvas 无关。

# This draws nothing
grid::grid.draw(
  grid::rectGrob(
    x = rect_grobs$x[1],
    y = rect_grobs$y[1],
    height = rect_grobs$height[1],
    width = rect_grobs$width[1],
    just = rect_grobs$just[1],
  )
)

然而,如果我手动插入 rect_grobs 中的值,则会在错误的位置绘制一个矩形。我怀疑这与视口有关,但我尝试查看 lgrobsrect_grobs,但我不知道这样设置的视口是什么。我看的地方只有vp = NULL.

# This draws in wrong position
grid::grid.draw(
  grid::rectGrob(
    x = 0.0455,
    y = 0.955,
    width = 0.431,
    height = 0.909,
    just = 'left'
  )
)

所以,我的问题是

  1. 如果我直接从 rect_grobs 列表中获取值,为什么代码不绘制矩形?
  2. 如果我手动添加矩形,如何将它放到正确的位置?

rect_grobs不画的原因确实是没有viewport。如果一个 grob 没有设置视口,它将从它的父级继承,但是因为你已经从 gTable 中取出它,它没有父级。这很容易通过给它一个默认视口来纠正:

rect_grobs$vp <- grid::viewport()
grid::grid.draw(rect_grobs)

只要我们指定正确的just,我们就在同一个地方得到了矩形:

red_rect <-   grid::rectGrob(
    x = 0.0455,
    y = 0.955,
    width = 0.431,
    height = 0.909,
    just = c("left", "top"),
    gp = grid::gpar(fill = "red")
  )

grid::grid.draw(red_rect)

但是,这不是矩形在 ggplot 中的位置。那是因为在 ggplot 中,面板有自己的视口。要在此上下文中绘制矩形,我们需要在调用 grid.draw

之前导航到正确的视口
plot(p)

grid::seekViewport(grid::vpPath("layout", "panel.7-5-7-5"))

grid::grid.draw(red_rect)