草庐IT

R语言使用forestploter包绘制单组及双组森林图(2)(附有超详细备注)

天桥下的卖艺者 2023-08-08 原文

森林图在论文中很常见,多用于表示多因素分析中的变量与结果变量的比值效应,可以用图示的方法比较直观的绘制出来。既往我们在文章《R语言快速绘制多因素回归分析森林图(1)》已经介绍了怎么绘制森林图,但是绘图比较简单,不够美观,不能绘制相对复杂的森林图。今天我们来介绍一下forestploter包,它等于是在forestplot包的基础上进一步强化功能,制作方法也相对简单一点,而且加强了对图形的精细控制,而且可以绘制单组和多组森林图。

我们先导入R包和数据

library(grid)
library(forestploter)
dt<-read.csv("E:/r/test/forest2.csv",sep=',',header=TRUE)


这是一个森林图数据(公众号回复:森林图数据2,可以获得数据)这个数据,嫌麻烦的可以在这里下载:https://download.csdn.net/download/dege857/86945654?spm=1001.2014.3001.5501
前几个变量我解释一下Subgroup:分组,就是的组别和亚组,Treatment:治疗组例数,Placebo:使用安慰剂,也就是对照组的例数。Est:效应值,可以是OR或者HR,low:效应值的最低值,可以认为是可信区间的下限,hi:效应值的最高值,可以认为是可信区间的上限。
我们先来画一个最基础的森林图,后面的几个数据暂时不需要,我们先精简一下数据

dt <- dt[,1:6]
View(dt)


数据变成了一个精简的数据(上图),我们先把数据格式整理一下,先让它缩进一格

dt$Subgroup <- ifelse(is.na(dt$Placebo), 
                      dt$Subgroup,
                      paste0("   ", dt$Subgroup))


接下来我们把治疗组和对照组NA(有缺失)的地方变成一个空格

dt$Treatment <- ifelse(is.na(dt$Treatment), "", dt$Treatment)
dt$Placebo <- ifelse(is.na(dt$Placebo), "", dt$Placebo)


生成一个变量se,它在绘图的时候表示正方形的大小

dt$se <- (log(dt$hi) - log(dt$est))/1.96

生成一个绘图区间,等下用来绘图

dt$` ` <- paste(rep(" ", 20), collapse = " ")

生成HR和可信区间

dt$`HR (95% CI)` <- ifelse(is.na(dt$se), "",
                           sprintf("%.2f (%.2f to %.2f)",
                                   dt$est, dt$low, dt$hi))#sprintF返回字符和可变量组合

最后得到绘图数据

整理好数据我们就可以绘图了

p <- forest(dt[,c(1:3, 8:9)],
            est = dt$est,       #效应值
            lower = dt$low,     #可信区间下限
            upper = dt$hi,      #可信区间上限
            sizes = dt$se,     #黑框的大小
            ci_column = 4,   #在那一列画森林图,要选空的那一列
            ref_line = 1,
            arrow_lab = c("Placebo Better", "Treatment Better"),
            xlim = c(0, 4),
            ticks_at = c(0.5, 1, 2, 3),
            footnote = "This is the demo data. Please feel free to change\nanything you want.")
p


有些人可能想问,有些森林图是有P值的,这个没有P值怎么办,我们可以给它加上去

dt$p <- paste(rep("<0.05", 22))

重新绘图

p <- forest(dt[,c(1:3, 8:10)],
            est = dt$est,       #效应值
            lower = dt$low,     #可信区间下限
            upper = dt$hi,      #可信区间上限
            sizes = dt$se,     #黑框的大小
            ci_column = 4,   #在那一列画森林图,要选空的那一列
            ref_line = 1,
            arrow_lab = c("Placebo Better", "Treatment Better"),
            xlim = c(0, 4),
            ticks_at = c(0.5, 1, 2, 3),
            footnote = "This is the demo data. Please feel free to change\nanything you want.")
p

这样P值就出来了

生成图形后我们还可以对图形进行细节调整,我们把第一行总病例数放到最后改成汇总,然后把它的名字改成Overall,

dt_tmp <- rbind(dt[-1, ], dt[1, ])
dt_tmp[nrow(dt_tmp), 1] <- "Overall"


forest_theme函数可以对森林图图片的细节进行调整,我们可以在forest_theme函数上设定预定的森林图样式模块,到时直接绘图就好了

