2015-11-20 11 views
8

od czasu, gdy czytałem dużo podobnych pytań na stackoverflow, nie mogłem znaleźć dobrego rozwiązania bez aktualizacji ggplot2 do wersji rozwojowej.używając ggsave i arranGrob po aktualizacji gridExtra do 2.0.0

Mój problem, mam kilka skryptów, które używają arrangeGrob do tworzenia połączonego wykresu z pojedynczych wykresów. Zapisuję je w zmiennej i print tej zmiennej i/lub zapisuję ją za pomocą ggsave. Ponieważ wielu moich kolegów regularnie aktualizuje paczki (co jest dobre, myślę), zawsze otrzymuję maile, że mój skrypt przestał działać po aktualizacji do gridExtra 2.0.0.

Nie jestem pewien, jak sobie z tym poradzić, ponieważ nowa wersja ggplot2, w której problem został rozwiązany, jest wciąż rozwijana. Znalazłem article na przepełnienie stosu, aby usunąć test, jeśli obiekt, aby zapisać to ggplot od nowa arrangeGrob funkcja zwraca gtable obiekt, ale to nie w moim przypadku:

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) 

Niektóre wyjścia i błędów na konsoli :

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 jest tworzony, ale jest on uszkodzony w jakikolwiek sposób i nie mogą być otwierane. Również obiekt gtable zostanie wydrukowany. Więc myślę, że coś jest nie tak.

Ale, jak widać, znalazłem w przykładowym kodzie, znalazłem funkcję grid.draw, aby wykreślić co najmniej mój połączony wykres, ale nadal nie mogę ggsave go po modyfikacji.

Nie chcę używać "starych" (pdf(file = "test.pdf"); grid.draw(b); dev.off()) funkcji oszczędzania urządzeń zgodnie z sugestiami podanymi w this article, ponieważ są one bardzo niewygodne w użyciu.

W this question ktoś zapytał dokładnie jak zapisać obiektu, ale w odpowiedzi po prostu wyjaśnić użycie grid.darw i przyjął odpowiedź jako solving the problem i nikt nie odpowiedział na moje komentarze do tej pory.

Więc jestem całkiem zagubiony w tej chwili, jak zapewnić obsługę skryptów dla tych, którzy mają i nie zaktualizowali do nowego pakietu gridExtra. Sposób na usunięcie testu w ramach funkcji ggsave jest chyba najlepszym rozwiązaniem, ponieważ mogę sprawdzić wersję gridExtra i ggplot2 i po prostu zastąpić funkcję ggsave na wypadek, gdyby wersja nie pasowała, ale nie mogłem jej uruchomić.

Czekamy na pomoc.

EDIT:

Może sessionInfo pomaga

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 
+0

Próbowałeś użyć PDF() zamiast ggsave? Coś w tym stylu: pdf (file = "test.pdf"); grid.newpage(); print (b); dev.off() – YCR

+0

Ten link może pomóc: http://alstatr.blogspot.co.uk/2015/02/r-how-to-layout-and-design- infographic.html – YCR

+0

@YCR to jest to, o czym wspomniałem z drugim linkiem. Wiem, że to działa, ale jest bardzo niefortunne. Chciałbym, aby funkcja 'ggsave' działała zgodnie z sugestią w pierwszym linku, ponieważ w przeciwnym razie muszę zmienić wiele linii w moich skryptach ... – drmariod

Odpowiedz

0

Pascal wprowadził mnie w końcu na pomysł, aby sprawdzić różnice między ggplot 1.0.1 i ggplot 1.0.1.9003, bo nie chcą lub zmusić wersja rozwojowa ggplot.

Więc moim pomysłem jest funkcja, która zostanie wykonana w ramach każdego skryptu, który nadpisuje domyślną funkcję ggsave.

Przetestowałem to teraz trochę, jeśli są jakieś błędy, proszę daj mi znać. Ale sposób, w jaki teraz to robię, działa tak daleko.

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 
     } 
    } 
    } 
} 

Zasadniczo nadpisuje ggsave i tworzy dwie nowe funkcje z wersji rozwojowej.

Po uruchomieniu funkcji wszystko wydaje się działać.

+0

Wydaje mi się to istotne. Tylko jedno pytanie: jak mam to zastosować? Zawiń trochę akcji ggware? 'repairGgsave (ggsave (paste0 (PLOT_loc,"/", Today", "ObsCoxQuint_CVD.eps"), plot = multiplot (ObsQuintPlot_CVD + guide (color = FALSE), CoxQuintPlot_CVD + guide (color = FALSE), cols = 2) , width = 12, height = 12)) ' –

+0

@ SanderW.vanderLaan Właściwie to nigdy nie udało mi się to w solidny sposób. Szczerze mówiąc, nigdy nie sprawdzałem powyżej powyższego rozwiązania Babtists. Zaimplementowałem rozwiązanie z 'grid.new(); grid.draw()' w moich skryptach. Pomyślałem, że to może być najlepsze rozwiązanie. – drmariod

2

Jako tymczasowe obejście tego niefortunnym okresie przejściowym, można ponownie wdrożyć klasy siekać, które były w gridExtra,

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

Ten sposób obejścia 'arran' musi być zastosowany na wydruku, który utworzę z' arrangeGrob'. Czy jest coś przeciwko proponowanemu przeze mnie rozwiązaniu? W moim przypadku tylko nadpisuję funkcję 'ggsave', jeśli wersje' gridExtra' i 'ggplot' nie są kompatybilne. – drmariod

+0

dobrze mieć różne opcje, nie powiedziałbym, że w tym przypadku jest lepiej. Osobiście wolę nie duplikować dużych fragmentów kodu w celu tymczasowego obejścia, ponieważ ma on skłonność do mylnego myślenia o mojej przyszłości, ale każdy ma inny przepływ pracy i/lub zdolność do pamiętania przeszłości. – baptiste

+0

Właśnie sobie uświadomiłem, że jeśli skorzystam z mojej funkcji, nie będzie już działać na normalnych działkach ggplota. Mówi ona "brak stosowanej metody" grid.draw "zastosowanej do obiektu klasy" c ("gg", "ggplot") "Zastanawiam się, jak to się dzieje. – drmariod

Powiązane problemy