используя ggsave и аранжировкуGrob после обновления gridExtra до 2.0.0

так как я до сих пор читал много подобных вопросов о stackoverflow, я не смог найти хорошего решения без обновления ggplot2 до версии для разработки.

Моя проблема, у меня есть несколько скриптов, которые используют arrangeGrob для создания комбинированного графика из отдельных графиков. Я сохраняю их в переменную и print эту переменную и/или сохраняю ее с помощью ggsave. Поскольку многие мои коллеги регулярно обновляют там пакеты (что, я думаю, хорошо), я всегда получаю письма, что мой скрипт больше не работает после обновления до gridExtra 2.0.0.

Я не уверен, как с этим справиться, так как новая версия ggplot2, в которой проблема решена, все еще находится в разработке. Я нашел статью. при переполнении стека, чтобы удалить тест, если объект для сохранения является ggplot, поскольку новая функция arrangeGrob возвращает объект gtable, но в моем случае это не удается:

library(ggplot2)
library(grid)
library(gridExtra)
a <- data.frame(x=c(1,2,3),
                y=c(2,3,4))
p <- ggplot(a, aes(x, y)) + geom_point()
b <- arrangeGrob(p, p)
grid.draw(b)
ggsave('test.pdf', b)
ggsave <- ggplot2::ggsave
body(ggsave) <- body(ggplot2::ggsave)[-2]
ggsave('test.pdf', b)

Некоторый вывод и ошибка в консоли:

d> grid.draw(b)
d> ggsave('test.pdf', b)
Error in ggsave("test.pdf", b) : plot should be a ggplot2 plot
d> ggsave <- ggplot2::ggsave
d> body(ggsave) <- body(ggplot2::ggsave)[-2]
d> ggsave('test.pdf', b)
Saving 10.5 x 10.7 in image
TableGrob (2 x 1) "arrange": 2 grobs
  z     cells    name           grob
1 1 (1-1,1-1) arrange gtable[layout]
2 2 (2-2,1-1) arrange gtable[layout]
d> 

test.pdf создан, но он каким-либо образом поврежден и не может быть открыт. Также печатается объект gtable. Так что я думаю, что что-то здесь не так.

Но, как вы можете видеть, я нашел в коде примера, я нашел функцию grid.draw для построения хотя бы моего комбинированного графика, но я все еще не могу ggsave после модификации.

Я не хочу использовать «старые» (pdf(file = "test.pdf"); grid.draw(b); dev.off()) функции сохранения устройства, как это предлагается в эту статью, так как ими очень неудобно пользоваться.

В этом вопросе кто-то спросил, как именно сохранить объект, но в ответ они просто объясняют использование grid.darw, и он принял ответ как solving the problem, и пока никто не ответил на мои комментарии.

Так что на данный момент я совершенно не понимаю, как предоставить рабочие сценарии для тех, кто обновил или не обновил до нового пакета gridExtra. Я думаю, что способ удалить тест в функции ggsave является лучшим решением, поскольку я могу проверить версии gridExtra и ggplot2 и просто перезаписать функцию ggsave в случае, если версии не совпадают, но я не смог заставить его работать.

С нетерпением жду помощи.

ИЗМЕНИТЬ:

может sessionInfo поможет

d> sessionInfo()
R version 3.2.0 (2015-04-16)
Platform: x86_64-apple-darwin13.4.0 (64-bit)
Running under: OS X 10.9.5 (Mavericks)

locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8

attached base packages:
[1] grid      stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
[1] gridExtra_2.0.0 ggplot2_1.0.1  

loaded via a namespace (and not attached):
 [1] Rcpp_0.12.1      digest_0.6.8     MASS_7.3-44      plyr_1.8.3       gtable_0.1.2    
 [6] magrittr_1.5     scales_0.3.0     stringi_1.0-1    reshape2_1.4.1   devtools_1.9.1  
[11] proto_0.3-10     tools_3.2.0      stringr_1.0.0    munsell_0.4.2    colorspace_1.2-6
[16] memoise_0.2.1  