tm <- forest_theme(base_size = 10,  #文本的大小
                   # Confidence interval point shape, line type/color/width
                   ci_pch = 15,   #可信区间点的形状
                   ci_col = "#762a83",    #CI的颜色
                   ci_fill = "blue",     #ci颜色填充
                   ci_alpha = 0.8,        #ci透明度
                   ci_lty = 1,            #CI的线型
                   ci_lwd = 1.5,          #CI的线宽
                   ci_Theight = 0.2, # Set an T end at the end of CI  ci的高度,默认是NULL
                   # Reference line width/type/color   参考线默认的参数,中间的竖的虚线
                   refline_lwd = 1,       #中间的竖的虚线
                   refline_lty = "dashed",
                   refline_col = "grey20",
                   # Vertical line width/type/color  垂直线宽/类型/颜色   可以添加一条额外的垂直线,如果没有就不显示
                   vertline_lwd = 1,              #可以添加一条额外的垂直线,如果没有就不显示
                   vertline_lty = "dashed",
                   vertline_col = "grey20",
                   # Change summary color for filling and borders   更改填充和边框的摘要颜色
                   summary_fill = "yellow",       #汇总部分大菱形的颜色
                   summary_col = "#4575b4",
                   # Footnote font size/face/color  脚注字体大小/字体/颜色
                   footnote_cex = 0.6,
                   footnote_fontface = "italic",
                   footnote_col = "red")

设定好模块后直接绘图就可以了

pt <- forest(dt_tmp[,c(1:3, 8:9)],
             est = dt_tmp$est,
             lower = dt_tmp$low, 
             upper = dt_tmp$hi,
             sizes = dt_tmp$se,
             is_summary = c(rep(FALSE, nrow(dt_tmp)-1), TRUE),
             ci_column = 4,
             ref_line = 1,
             arrow_lab = c("Placebo Better", "Treatment Better"),
             xlim = c(0, 4),
             ticks_at = c(0.5, 1, 2, 3),
             footnote = "This is the demo data. Please feel free to change\nanything you want.",
             theme = tm)

plot(pt)


我们还可以对图片细节进行修改,比如我们想把第三行变成红色

g <- edit_plot(p, row = 3, gp = gpar(col = "red", fontface = "italic"))
g


更改3,6,10,11行方块及长条的颜色为绿色

g <- edit_plot(g,
               row = c(3, 6, 11, 13),
               col = 4,
               which = "ci",
               gp = gpar(col = "green"))
g


把2, 5, 10, 13, 17, 20行的文本变成粗体

g <- edit_plot(g,
               row = c(2, 5, 10, 13, 17, 20),
               gp = gpar(fontface = "bold"))
g


把第五行的背景改成绿色

g <- edit_plot(g, row = 5, which = "background",
               gp = gpar(fill = "darkolivegreen1"))
g


在顶部插入文本

g <- insert_text(g,
                 text = "Treatment group",
                 col = 2:3,
                 part = "header",
                 gp = gpar(fontface = "bold"))
g


在标题下方加一条下划线

g <- add_underline(g, part = "header")
g


在第十行位置插入文本

g <- insert_text(g,
                 text = "This is a long text. Age and gender summarised above.\nBMI is next",
                 row = 10,
                 just = "left",
                 gp = gpar(cex = 0.6, col = "green", fontface = "italic"))

g


下面来介绍一下怎么绘制多组的森林图,绘制对组森林图就要涉及多组的数据,我们把数据重新导入一下

dt<-read.csv("E:/r/test/forest2.csv",sep=',',header=TRUE)

设置一下缩进,这样好看一点,这步和前面是一样的

dt$Subgroup <- ifelse(is.na(dt$Placebo), 
                      dt$Subgroup,
                      paste0("   ", dt$Subgroup))#######如果变量没有缺失,就缩进一格,也就是前进一格

因为是双组变量,所以要设置2个n,这步和前面基本一样

dt$n1 <- ifelse(is.na(dt$Treatment), "", dt$Treatment)###将缺失的部分变为空格
dt$n2 <- ifelse(is.na(dt$Placebo), "", dt$Placebo)

因为是要画两个森林图,所以要增加两个空地方来画图

