imd 统计教程 · 统计图表与论文表格
← 教程首页 返回本模块

森林图(forest plot)-全套路与珍藏级美图

聂志强 超磊实战医学统计2022-08-12 11:40:14广东


初识森林图(Forest plot),依稀记得是大学时候Meta分析课程。后来阅读SCI后发现,越来越多论文中用森林图来取代多因素回归做结果展示,包括主效应、交互作用、分层分析等,展现形式也愈发多样化。正巧最近论文修回需要用到一些高阶段位森林图,那这期笔者就打算盘它了,将常见original article森林图套路分享如下。友情提示,本章图片较多请耐心阅读。

一、原理

多因素结果的森林图与meta分析森林图形态近似,最大区别是没有文献合并效应量。多因素森林图在平面直角坐标系中,以一条垂直于X轴的无效线(通常坐标X=1[对应OR、RR、HR等分类型effect size]或0[对应RD、AD、β等连续型effect size])为中心,用若干条平行于X轴的线段,来表示每个变量的效应量大小及其95%可信区间。简而言之,就是Effect size 图形化。

二、SCI套路

人狠话不多,直接上套路。


三、R代码

窈窕淑女,君子好逑。掌握本章节介绍的forestplot、forestploter、ggforestplot、以及ggplot2,小伙伴们就拥有了再进一步拥抱高水平论文的可能性。小伙伴们可以阅读后自行DIY各杂志的主题色。

1. forestplot包 

此包是较成熟且较早期的包,折腾后实现功能有限,不过重在便捷。

