rggplot2gridr-forestplotpatchwork

Draw a common vertical line to two plots with R , patchwork and probably GRID package


I'm trying to make a "forest" plot using the ggplot2 package, patchwork, and grid package. The only visual element that I could not add to my current plot is a vertical line over both of the figures. Any help is appreciated.

I'm wondering how I can do this trick.

That's what I have right now
enter image description here

That's what I want
enter image description here

That's what I got
enter image description here

codes are here -- you'll need to load tidyverse, patchwork, and grid packages.

library(tidyverse)
library(patchwork)
library(grid)

df2 = data.frame(gender = c("male", "female"), age = c("teenager", "adult"), math = rnorm(100,0,0.3))
df2 = df2 %>% mutate(math = if_else(age == "adult", math+0.2, math))
p1 = df2 %>%
  ggplot(. , aes(x = gender, y = math)) +
  stat_summary(fun.data = mean_cl_boot,geom = "errorbar") +
  coord_flip() +
  theme_minimal()+
  theme(
    axis.title.x = element_blank(),
    axis.text.x = element_blank(),
    axis.ticks.x = element_blank(),
    panel.grid.major = element_blank(),
    panel.grid.minor = element_blank()
  )
p2 = df2 %>%
  ggplot(. , aes(x = age, y = math)) +
  stat_summary(fun.data = mean_cl_boot,geom = "errorbar") +
  coord_flip() +
  theme_minimal()+
  theme(
    panel.grid.major = element_blank(),
    panel.grid.minor = element_blank()
  ) 
p1/p2
grid.draw(linesGrob()linesGrob(x = unit(c(0,1), "npc"), y = unit(c(0, 1), "npc")))

Solution

  • If I were you, I will do it via geom_hline with facet rather than grid.draw because the value of x-axis = 0 in grob would change when you resize the plot.

    geom_hline

    library(tidyverse)
    
    df2 = data.frame(gender = c("male", "female"), age = c("teenager", "adult"), math = rnorm(100,0,0.3))
    df2 = df2 %>% mutate(math = if_else(age == "adult", math+0.2, math))
    
    pivot_longer(df2, gender:age) |> 
      ggplot(aes(x = value, y = math)) +
      stat_summary(fun.data = mean_cl_boot,geom = "errorbar") +
      facet_grid(name~., space = "free", scale = "free", switch = "y") +
      geom_hline(yintercept = 0, color = "darkslategray3") +
      coord_flip() +
      theme_minimal()+
      theme(
        panel.grid.major = element_blank(),
        panel.grid.minor = element_blank(),
        panel.spacing.y = unit(-0.1, "lines"),
        axis.title.y = element_blank(),
        strip.placement = "outside"
      ) 
    

    linesGrob

    The problem with your plot is that you want a vertical line, so the x in linesGrob should be a single value at x-axis = 0 rather than c(0, 1). You can play around with the value, currently I'm using x = 0.291 to get it at the right position.

    library(dplyr)
    library(ggplot2)
    library(patchwork)
    library(grid)
    library(gridExtra)
    
    df2 = data.frame(gender = c("male", "female"), age = c("teenager", "adult"), math = rnorm(100,0,0.3))
    df2 = df2 %>% mutate(math = if_else(age == "adult", math+0.2, math))
    p1 = df2 %>%
      ggplot(. , aes(x = gender, y = math)) +
      stat_summary(fun.data = mean_cl_boot,geom = "errorbar") +
      coord_flip() +
      theme_minimal()+
      theme(
        axis.title.x = element_blank(),
        axis.text.x = element_blank(),
        axis.ticks.x = element_blank(),
        panel.grid.major = element_blank(),
        panel.grid.minor = element_blank()
      )
    p2 = df2 %>%
      ggplot(. , aes(x = age, y = math)) +
      stat_summary(fun.data = mean_cl_boot,geom = "errorbar") +
      coord_flip() +
      theme_minimal()+
      theme(
        panel.grid.major = element_blank(),
        panel.grid.minor = element_blank()
      ) 
    
    p1/p2
    
    grid.draw(linesGrob(x = 0.291, "npc", y = unit(c(0, 1), "npc"), gp = gpar(col = "darkslategray3")))
    

    linesGrob