dt$`CVD outcome` <- paste(rep(" ", 20), collapse = " ")
dt$`COPD outcome` <- paste(rep(" ", 20), collapse = " ")

设置一些森林图的基本参数,这步和前面是一样的

tm <- forest_theme(base_size = 10,
                   refline_lty = "solid",   #参考线类型
                   ci_pch = c(15, 18),
                   ci_col = c("#377eb8", "#4daf4a"),
                   footnote_col = "blue",
                   legend_name = "Group",   #设置标题名字
                   legend_value = c("Trt 1", "Trt 2"),   #设置分组名字
                   vertline_lty = c("dashed", "dotted"),
                   vertline_col = c("#d6604d", "#bababa"))

最后绘图,这里我要说一下,ci_column = c(3, 5)是指在第3和5列绘图,est_gp1和est_gp2为一组,est_gp3和est_gp4为一组,其他的依次类推

p <- forest(dt[,c(1, 19, 21, 20, 22)],
            est = list(dt$est_gp1,
                       dt$est_gp2,
                       dt$est_gp3,
                       dt$est_gp4),
            lower = list(dt$low_gp1,
                         dt$low_gp2,
                         dt$low_gp3,
                         dt$low_gp4), 
            upper = list(dt$hi_gp1,
                         dt$hi_gp2,
                         dt$hi_gp3,
                         dt$hi_gp4),
            ci_column = c(3, 5),
            ref_line = 1,
            vert_line = c(0.5, 2),
            nudge_y = 0.2,
            theme = tm)

p


最后双组森林图也绘制好了,也可以像单组一样调整。这应该是我写得最详细的1次了,整整搞了15页。

有关R语言使用forestploter包绘制单组及双组森林图(2)(附有超详细备注)的更多相关文章

  1. ruby - 如何使用 Nokogiri 的 xpath 和 at_xpath 方法 - 2

    我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div

  2. ruby - 使用 RubyZip 生成 ZIP 文件时设置压缩级别 - 2

    我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看ruby​​zip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d

  3. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  4. ruby-on-rails - 使用 Ruby on Rails 进行自动化测试 - 最佳实践 - 2

    很好奇,就使用ruby​​onrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提

  5. ruby - 在 Ruby 中使用匿名模块 - 2

    假设我做了一个模块如下:m=Module.newdoclassCendend三个问题:除了对m的引用之外,还有什么方法可以访问C和m中的其他内容?我可以在创建匿名模块后为其命名吗(就像我输入“module...”一样)?如何在使用完匿名模块后将其删除,使其定义的常量不再存在? 最佳答案 三个答案:是的,使用ObjectSpace.此代码使c引用你的类(class)C不引用m:c=nilObjectSpace.each_object{|obj|c=objif(Class===objandobj.name=~/::C$/)}当然这取决于

  6. ruby - 使用 ruby​​ 和 savon 的 SOAP 服务 - 2

    我正在尝试使用ruby​​和Savon来使用网络服务。测试服务为http://www.webservicex.net/WS/WSDetails.aspx?WSID=9&CATID=2require'rubygems'require'savon'client=Savon::Client.new"http://www.webservicex.net/stockquote.asmx?WSDL"client.get_quotedo|soap|soap.body={:symbol=>"AAPL"}end返回SOAP异常。检查soap信封,在我看来soap请求没有正确的命名空间。任何人都可以建议我

  7. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  8. ruby-on-rails - 'compass watch' 是如何工作的/它是如何与 rails 一起使用的 - 2

    我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t

  9. ruby - 使用 ruby​​ 将 HTML 转换为纯文本并维护结构/格式 - 2

    我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h

  10. ruby - 在 64 位 Snow Leopard 上使用 rvm、postgres 9.0、ruby 1.9.2-p136 安装 pg gem 时出现问题 - 2

    我想为Heroku构建一个Rails3应用程序。他们使用Postgres作为他们的数据库,所以我通过MacPorts安装了postgres9.0。现在我需要一个postgresgem并且共识是出于性能原因你想要pggem。但是我对我得到的错误感到非常困惑当我尝试在rvm下通过geminstall安装pg时。我已经非常明确地指定了所有postgres目录的位置可以找到但仍然无法完成安装:$envARCHFLAGS='-archx86_64'geminstallpg--\--with-pg-config=/opt/local/var/db/postgresql90/defaultdb/po

随机推荐