英文:
How to put multiple plots with inner plots in a M x N layout without messing up the par()s?
问题
我在一个图中创建了另一个图。
(我在这里简单使用curve(),但这也适用于plot()。)
curve(exp(x), 0, 1, col=4)
.op <- par(
fig=c(grconvertX(c(.05, .4), to='ndc'),
grconvertY(c(2, 2.75), to='ndc')),
mar=c(1, 1, 1, 1),
new=TRUE
)
curve(sin(x), 0, 2*pi)
par(.op)
通过for循环重复这个基本上是有效的。但是,当我尝试使用2x2的layout时,图形分散在四个不同的图中,而不是显示在一个图中。
layout(matrix(1:4, 2, 2))
for (i in 1:4) {
curve(exp(x), 0, 1, col=4)
.op <- par(
fig=c(grconvertX(c(.05, .3), to='ndc'),
grconvertY(c(2, 2.75), to='ndc')),
mar=c(1, 1, 1, 1),
new=TRUE
)
curve(sin(x), 0, 2*pi)
par(.op)
}
由于某种原因,内部的par破坏了外部的par。我还尝试了op <- par(mfrow=); ... par(op)而不是layout,但结果相同。
如何修复这个问题?
英文:
I make a plot within a plot.
(I use curve() here for simplicity, but this also refers to plot().)
curve(exp(x), 0, 1, col=4)
.op <- par(
fig=c(grconvertX(c(.05, .4), to='ndc'),
grconvertY(c(2, 2.75), to='ndc')),
mar=c(1, 1, 1, 1),
new=TRUE
)
curve(sin(x), 0, 2*pi)
par(.op)
Repeating this in a for loop basically works well. However, when I try use a 2x2 layout, the figures are spread over four different plots instead of being shown on one.
layout(matrix(1:4, 2, 2))
for (i in 1:4) {
curve(exp(x), 0, 1, col=4)
.op <- par(
fig=c(grconvertX(c(.05, .3), to='ndc'),
grconvertY(c(2, 2.75), to='ndc')),
mar=c(1, 1, 1, 1),
new=TRUE
)
curve(sin(x), 0, 2*pi)
par(.op)
}
For some reason the inner par messes up the outer one. I also tried to op <- par(mfrow=); ... par(op) instead of layout, but with same result.
How can I fix that?
答案1
得分: 5
尝试使用 screen 替代。
split.screen(c(2,2))
for (i in 1:4) {
screen(i)
curve(exp(x), 0, 1, col=4)
title(paste("i=",i))
.op <- par(
fig=c(grconvertX(c(.05, .3), to='ndc'),
grconvertY(c(2, 2.75), to='ndc')),
mar=c(1, 1, 1, 1),
new=TRUE
)
curve(sin(x), 0, 2*pi)
par(.op)
}
英文:
Try using screen instead.
split.screen(c(2,2))
for (i in 1:4) {
screen(i)
curve(exp(x), 0, 1, col=4)
title(paste("i=",i))
.op <- par(
fig=c(grconvertX(c(.05, .3), to='ndc'),
grconvertY(c(2, 2.75), to='ndc')),
mar=c(1, 1, 1, 1),
new=TRUE
)
curve(sin(x), 0, 2*pi)
par(.op)
}
答案2
得分: 2
如果你想继续使用 layout(某种程度上),你可以首先创建一系列空白图形,以找到布局区域的坐标。然后,不再依赖于 layout,你可以再次使用 par(fig=...) 来定义它们,这将允许你绘制内部图形而不会弄乱事情。
layout(matrix(1:4, 2, 2))
# 存储布局区域的坐标
figs <- sapply(1:4, \(i) {
frame()
par('fig')
})
# 覆盖空白图形
par(new=T)
for (i in 1:4) {
# 将图形区域设置为当前布局窗口
par(fig = figs[, i])
curve(exp(x), 0, 1, col=4)
.op <- par(
fig=c(grconvertX(c(.05, .3), to='ndc'),
grconvertY(c(2, 2.75), to='ndc')),
mar=c(1, 1, 1, 1),
new=TRUE
)
curve(sin(x), 0, 2*pi)
par(.op)
par(new=T)
}
英文:
If you want to stick to using layout (sort of), you can first create a series of empty plots to find the coordinates for the layout regions. Then, not relying on layout anymore, you can define them again with par(fig=...) which will allow you to draw the inner plots without things getting messed up.
layout(matrix(1:4, 2, 2))
# store coordinates of layout regions
figs <- sapply(1:4, \(i) {
frame()
par('fig')
})
# to overwrite the empty plots
par(new=T)
for (i in 1:4) {
# set figure region to the current layout window
par(fig = figs[, i])
curve(exp(x), 0, 1, col=4)
.op <- par(
fig=c(grconvertX(c(.05, .3), to='ndc'),
grconvertY(c(2, 2.75), to='ndc')),
mar=c(1, 1, 1, 1),
new=TRUE
)
curve(sin(x), 0, 2*pi)
par(.op)
par(new=T)
}
答案3
得分: 2
以下是您要翻译的内容:
"Here's how I combined the insights from the two answers in a function plot_fun(). From @Edward I take split.screen, and from @Robert Hacken the fact that curve (or plot respectively) produces margins relative to the font size that we may manipulate using cex."
"这是我如何将两个答案的见解结合到一个名为 plot_fun() 的函数中。从@Edward那里,我使用了 split.screen,而从@Robert Hacken那里,我了解到 curve(或者 plot)会相对于字体大小产生边距,我们可以使用 cex 进行操作。"
plot_fun <- function(spl, .cex = 3, iadj = 0) {
scr <- split.screen(spl)
for (i in scr) {
screen(i)
par(mar = c(5, 6, 4, 3) + 0.1)
curve(exp(x), 0, 1, col = 4, cex.axis = .cex, cex.lab = .cex)
.op <- par(
fig = c(grconvertX(c(0.1, 0.4), to = 'ndc'),
grconvertY(c(2 + iadj, 2.75), to = 'ndc')),
mar = c(1, 1, 1, 1),
cex = .cex * 0.1,
new = TRUE
)
curve(sin(x), 0, 2 * pi, cex.axis = .cex * 3)
par(.op)
}
close.screen(all.screens = TRUE)
}
f <- 4 ## appears to work fine with the two versions below
pdf("tmp/p1.pdf", 16 * f, 9 * f)
plot_fun(spl = c(6, 7))
dev.off()
"如果我们希望在出版或其他方面获得更清晰的坐标轴刻度标签,我们仍然可以使用 curve(., axes=FALSE) 并使用 axis() 和 mtext() 进行调整,但这已经可以在不费力的情况下得到令人满意的分析结果。"
"如果您的设备在设置过程中出现问题并且产生奇怪的结果,可以使用 graphics.off() 和 close.screen(all.screens=TRUE) 来重置设备。"
英文:
Here's how I combined the insights from the two answers in a function plot_fun(). From @Edward I take split.screen, and from @Robert Hacken the fact that curve (or plot respectively) produces margins relative to the font size that we may manipulate using cex.
plot_fun <- \(spl, .cex=3, iadj=0) {
scr <- split.screen(spl)
for (i in scr) {
screen(i)
par(mar=c(5, 6, 4, 3) + .1)
curve(exp(x), 0, 1, col=4, cex.axis=.cex, cex.lab=.cex)
.op <- par(
fig=c(grconvertX(c(.1, .4), to='ndc'),
grconvertY(c(2 + iadj, 2.75), to='ndc')),
mar=c(1, 1, 1, 1),
cex=.cex*.1,
new=TRUE
)
curve(sin(x), 0, 2*pi, cex.axis=.cex*3)
par(.op)
}
close.screen(all.screens=TRUE)
}
f <- 4 ## appears to work fine with the two versions below
pdf("tmp/p1.pdf", 16*f, 9*f)
plot_fun(spl=c(6, 7))
dev.off()
pdf("tmp/p1.pdf", 16*f, 9*f)
plot_fun(spl=c(2, 3), iadj=.2)
dev.off()
If we wish cleaner tick labels on the axes for publishing or so, we may still use curve(., axes=FALSE) and mess around with axis() and mtext(), but this already gives an acceptable result for analyses without great effort.
If your device gets messed up during setup and gives weird results, use graphics.off() and close.screen(all.screens=TRUE) to reset the device.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。




评论