【问题标题】:using ggsave and arrangeGrob after updating gridExtra to 2.0.0在将 gridExtra 更新为 2.0.0 后使用 ggsave 和安排Grob
【发布时间】:2015-11-20 09:39:15
【问题描述】:

由于到目前为止我在 stackoverflow 上阅读了很多类似的问题,因此如果不将 ggplot2 更新到开发版本,我找不到一个好的解决方案。

我的问题,我有几个脚本使用arrangeGrob 从单个图形中创建组合图形。我将它们保存到一个变量和print 这个变量和/或用ggsave 保存它。由于我的很多同事定期更新那里的软件包(我认为这是一件好事),我总是收到邮件我的脚本在更新到 gridExtra 2.0.0 后不再工作。

我不确定如何处理这个问题,因为解决问题的新 ggplot2 版本仍在开发中。如果要保存的对象是ggplot,我在堆栈溢出时发现了一个article,以删除一个测试,因为新的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 它。

我不想使用this article 中建议的“旧”(pdf(file = "test.pdf"); grid.draw(b); dev.off())设备保存功能,因为它们使用起来非常不舒服。

this question 中,有人确切地询问如何保存对象,但在答案中他们只是解释使用grid.darw,他接受了solving the problem 的答案,到目前为止没有人在我的 cmets 上回答。

所以我现在很迷茫,如何为那些已经和没有更新到新的gridExtra 包的人提供工作脚本。在ggsave 函数中删除测试的方法是我想最好的解决方案,因为我可以检查gridExtraggplot2 版本并覆盖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  

【问题讨论】:

  • 您是否尝试使用 pdf() 而不是 ggsave?类似的东西: pdf(file = "test.pdf"); grid.newpage() ;print(b) ;dev.off()
  • 此链接可能会有所帮助:alstatr.blogspot.co.uk/2015/02/…
  • @YCR 这是我在第二个链接中提到的。我知道这是可行的,但非常不方便。我希望ggsave 函数按照第一个链接中的建议工作,否则我必须更改脚本中的很多行...
  • 我可能不明白,但是ggsave 使用您的示例的错误/问题在哪里?
  • @Pascal 我在下面直接添加了输出和评论,忘记提及问题所在:-)

标签: r ggplot2 gridextra


【解决方案1】:

作为这个不幸的过渡期的临时解决方法,您可以重新实现曾经在 gridExtra 中的类 hack,

class(b) <- c("arrange","ggplot", class(b))
print.arrange <- function(x) grid.draw(x)
ggsave('test.pdf', b)

【讨论】:

  • 这个arrange 解决方法必须应用于我使用arrangeGrob 创建的情节。有什么反对我建议的解决方案的吗?就我而言,我只覆盖ggsave 函数,以防gridExtraggplot 的版本不兼容。
  • 有不同的选择很好,在这种情况下我不会说一个更好。就我个人而言,我不喜欢复制大量代码来临时解决问题,因为这往往会混淆我未来的自我,但每个人都有不同的工作流程和/或记住过去的能力。
  • 我刚刚意识到,如果我使用我的函数,它不再适用于正常的 ggplot 图。上面写着no applicable method for 'grid.draw' applied to an object of class "c('gg', 'ggplot')"我想知道这是怎么回事。
【解决方案2】:

Pascal 最终让我想到了检查 ggplot 1.0.1ggplot 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,并从开发版本中创建了两个新函数。

执行该功能后,一切似乎都正常了。

【讨论】:

  • 这似乎与我有关。只有一个问题:我应该如何应用它?环绕一些ggsave-action? 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))
  • @SanderW.vanderLaan 实际上我从来没有让它以可靠的方式工作。老实说,我从来没有真正检查过上面的 babtists 解决方案。我在脚本中使用grid.new();grid.draw() 实现了解决方案。认为这可能是最好的解决方案。
【解决方案3】:

Fix for me 是明确定义文件:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-18
    • 1970-01-01
    相关资源
    最近更新 更多