英文:
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论