rggplot2grobeulerr

How to draw a grob on top of ggplot?


I have a grob object (in my case it's euler plot) and a ggplot object, and I want to place one on top of another, for example:

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

Should produce something like this: overlayed plot

I tried using ggplotify for example but couldn't find a way to get rid of white rectangle that was drawn as a canvas for the second plot...


Solution

  • You could use annotation_custom:

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

    enter image description here

    If you want this to work with log axis scales, you will need to use grid to directly draw p_v over p_g. You will first need to put it in a grobtree so that you can specify its position and dimensions:

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

    enter image description here

    If you want this as a single R object, you can do:

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

    So that obj is now a grob of your whole picture.

    One further way to do this would be using geom_grob from package ggpmisc:

    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()
    

    enter image description here