person drmariod    schedule 20.11.2015    source источник
comment
Вы пытались использовать pdf() вместо ggsave? Что-то вроде этого: pdf(file = test.pdf); grid.newpage() ;print(b);dev.off()   -  person YCR    schedule 20.11.2015
comment
Эта ссылка может помочь: alstatr .blogspot.co.uk/2015/02/   -  person YCR    schedule 20.11.2015
comment
@YCR это то, что я упомянул во второй ссылке. Я знаю, что это работает, но очень неудобно. Я бы хотел, чтобы функция ggsave работала так, как предложено в первой ссылке, потому что в противном случае мне придется изменить много строк в моих скриптах...   -  person drmariod    schedule 20.11.2015
comment
Я, наверное, не понимаю, но где ошибка/проблема с ggsave на вашем примере?   -  person    schedule 20.11.2015
comment
@Pascal Я добавил вывод и комментарий прямо ниже, забыл упомянуть, в чем проблема :-)   -  person drmariod    schedule 20.11.2015
comment
Кажется, это работает для меня. Сюжет сохранен в test.pdf по вашему примеру (ggplot2 версия 1.0.1.9003 и gridExtra версия 2.0.0).   -  person    schedule 20.11.2015
comment
@Pascal the ggplot2 1.0.1.9003 — это версия для разработки, которую также нелегко установить для всех пользователей, поскольку приходится использовать devtools и загружать с github. Поэтому я хотел бы остаться со стабильными версиями, но также использовать функции ggsave, а не функции pdf() и dev.off(), как я уже упоминал в своем посте.   -  person drmariod    schedule 20.11.2015
comment
Ваш пример не работает с ggplot2 версией 1.0.1. Но он работает с версией разработки ggplot2, версией 1.0.1.9003.   -  person    schedule 20.11.2015
comment
grid.arrange не работает?   -  person Chapo    schedule 20.11.2015
comment
grid.arrange напрямую строит график. Но я хочу сохранить объект без его построения или построения позже в сценарии.   -  person drmariod    schedule 20.11.2015


Ответы (3)


В качестве временного обходного пути для этого неудачного переходного периода вы можете повторно реализовать хак класса, который раньше был в gridExtra,

class(b) <- c("arrange","ggplot", class(b))
print.arrange <- function(x) grid.draw(x)
ggsave('test.pdf', b)
person baptiste    schedule 21.11.2015
comment
Этот обходной путь arrange должен быть применен к графику, который я создаю с помощью arrangeGrob. Есть ли что-то против решения, которое я предложил? В моем случае я перезаписываю функцию ggsave только в том случае, если версии gridExtra и ggplot несовместимы. - person drmariod; 23.11.2015
comment
Хорошо иметь разные варианты, я бы не сказал, что какой-то один лучше в данном случае. Лично я предпочитаю не дублировать большие куски кода для временных обходных путей, потому что это может сбить меня с толку в будущем, но у каждого свой рабочий процесс и/или способность помнить прошлое. - person baptiste; 23.11.2015
comment
Я только что понял, что если я использую свою функцию, она больше не работает для обычных графиков ggplot. Там написано no applicable method for 'grid.draw' applied to an object of class "c('gg', 'ggplot')" Интересно, как это происходит. - person drmariod; 25.11.2015

Паскаль, наконец, привел меня к идее проверить различия между ggplot 1.0.1 и ggplot 1.0.1.9003, так как я не хочу или навязываю разработку версии ggplot.

Итак, моя идея - это функция, которая будет выполняться в каждом сценарии, перезаписывая функцию по умолчанию ggsave.

Я немного протестировал его сейчас, если есть какие-либо ошибки или около того, пожалуйста, дайте мне знать. Но то, как я это делаю сейчас, работает до сих пор.