library('ggplot2'
setwd("D:/聂个人文件/我的公众号/森林图")

#-------① 经典款 带空格 森林图绘制,forest_model2.xlsx

#------- 1.forestplot包,仅亚组
library(forestplot)
library(readxl)
library(haven)
forest <- read_excel("forest_model2.xlsx",sheet = "subgroup")
#subgps缩进
subgps <- c(3,4,7,8,11,12,15,16,19,20,23,24,25,26) 
forest$Variable[subgps] <- paste("    ",forest$Variable[subgps])  
attach(forest)
labeltext <- as.matrix(forest[,1:2]) 
#设定字体
windowsFonts(myFont1 = windowsFont("Times New Roman")) 
forestplot(labeltext,  
           mean = OR,   #分类effect size
           lower = LowerCI,         
           upper = UpperCI,
           zero = 1.0, lwd.zero = 2, # 参考线X=1,粗2
           xlab = "←Low risk          High risk →"#x标签
           xticks = c(0,1,2,3),  
           lwd.xaxis = 2, 
           boxsize = 0.5, #设置中心大小 
           lty.ci = 1, lwd.ci = 2, #设置区间估计线的"solid",粗细
           col=fpColors(box='#6495ED',summary="#8B008B",lines = '#98C9F6',zero = '#000000'),
           #颜色从左至右分别点估计方形,汇总值,区间估计线'black',参考线   橙色#FFDD00
           ci.vertices = TRUE,   
           ci.vertices.height = 0.2, 
           align = "l",  
           is.summary= c(T,T,F,F,F,T,F,F,F,T,F,F,F,T,F,F,F,T,F,F,F,T,F,F,F,F),  
           #每一行是否是汇总值,粗体, all时会变紫色
           txt_gp = fpTxtGp(label = gpar(cex = 1.15, fontfamily="myFont1"), 
                            ticks = gpar(cex = 1.20),
                            xlab = gpar(cex = 1.45)),
           grid= T, #在x轴对应的单位间隔上做垂直的虚线参考线
           graphwidth = unit(6,"cm"), #调节95%可信区间作图的宽度
           graph.pos = 3 ) #设置森林图的位置,此处设置为3,则出现在第3列


#------- 2.forestplot包,all+ 亚组
pacman::p_load(forestplot,readxl,haven)
forest <- read_excel("forest_model2.xlsx",sheet = "allsub")
#subgps缩进
subgps <- c(1,2,4,5,6,8,9,10,12,13,14,16,17,18,20,21,22,24,25,26,27,28) 
forest$Variable[subgps] <- paste("    ",forest$Variable[subgps])  
attach(forest)
#文本展示前2列
labeltext <- as.matrix(forest[,1:2]) 
#设定字体
windowsFonts(myFont1 = windowsFont("Times New Roman")) 
forestplot(labeltext,  
           mean = OR,   #分类effect size
           lower = LowerCI,         
           upper = UpperCI,
           zero = 1.0, lwd.zero = 2, # 参考线X=1,粗2
           xlab = "←Low risk          High risk →"#x标签
           xticks = c(0,1,2,3),  
           clip=c(0,3),#设置 CI显示的上下限,超过变箭头,适用于异常OR HR
           lwd.xaxis = 2, #x垂直线粗细
           boxsize = 0.5, #设置中心大小 
           lineheight = unit(6,'mm'),#设置图形中的行距
           colgap = unit(2,'mm'),#设置图形中的列间距
           lty.ci = 1, lwd.ci = 2, #设置区间估计线的"solid",粗细
           col=fpColors(box='#6495ED',summary="#8B008B",lines = '#98C9F6',zero = '#000000'),
           #颜色从左至右分别点估计方形,汇总值,区间估计线'black',参考线   橙色#FFDD00
           ci.vertices = TRUE,   
           ci.vertices.height = 0.3, #CI端天线高度
           align = "l",  
           is.summary= c(T,T,F,T,F,F,F,T,F,F,F,T,F,F,F,T,F,F,F,T,F,F,F,T,F,F,F,F),  
           #每一行是否是汇总值,其实仅表现粗体
           txt_gp = fpTxtGp(label = gpar(cex = 1.2, fontfamily="myFont1"), 
                            ticks = gpar(cex = 1.2),
                            xlab = gpar(cex = 1.2)),
           grid= F, #在x轴对应的单位间隔上做垂直的虚线参考线
           graphwidth = unit(6,"cm"), #调节95%可信区间作图的宽度
           graph.pos = 3 ) #设置森林图的位置,此处设置为3,则出现在第3列

#------- 3.forestplot包,all+ 亚组+多列
pacman::p_load(forestplot,readxl,haven)
forest <- read_excel("forest_model2.xlsx",sheet = "casen")
#subgps缩进
subgps <- c(1,2,4,5,6,8,9,10,12,13,14,16,17,18,20,21,22,24,25,26,27,28) 
forest$Variable[subgps] <- paste("    ",forest$Variable[subgps])  
attach(forest)
#文本展示前3列
labeltext <- as.matrix(forest[,1:3]) 
#设定字体
windowsFonts(myFont1 = windowsFont("Times New Roman")) 
forestplot(labeltext,  
           mean = OR,   #分类effect size
           lower = LowerCI,         
           upper = UpperCI,
           zero = 1.0, lwd.zero = 2, # 参考线X=1,粗2
           xlab = "←Low risk          High risk →"#x标签
           xticks = c(0,1,2,3),  
           clip=c(0,3),#设置 CI显示的上下限,超过变箭头,适用于异常OR HR
           lwd.xaxis = 2, #x垂直线粗细
           boxsize = 0.5, #设置中心大小 
           lineheight = unit(6,'mm'),#设置图形中的行距
           colgap = unit(2,'mm'),#设置图形中的列间距
           lty.ci = 1, lwd.ci = 2, #设置区间估计线的"solid",粗细
           col=fpColors(box='#6495ED',summary="#FF0000",lines = '#98C9F6',zero = '#000000'),
           #颜色从左至右分别点估计方形,汇总值,区间估计线'black',参考线   橙色#FFDD00
           ci.vertices = TRUE,   
           ci.vertices.height = 0.3, #CI端天线高度
           align = "l",  
           is.summary= c(T,T,F,T,F,F,F,T,F,F,F,T,F,F,F,T,F,F,F,T,F,F,F,T,F,F,F,F),  
           #每一行是否是汇总值,其实仅表现粗体
           txt_gp = fpTxtGp(label = gpar(cex = 1.2, fontfamily="myFont1"), 
                            ticks = gpar(cex = 1.2),
                            xlab = gpar(cex = 1.2)),
           grid= F, #在x轴对应的单位间隔上做垂直的虚线参考线
           graphwidth = unit(6,"cm"), #调节95%可信区间作图的宽度
           graph.pos = 3 ) #设置森林图的位置,此处设置为3,则出现在第3列



#------- 4.forestplot包,all+ 亚组+多列+ 无空格
pacman::p_load(forestplot,readxl,haven)
forest <- read_excel("forest_model2.xlsx",sheet = "noblank")
#subgps缩进
subgps <- c(4,5,7,8,10,11,13,14,16,17,19,20,21,22) 
forest$Variable[subgps] <- paste("    ",forest$Variable[subgps])  
attach(forest)
#文本展示前3列
labeltext <- as.matrix(forest[,1:3]) 
#设定字体
windowsFonts(myFont1 = windowsFont("Times New Roman")) 
forestplot(labeltext,  
           mean = OR,   #分类effect size
           lower = LowerCI,         
           upper = UpperCI,
           zero = 1.0, lwd.zero = 2, # 参考线X=1,粗2
           xlab = "←Low risk          High risk →"#x标签
           xticks = c(0,1,2,3),  
           clip=c(0,3),#设置 CI显示的上下限,超过变箭头,适用于异常OR HR
           lwd.xaxis = 2, #x垂直线粗细
           boxsize = 0.5, #设置中心大小 
           lineheight = unit(6,'mm'),#设置图形中的行距,默认6mm
           colgap = unit(2,'mm'),#设置图形中的列间距
           lty.ci = 1, lwd.ci = 2, #设置区间估计线的"solid",粗细
           col=fpColors(box='#6495ED',summary="#FF0000",lines = '#98C9F6',zero = '#000000'),
           #颜色从左至右分别点估计方形,汇总值,区间估计线'black',参考线   橙色#FFDD00
           ci.vertices = TRUE,   
           ci.vertices.height = 0.3, #CI端天线高度
           align = "l",  
           #区别在summary,加粗合并
           is.summary= c(T,T,T,F,F,T,F,F,T,F,F,T,F,F,T,F,F,T,F,F,F,F),  
           #每一行是否是汇总值,其实仅表现粗体
           txt_gp = fpTxtGp(label = gpar(cex = 1.2, fontfamily="myFont1"), 
                            ticks = gpar(cex = 1.2),
                            xlab = gpar(cex = 1.2)),
           grid= F, #在x轴对应的单位间隔上做垂直的虚线参考线
           graphwidth = unit(6,"cm"), #调节95%可信区间作图的宽度
           graph.pos = 3 ) #设置森林图的位置,此处设置为3,则出现在第3列



2. forestploter包

笔者将珍藏级主题放出,感兴趣的小伙伴自行重现,才能学的深刻。



#-------  5 forestploter包绘制,casen_name数据,无空格,有空行会出现NA, 
# install.packages("devtools")
# devtools::install_github("adayim/forestploter")
pacman::p_load(forestploter,readxl,haven)
forest<- read_excel("forest_model2.xlsx",sheet = "casen_name")
#第二种缩进方法,更智能
forest$Subgroups <- ifelse(is.na(forest$"Event/patients"),
                       forest$Subgroups,
                       paste0("      ", forest$Subgroups))

#再创建一列空列,用来后面存放森林图的图形部分,长度20
forest$` ` <- paste(rep(" ", 20), collapse = " ")

#本段自动 OR95%CI 拼接
# forest$`OR (95% CI) AUTO` <- ifelse(is.na(forest$OR), "",sprintf("%.2f (%.2f to %.2f)",forest$OR, forest$LowerCI, forest$UpperCI))

#这里要注意,保留前3列信息+空白列!
# 注意,NA 需要转换为空白!.
forest$"Event/patients" <- ifelse(is.na(forest$"Event/patients"), "", forest$"Event/patients")
forest$"OR (95%Cl)" <- ifelse(is.na(forest$"OR (95%Cl)"), "", forest$"OR (95%Cl)")

plot1 <- forest(forest[, c(1:3,7)],
               est = forest$OR,
               lower = forest$LowerCI,
               upper = forest$UpperCI,
               ci_column = 4,
               # sizes=forest$OR, #等比例放大方框,不美观
               # is_summary=c(TRUE,rep(FALSE, nrow(forest)-1)), #第一行汇总
               # is_summary=c(rep(FALSE, nrow(forest)-1),TRUE), #最后一行汇总
               ref_line = 1, #参考线x=1
               arrow_lab = c("Low risk""High risk"),
               xlim = c(0, 3),ticks_at = c(0, 1, 2, 3)#设置X范围,超范围带箭头 
               )
plot1

3. ggplot2包

全部自定义,后期PDF转PPT后需要手动编辑对齐。

4. ggforestplot包

如果risk很多>20个,需要一起展示,那请毫不犹豫的用吧。


四、小结

森林图R包很多很多,不光有forestploter、forestplot、ggforestplot,其实还有forplo、survminer::ggforest()函数等偏门的包。本章并未详细介绍meta的森林图,请小伙伴一切按论文需求,选择最优图形。如果有不会R的小伙伴,请关注下期更加友好的Excel篇。

参考文献:

  1. DOI: 10.1002/cam4.2254
  2. DOI https://doi.org/10.1200/JCO.19.00010
  3. Saez-Atienzar et al., Sci. Adv. 2021
  4. DOI: 10.1038/s41467-018-05914-x
  5. doi:10.1093/eurheartj/ehu116
  6. DOI: 10.1200/JCO.2015.65.7825
  7. http://dx.doi.org/10.5339/gcsp.2015.33
  8. doi: 10.1016/j.bone.2013.05.009
  9. Nie Z, Yang B, Ou Y, Bloom MS, Han F, Qu Y, Nasca P, Matale R, Mai J, Wu Y, Gao X, Guo Y, Markevych I, Zou Y, Lin S, Dong G, Liu X. Maternal residential greenness and congenital heart defects in infants: A large case-control study in Southern China. Environ Int. 2020 Sep;142:105859. doi: 10.1016/j.envint.2020.105859. Epub 2020 Jun 25. PMID: 32593836.
  10. ggforestplot安装请看:https://blog.csdn.net/weixin_44022515/article/details/122022228



原创不易,转载请说明来自本公众号。