了解如何读取设备列表

时间:2011-04-14 15:02:24

标签: r graphics device

我在开放设备列表中遇到了一个相当恼人的问题,试图构建一个为列表保存大量图形的函数。假设我们有以下数据:

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.pdfX3.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 

显然,自下而上的列表需要关闭它遇到的所有内容。因此,如果有一个图形窗口打开,那就是下一个&#34;当前&#34;设备。这意味着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)轻松清理。

2 个答案:

答案 0 :(得分:6)

如何制作帮助功能来制作一个情节:

myPlotFunc <- function(x, save=FALSE) {
    fnames <- paste(names(x), "pdf", sep=".")
    plot_one <- function(xx, fname, save=save) {
        if (save) {
            pdf(fname)
            on.exit(dev.off())
        }
        plot(xx)
    }
    for (i in 1:length(x)) plot_one(x[[i]], fnames[i], save)

    fnames
}

答案 1 :(得分:1)

一个重要的解决方案可能是使用graphics.off()而不是尝试关闭脚本打开的设备。如果这只是用户代码,那么退出时是否所有图形设备都关闭并不重要?

使用这种野蛮的方法似乎有效:

myPlotFunc <- function(x,save = FALSE) {
    fnames <- paste(names(x),"pdf",sep=".")
    if(save)
        on.exit(graphics.off(),add = TRUE)
    for(i in 1:length(x)) {
      if(save) {
        pdf(fnames[i])
      }
      plot(x[[i]])
    }
    fnames
  }

另一种方法是在on.exit()被调用时列出所有设备,选择pdf并关闭它们。此函数实现了此功能,似乎具有所需的行为。

myPlotFunc2 <- function(x,save = FALSE) {
    fnames <- paste(names(x), "pdf", sep=".")
    if(save) {
        on.exit(foo <- lapply(dev.list()[grepl("pdf", names(dev.list()))], 
                              dev.off),
                add = TRUE)
    }
    for(i in 1:length(x)) {
      if(save) {
        pdf(fnames[i])
      }
      plot(x[[i]])
    }
    fnames
  }

似乎编号最小的设备是在调用dev.off()后R激活的设备,这将是您描述的设置中的屏幕设备,因此也就是报告的行为。