Понимание того, как читается список устройств - PullRequest
3 голосов
/ 14 апреля 2011

Я столкнулся с довольно раздражающей проблемой со списком открытых устройств, пытаясь создать функцию, которая сохраняет ряд графиков для списка.Скажем, у нас есть следующие данные:

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), когда вы закончите.

Ответы [ 2 ]

6 голосов
/ 14 апреля 2011

Как насчет того, чтобы сделать функцию помощи для построения одного графика:

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 голос
/ 14 апреля 2011

Одним из радикальных решений может быть использование 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
  }

Похоже, что устройство с наименьшим номером - это то, которое R активирует после вызова dev.off(), и это будет экранное устройство в параметре, который вы описываете, и, следовательно, поведение вашего отчета.

...