在R
中,如何调整绘图设备的height
值(例如windows()
或png()
),以便点之间的绝对间距保持不变?这是一个例子来说明我的意思:
n <- 10
windows(width=4, height=4)
par(xpd=NA)
plot(1:n)
abline(h=1:10)
n <- 20
windows(width=4, height=6)
par(xpd=NA)
plot(1:n)
abline(h=1:20)
我希望每个图中点/线之间的距离完全相同(我使用par(xpd=NA)
因此很容易将图形放在彼此旁边,如果线条对齐则更好看)。显然,height
必须是n
的函数。当然,人们可以尝试通过反复试验找到n
的某些功能来实现这一目标。但也许有一种聪明的方法可以通过编程方式实现这一目标。
我的问题与此类似:set ggplot plots to have same x-axis width and same space between dot plot rows。但是这个问题使用了ggplot2
,而我的问题则坚持基础图形。
答案 0 :(得分:2)
这里似乎有两件事情在发挥作用。
首先,我们需要找出没有边距的情况:
adjLineSpace <- function(nLine, baseHeight=32){
# get reproducible device
png(paste("nLine=", nLine, ".png", sep=""), width=baseHeight*nLine, heigh=baseHeight*nLine, res=100)
# control margins
par(mar=c(0,0,0,0))
# open plot with axis that do not interact with data to find "optimal range of axes"
plot(0:nLine, pch=NA_integer_, xlim=c(0, nLine), ylim=c(0, nLine), yaxs="i", xaxs="i")
abline(h=1:nLine)
# include text for visualisation
text(0:nLine, 0:nLine, labels=0:nLine)
text(c(1:4), 0.5, par("usr")[1:4], pos=4)
text(c(5), c(0.5), paste("pin: ", par("pin")[1], ", ", par("pin")[2], sep=""), pos=4)
text(c(5), c(1.5), paste("fin: ", par("fin")[1], ", ", par("fin")[2], sep=""), pos=4)
text(c(5), c(2.5), paste("din: ", par("din")[1], ", ", par("din")[2], sep=""), pos=4)
dev.off()
}
# examples
adjLineSpace(10)
adjLineSpace(20)
找到问题之后,我感觉自己像个血腥的初学者,因为我没有看到这么长时间:一个人需要从0开始计数,否则不会有10或20或n“行”,但是9 ,19或n-1。
但由于几乎在任何情况下都需要保证金,我们还需要了解保证金如何与其相互作用:
# introduce new attributes to adjust margins, make it possible to deal with width and height seperately and be able to controll resolution
adjLineSpace <- function(nLine, basePHeight=32, basePWidth=32, marHeight=c(0, 0), marWidth=c(0, 0), res=100){
pMai <- round(par("mai"),2); pMar <- round(par("mar"),2)
pixelLeft <- marWidth[1]*pMai[2]/pMar[2]*res # adjust left
pixelRight <- marWidth[2]*pMai[4]/pMar[4]*res # adjust right
pixelBottom <- marHeight[1]*pMai[1]/pMar[1]*res # adjust bottom
pixelTop <- marHeight[2]*pMai[3]/pMar[3]*res # adjust top
# reproducible device: we first need to find out how many inches one row covers, multiply that by our resolution and the number of 'lines' we want to use in our margin
png(
paste("nLine=", nLine, ".png", sep=""),
width=basePWidth*nLine + pixelLeft + pixelRight,
heigh=basePHeight*nLine + pixelBottom + pixelTop,
res=res
)
# set margins
par(mar=c(marHeight[1], marWidth[1], marHeight[2], marWidth[2]))
# this is the key to it all! Set range of plot area (in pixels) as above, only transformed to inches (divided by resolution in ppi=points/pixels per inch)
par(pin=c(basePWidth*nLine/res, basePHeight*nLine/res))
plot(0:nLine, pch=NA_integer_, xlim=c(0, nLine), ylim=c(0, nLine), yaxs="i", xaxs="i", bg="white")
abline(h=1:nLine)
# include text for visualisation of values
text(0:nLine, 0:nLine, labels=0:nLine)
text(c(1:4), 0.5, par("usr")[1:4], pos=4)
text(c(5), c(0.5), paste("din: ", par("din")[1], ", ", par("din")[2], sep=""), pos=4)
text(c(5), c(1.5), paste("fin: ", par("fin")[1], ", ", par("fin")[2], sep=""), pos=4)
text(c(5), c(2.5), paste("pin: ", par("pin")[1], ", ", par("pin")[2], sep=""), pos=4)
text(c(.5), c(9.5), paste("mar: ", pMar[1], ", ", pMar[2], ", ", pMar[3], ", ", pMar[4], sep=""), pos=4)
text(c(.5), c(8.5), paste("mai: ", pMai[1], ", ", pMai[2], ", ", pMai[3], ", ", pMai[4], sep=""), pos=4)
text(c(.5), c(7.5), paste("mai(nch)/mar(ow): ", round(pMai[1]/pMar[1],2), ", ", round(pMai[2]/pMar[2],2), ", ", round(pMai[3]/pMar[3],2), ", ", round(pMai[4]/pMar[4],2), sep=""), pos=4)
dev.off()
}
# examples without margins still work
adjLineSpace(10, basePHeight=32, basePWidth=32, marHeight=c(0, 0), marWidth=c(0, 0))
adjLineSpace(20, 32, 32, c(0, 0), c(0, 0))
# with margins as well!
adjLineSpace(10, 32, 32, c(4, 0), c(4, 0))
adjLineSpace(20, 32, 32, c(4, 0), c(4, 0))
有关设备区域的说明,请参阅https://www.stat.auckland.ac.nz/~paul/RGraphics/rgraphics.html(由Paul Murrell提供)。 不幸的是我还没有发布图片,否则我也会在这里添加一些例子。
实际上我也来自这篇文章:Align text to a plot with variable size in R我有兴趣看到它包含在forest() - metafor的功能中。我会寄给你一个PM,Wolfgang。