我很擅长使用R的力量来创建图形输出。
我在metafor-package中使用forest() - 函数来创建我的元分析的Forest图。我使用循环生成几个图,然后通过png()保存它们。
for (i in 1:ncol(df)-2)){
dat <- escalc(measure="COR", ri=ri, ni=ni, data=df) # Calcultes Effect Size
res_re <- rma.uni(yi, vi, data=dat, method="DL", slab=paste(author)) # Output of meta-analysis
png(filename=path, width=8.27, height=11.69, units ="in", res = 210)
forest(res_re, showweight = T, addfit= T, cex = .9)
text(-1.6, 18, "Author(s) (Year)", pos=4)
text( 1.6, 18, "Correlation [95% CI]", pos=2)
dev.off()
}
如果绘图的大小相等,则效果很好。然而,循环的每次迭代在森林图中集成了不同数量的研究。因此,文本元素不在正确的位置,并且许多研究的森林情节看起来有点奇怪。我有两个问题:
每个森林地块应如下所示:
答案 0 :(得分:1)
以下是您需要做的工作:
我会在图表中修复xlim
,以便有一个固定的位置来放置“作者(年)”和“相关[95%CI]”标题。生成森林图后,请查看par()$usr[1:2]
。使用这些值作为起点来调整xlim
,使其适合您的所有绘图。然后对text()
的两次调用使用这两个值。
每个图中都有k
行。标题应该高出两行。因此,请使用text(<first xlim value>, res_re$k+2, "Author(s) (Year)", pos=4)
和text(<second xlim value>, res_re$k+2, "Correlation [95% CI]", pos=2)
将cex
中的text()
设置为您在调用forest()
时指定的相同值。
最后一部分很棘手。您已修复cex
,因此文本元素的大小在各个图表中应相同。但是如果有更多的研究,那么k
行会被塞进更小的空间,因此它们会变得更少分离。如果我理解正确,您希望通过调整绘图的实际高度来保持行之间的间距相等。从本质上讲,这需要在调用height
png()
时使k
成为height
。对于每个额外的研究,需要将额外的数量添加到height=<some factor> + res_re$k * <some factor>
,以便行间距保持不变,因此类似于k
。但作为?par
函数的高度增加也可能是非线性的。做到这一点需要花费大量的尝试和错误。可能有一种巧妙的方法可以通过编程方式确定(挖掘?strheight
和height
)。
因此,让其他人更容易进入,问题的最后部分归结为:我如何调整绘图设备的plot(1:10)
值,以便行之间的绝对间距在plot(1:20)
和{{1}}保持平等?这本身就是一个有趣的问题,所以我将把它作为一个单独的问题发布。
答案 1 :(得分:1)
ad 4。:在Wolfgangs的问题(Constant Absolute Spacing of Row in R Plots)中,您将找到如何根据其中的行数制作绘图高度。
对于forest()
,它会有所不同,因为此函数会在内部修改par("mar")
- 值。
但是,如果将边距设置为零,则只需在yaxs="i"
- 函数中包含属性forest()
,以便y轴将针对数据范围进行分段,没有其他的。需要将设备配置为高度(length(ma$yi)+4.5)*fact*res
,其中fact
为英寸/行(见下文),res
为像素/英寸(分辨率)。
4.5
取决于您是否在您的元分析模型中留下addfit=T
和intercept=T
(在这种情况下forest()
在内部设置ylim <- c(-1.5, k + 3)
)。否则,您必须使用2.5
(而不是ylim <- c(0.5, k + 3)
)。
如果您想使用边距,您可以执行以下操作(我在识别出一些错误后编辑了以下部分):
res <- 'your desired resolution' # pixels per inch
fact <- par("mai")[1]/par("mar")[1] # calculate inches per line
### this following part is copied from inside the forest()-function.
# forest() modifies the margin internally in the same way.
par.mar <- par("mar")
par.mar.adj <- par.mar - c(0, 3, 1, 1)
par.mar.adj[par.mar.adj < 0] <- 0
###
ylim <- c(-1.5, length(ma$yi)+3) # see above
ylim.abs <- abs(ylim[1])+abs(ylim[2])-length(ma$yi) # calculate absolute distance of ylim-argument
pixel.bottom <- (par.mar.adj[1])*fact*res # calculate pixels to add to bottom and top based on the margin that is internally used by forest().
pixel.top <- (par.mar.adj[3])*fact*res
png(filename='path',
width='something meaningful',
height=((length(ma$yi)+ylim.abs)*fact*res) + pixel.bottom + pixel.top,
res=res)
par(mar=par.mar) # make sure that inside the new device the margins you want to define are actually used.
forest(res_re, showweight = T, addfit= T, cex = .9, yaxs="i")
...
dev.off()