如何在ggplot上画一个grob?

How to draw a grob on top of ggplot?

我有一个 grob 对象(在我的例子中是 euler 绘图)和一个 ggplot 对象,我想将一个对象放在另一个对象之上,例如:

library(eulerr)
library(ggplot2)

df <- data.frame(a=sample(100),b=sample(50:149), c=sample(20:119))
venn <- euler(list(
  A=df$a,
  B=df$b[1:50],
  C=df$c
), shape='ellipse')

p_v <- plot(venn, quantities = T, fills=c('red','green','blue'))
p_g <- ggplot(df, aes(x=a,y=b)) + geom_point()

# Now I want somehow to draw p_v on top of p_g
p_g + p_v

应该产生这样的东西:

例如,我尝试使用 ggplotify,但找不到摆脱在第二个绘图中绘制为 canvas 的白色矩形的方法...

你可以使用 annotation_custom:

p_g + annotation_custom(p_v, xmin  = 0, xmax = 50, ymin = 80, ymax = 150)

如果您希望它与对数轴刻度一起使用,您将需要使用 grid 直接在 p_g 上绘制 p_v。您首先需要将其放入 grobtree 中,以便您可以指定其位置和尺寸:

p_g <- ggplot(df, aes(x=a,y=b)) + geom_point() + scale_y_log10()

p_g 
grid::grid.draw(
  grid::grobTree(p_v$children,
                 vp = grid::viewport(x = unit(0.3, "npc"), 
                                     y = unit(0.7, "npc"), 
                                     width = unit(0.4, "npc"), 
                                     height = unit(0.5, "npc"))))

如果你想把它作为一个单独的 R 对象,你可以这样做:

obj <- grid::grobTree(ggplotGrob(p_g), grid::grobTree(p_v$children,
                 vp = grid::viewport(x = unit(0.3, "npc"), 
                                     y = unit(0.7, "npc"), 
                                     width = unit(0.4, "npc"), 
                                     height = unit(0.5, "npc"))))

所以 obj 现在是你的整个画面的 grob

另一种方法是使用包 ggpmisc:

中的 geom_grob
library(ggpmisc)

ggplot(df, aes(x=a,y=b)) + 
  geom_point() + 
  geom_grob(aes(x = 12.5, y = 100, label = list(p_v$children$canvas.grob)),
            vp.width = 0.3, vp.height = 0.4) +
  scale_y_log10()