【发布时间】:2011-04-14 15:02:24
【问题描述】:
我在打开设备列表时遇到了一个相当烦人的问题,我试图构建一个函数来保存列表中的多个图表。假设我们有以下数据:
Alist <- list(
X1 = data.frame(X=rnorm(10),Y=1:10),
X2 = data.frame(X=rnorm(10),Y=1:10),
X3 = data.frame(X=rnorm(10),Y=1:10)
)
及以下功能:
myPlotFunc <- function(x,save=F){
fnames <- paste(names(x),"pdf",sep=".")
for(i in 1:length(x)){
if(save){
pdf(fnames[i])
on.exit(dev.off(),add=T)
}
plot(x[[i]])
}
fnames
}
如果我运行 fnames <- myPlotFunc(Alist,save=T),一切都会正常运行,我会得到 3 个 pdf 文件名 X1.pdf 到 X3.pdf。也就是说,如果没有打开图形窗口。如果有,则其中一个 pdf 不会关闭,并且所有后续绘图都将添加到 pdf 中,直到我在控制台中明确调用 dev.off()。像这样:
plot(Alist[[1]])
fnames <- myPlotFunc(Alist,save=T)
myPlotFunc(Alist,save=F)
> dev.list()
pdf
4
如果我添加 on.exit({print(dev.cur());dev.off()},add=T) ,我会得到以下输出:
> fnames <- myPlotFunc(Alist,save=T)
pdf
5
windows
2
pdf
3
显然它需要从下到上的列表再次关闭它遇到的所有内容。因此,如果有一个图形窗口打开,那就是下一个“当前”设备。这意味着 dev.off() 将不再关闭倒数第二个打开的 pdf 连接,因为在 on.exit 调用中会有一个短路。
我通过将函数更改为:
myPlotFunc <- function(x,save=F){
fnames <- paste(names(x),"pdf",sep=".")
devs <- NULL
on.exit(for(i in devs) dev.off(i), add=T)
for(i in 1:length(x)){
if(save){
pdf(fnames[i])
devs <- c(devs,dev.cur())
}
plot(x[[i]])
}
fnames
}
但这感觉相当尴尬。有什么我在这里遗漏的东西,或者有更好的方法来解决这个问题吗?
免责声明:
如果您不知道,请在运行第三个代码块后运行dev.off()。完成后运行unlink(fnames) 即可轻松清理。
【问题讨论】: