Home > OS >  Combine several forestplot object in one graph in R
Combine several forestplot object in one graph in R

Time:02-26

All is in the question. I tried to transform the forestplot objects into ggplot object in order to use the ggarrange() function but it doesn't work. I also tried the as.grob() function or viewport(), but unsuccessfully. I describe below the two forest plots that I want to combine in one plot:

library(forestplot)
library(tidyverse)

#Estimate
est1=data.frame(model="multivariable model",
                variable=c("v1","v2","v3"),
                hr=c(1,2,3),
                low=c(0,1,2),
                high=c(2,3,4),
                p.value= rep(0.0123,3))
est2 = data.frame( model="univariable model",
                   variable=c("v1","v2","v3"),
                   hr=c(1,2,3),
                   low = c(0,1,2),
                   high=c(2,3,4),
                   p.value= rep(0.0123,3))


est= rbind(est1,est2) %>%
  mutate(variable= factor(variable,levels=c("v2","v3", "v1")),
                                 model= factor(model,levels=c("univariable model", "multivariable model"))) %>% arrange(variable,model)
#sheet4
forestplot_neutr = est

#Table text
tabletext <- cbind(c("Variables","v1","v2","v3"),
                   c('Baseline', c("low", "low", "low")),
                   c("Subcategory","high", "high", "high"), 
                   c("p-value", est %>% mutate(p.value=sub("0 $", "", as.character(signif(p.value,digits=2)))) %>%
                       group_by(variable) %>% summarize(p.value=str_c(p.value,collapse = "\n")) %>% pull(p.value)))

# adjust text size of forestplot
own <- fpTxtGp()
own$title$cex <-1
own <- fpTxtGp(label = gpar(cex=1.05), ticks = gpar(cex=1), summary=gpar(cex=1), xlab =gpar(cex=1), legend = gpar(cex=1),
               legend.title = gpar(cex=1), title = gpar(cex=1.5))

#Forest plot
p1 <- forestplot(tabletext, graph.pos=4, align = c("l","l","l","l"),
           legend =  c( "univariable", "multivariable"),
           legend_args = fpLegend(pos = list(x=.4, y=0.98), 
                                  gp=gpar(col="#CCCCCC", fill="#F9F9F9")),
           mean = cbind(c(NA,est %>% filter(model=="univariable model") %>% pull(hr)), 
                        c(NA,est %>% filter(model=="multivariable model") %>% pull(hr))),
           lower = cbind(c(NA,est %>% filter(model=="univariable model") %>% pull(low)),
                         c(NA,est %>% filter(model=="multivariable model") %>% pull(low))),
           upper = cbind(c(NA,est %>% filter(model=="univariable model") %>% pull(high)),
                         c(NA,est %>% filter(model=="multivariable model") %>% pull(high))),
           is.summary=c(TRUE,rep(FALSE,3)),
           txt_gp = own, 
           #hrzl_lines= gpar(lwd=1, columns=1:6, col = "#99999922", "leftbind"),
           title="",     
           xlab="Hazard Ratio",
           clip= c(0.1,6) , zero = 1, lineheight = unit(2.5,"cm"),boxsize= c(0.1),
           grid = structure(c(1), gp = gpar(lty = 1, col = "black")),
           graphwidth = unit(8, "cm"),
           colgap=unit(8,"mm"),lwd.ci=2, ci.vertices=TRUE, ci.vertices.height = 0.1,
           col=fpColors(box=c('gray', "black"), lines = c('gray', "black")),
           xticks = c(0.1,0.2,0.5,1,2,5,10,20),xlog=T) #5-12

#Second forest plot
p2 = p1

#How to combine forest plots?????????????????

CodePudding user response:

This is tricky, since the forestplot objects are not actually grid grobs or ggplot objects, but rather S3 objects which contain the "ingredients" that are only "baked" into grobs when print is called on them. There is a way round this, which is to use ggplotify and patchwork to convert them to grobs, wrap them as plot objects, then arrange them.

library(ggplotify)
library(patchwork)

p1 <- grid2grob(print(p1))
p2 <- grid2grob(print(p2))
p_both <- wrap_elements(p1) / wrap_elements(p2)
p_both

enter image description here

Note that these objects also seem to have a fixed size measured in absolute units, rather than the "npc" or "native" units that allow for flexible aspect ratios in ggplot. This means that I had to save the produced plot using ggsave with a height of 1024 pixels at 96 dpi to get both plots in a single image. Effectively, there is no benefit to stacking these plots in R compared to stitching them together in a graphics application. You might like to check out alternatives such as ggforest.

  • Related