repairGgsave <- function() {
  ggplot_version <- 
    compareVersion(as.character(packageVersion('ggplot2')), 
                 '1.0.1.9003')
  gridextra_version <- 
    compareVersion(as.character(packageVersion('gridExtra')), 
                   '0.9.1')
  if(gridextra_version > 0) {
    if(ggplot_version <= 0) {
      ggsave <- function(filename, plot = last_plot(),
                         device = NULL, path = NULL, scale = 1,
                         width = NA, height = NA, units = c("in", "cm", "mm"),
                         dpi = 300, limitsize = TRUE, ...) {

        dev <- plot_dev(device, filename, dpi = dpi)
        dim <- plot_dim(c(width, height), scale = scale, units = units,
                        limitsize = limitsize)

        if (!is.null(path)) {
          filename <- file.path(path, filename)
        }
        dev(file = filename, width = dim[1], height = dim[2], ...)
        on.exit(utils::capture.output(grDevices::dev.off()))
        grid.draw(plot)

        invisible()
      }
      assign("ggsave", ggsave, .GlobalEnv)
      plot_dim <<- function(dim = c(NA, NA), scale = 1, units = c("in", "cm", "mm"),
                           limitsize = TRUE) {

        units <- match.arg(units)
        to_inches <- function(x) x / c(`in` = 1, cm = 2.54, mm = 2.54 * 10)[units]
        from_inches <- function(x) x * c(`in` = 1, cm = 2.54, mm = 2.54 * 10)[units]

        dim <- to_inches(dim) * scale

        if (any(is.na(dim))) {
          if (length(grDevices::dev.list()) == 0) {
            default_dim <- c(7, 7)
          } else {
            default_dim <- dev.size() * scale
          }
          dim[is.na(dim)] <- default_dim[is.na(dim)]
          dim_f <- prettyNum(from_inches(dim), digits = 3)

          message("Saving ", dim_f[1], " x ", dim_f[2], " ", units, " image")
        }

        if (limitsize && any(dim >= 50)) {
          stop("Dimensions exceed 50 inches (height and width are specified in '",
               units, "' not pixels). If you're sure you a plot that big, use ",
               "`limitsize = FALSE`.", call. = FALSE)
        }

        dim
      }

      plot_dev <<- function(device, filename, dpi = 300) {
        if (is.function(device))
          return(device)

        eps <- function(...) {
          grDevices::postscript(..., onefile = FALSE, horizontal = FALSE,
                                paper = "special")
        }
        devices <- list(
          eps =  eps,
          ps =   eps,
          tex =  function(...) grDevices::pictex(...),
          pdf =  function(..., version = "1.4") grDevices::pdf(..., version = version),
          svg =  function(...) grDevices::svg(...),
          emf =  function(...) grDevices::win.metafile(...),
          wmf =  function(...) grDevices::win.metafile(...),
          png =  function(...) grDevices::png(..., res = dpi, units = "in"),
          jpg =  function(...) grDevices::jpeg(..., res = dpi, units = "in"),
          jpeg = function(...) grDevices::jpeg(..., res = dpi, units = "in"),
          bmp =  function(...) grDevices::bmp(..., res = dpi, units = "in"),
          tiff = function(...) grDevices::tiff(..., res = dpi, units = "in")
        )

        if (is.null(device)) {
          device <- tolower(tools::file_ext(filename))
        }

        if (!is.character(device) || length(device) != 1) {
          stop("`device` must be NULL, a string or a function.", call. = FALSE)
        }

        dev <<- devices[[device]]
        if (is.null(dev)) {
          stop("Unknown graphics device '", device, "'", call. = FALSE)
        }
        dev
      }
    }
  }
}

Он в основном перезаписывает ggsave и создает две новые функции из версии разработки.

После выполнения функции все работает.

person drmariod    schedule 20.11.2015
comment
Это кажется мне актуальным. Только один вопрос: как мне его применить? Обернуть какое-нибудь ggsave-действие? repairGgsave(ggsave(paste0(PLOT_loc,"/",Today,"_ObsCoxQuint_CVD.eps"), plot = multiplot(ObsQuintPlot_CVD + guides(colour = FALSE), CoxQuintPlot_CVD + guides(colour = FALSE), cols = 2), width = 12, height = 12)) - person Sander W. van der Laan; 10.05.2016
comment
@SanderW.vanderLaan На самом деле у меня никогда не получалось, чтобы это работало надежно. Честно говоря, я никогда не проверял решение бабтистов выше. Я реализовал решение с grid.new();grid.draw() в своих скриптах. Думал, что это может быть лучшим решением. - person drmariod; 11.05.2016

Исправление для меня было явным определением файла:

ggsave(file='test.pdf', b)

person Rachel    schedule 13.03.2019