Grid.arrange kullanarak rastgele bir ggplot sayısını nasıl düzenleyebilirim?


93

Bu, ggplot2 google grubunda çapraz olarak yayınlanmıştır

Benim durumum, rastgele sayıda grafik çıkaran bir işlev üzerinde çalışmamdır (kullanıcı tarafından sağlanan giriş verilerine bağlı olarak). İşlev, n grafiklerin bir listesini döndürür ve bu grafikleri 2 x 2 formasyonunda düzenlemek istiyorum. Eşzamanlı problemlerle mücadele ediyorum:

  1. Esnekliğe keyfi (n) sayıda parsel verilmesine nasıl izin verebilirim?
  2. Ayrıca 2 x 2 düzenlenmesini istediğimi de nasıl belirtebilirim

Benim şu anki stratejisi kullanır grid.arrangegelen gridExtrapaketin. Muhtemelen optimal değil, özellikle ve bu anahtar olduğundan, tamamen işe yaramıyor . İşte yorumlu örnek kodum, üç grafikle deneyler:

library(ggplot2)
library(gridExtra)

x <- qplot(mpg, disp, data = mtcars)
y <- qplot(hp, wt, data = mtcars)
z <- qplot(qsec, wt, data = mtcars)

# A normal, plain-jane call to grid.arrange is fine for displaying all my plots
grid.arrange(x, y, z)

# But, for my purposes, I need a 2 x 2 layout. So the command below works acceptably.
grid.arrange(x, y, z, nrow = 2, ncol = 2)

# The problem is that the function I'm developing outputs a LIST of an arbitrary
# number plots, and I'd like to be able to plot every plot in the list on a 2 x 2
# laid-out page. I can at least plot a list of plots by constructing a do.call()
# expression, below. (Note: it totally even surprises me that this do.call expression
# DOES work. I'm astounded.)
plot.list <- list(x, y, z)
do.call(grid.arrange, plot.list)

# But now I need 2 x 2 pages. No problem, right? Since do.call() is taking a list of
# arguments, I'll just add my grid.layout arguments to the list. Since grid.arrange is
# supposed to pass layout arguments along to grid.layout anyway, this should work.
args.list <- c(plot.list, "nrow = 2", "ncol = 2")

# Except that the line below is going to fail, producing an "input must be grobs!"
# error
do.call(grid.arrange, args.list)

Yapmaya alışkın olduğum gibi, köşede alçakgönüllülükle toplanıyorum, benden çok daha akıllı bir topluluğun bilgece geri bildirimlerini hevesle bekliyorum. Özellikle de bunu olması gerekenden daha zor hale getiriyorsam.


2
ÇOK iyi yapılmış bir soru için tebrikler. Bunu, iyi bir SO [r] sorusunun nasıl yazılacağına dair bir örnek olarak kullanacağım.
JD Long

1
özellikle "alçakgönüllülükle toplanma" kısmı - iyi bir
serseri gibisi yoktur

@JD ve @Ben - Gururum okşandı çocuklar. İçtenlikle. Ve yardımın için gerçekten minnettarım.
briandk

Yanıtlar:


45

NEREDEYSE oradasın! Sorun, bağımsız değişkenlerinizin do.calladlandırılmış bir listnesnede olmasını beklemektir . Bunları listeye koydunuz, ancak liste öğeleri olarak adlandırmadınız, karakter dizileri olarak.

Bunun işe yarayacağını düşünüyorum:

args.list <- c(plot.list, 2,2)
names(args.list) <- c("x", "y", "z", "nrow", "ncol")

Ben ve Joshua'nın yorumlarda belirttiği gibi, listeyi oluştururken isimler vermiş olabilirdim:

args.list <- c(plot.list,list(nrow=2,ncol=2))

veya

args.list <- list(x=x, y=y, z=x, nrow=2, ncol=2)

1
Kodu birkaç kez değiştirdim. Düzenlemeler için özür dilerim. şimdi mantıklı mı? Daha önce vektör olduklarını söylediğimde yanlış söyledim. Bunun için üzgünüm.
JD Long

2
Liste oluşturma sırasında değiştirgeleri adlandırabilirsiniz:args.list <- list(x=x, y=y, z=x, nrow=2, ncol=2)
Joshua Ulrich

2
Tam olarak değil. Seninki uygun uzunlukta. Listenizin yapısı JD'nin listesinin yapısından farklıdır. Str () ve isimler () kullanın. Tüm liste öğeleriniz adsızdır, bu nedenle do.callbaşarılı olması için tam konumsal eşleştirme olması gerekir.
IRTFM

2
@JD Long; Ben yürekten katılıyorum. Ve tüm hataları engellemezse, traceback()adlandırılmış bağımsız değişkenler kullanırsanız , yine de çok daha iyi hata mesajları ve bilgiler alırsınız.
IRTFM

1
Buradaki tartışmayı tam olarak takip etmiyorum; İlk argüman beri grid.arrange()olan ...konumsal eşleştirme muhtemelen alakasız. Her girdi ya bir ızgara nesnesi (adı olan veya olmayan), için adlandırılmış bir parametre grid.layoutveya kalan bağımsız değişkenler için adlandırılmış bir parametre olmalıdır.
baptiste

16

Bunu dene,

require(ggplot2)
require(gridExtra)
plots <- lapply(1:11, function(.x) qplot(1:10,rnorm(10), main=paste("plot",.x)))

params <- list(nrow=2, ncol=2)

n <- with(params, nrow*ncol)
## add one page if division is not complete
pages <- length(plots) %/% n + as.logical(length(plots) %% n)

groups <- split(seq_along(plots), 
  gl(pages, n, length(plots)))

pl <-
  lapply(names(groups), function(g)
         {
           do.call(arrangeGrob, c(plots[groups[[g]]], params, 
                                  list(main=paste("page", g, "of", pages))))
         })

class(pl) <- c("arrangelist", "ggplot", class(pl))
print.arrangelist = function(x, ...) lapply(x, function(.x) {
  if(dev.interactive()) dev.new() else grid.newpage()
   grid.draw(.x)
   }, ...)

## interactive use; open new devices
pl

## non-interactive use, multipage pdf
ggsave("multipage.pdf", pl)

3
version> = 0.9 of gridExtra, marrangeGrob'un her ne zaman * ncol <length (plots) 'da otomatik olarak yapmasını sağlar
baptiste

5
ggsave("multipage.pdf", do.call(marrangeGrob, c(plots, list(nrow=2, ncol=2))))
baptiste

4

Biraz geç cevap veriyorum, ancak R Graphics Cookbook'ta, adı verilen özel bir işlevi kullanarak çok benzer bir şey yapan bir çözüme rastladım multiplot. Belki de bu soruyu bulanlara yardımcı olacaktır. Ayrıca yanıtı ekliyorum çünkü çözüm bu soruya verilen diğer yanıtlardan daha yeni olabilir.

Tek sayfada birden çok grafik (ggplot2)

Yazarın ggplot2 0.9.3 için güncellendiğini belirttiği için lütfen yukarıdaki bağlantıyı kullanın, bu da tekrar değişebileceğini gösterir.

# Multiple plot function
#
# ggplot objects can be passed in ..., or to plotlist (as a list of ggplot objects)
# - cols:   Number of columns in layout
# - layout: A matrix specifying the layout. If present, 'cols' is ignored.
#
# If the layout is something like matrix(c(1,2,3,3), nrow=2, byrow=TRUE),
# then plot 1 will go in the upper left, 2 will go in the upper right, and
# 3 will go all the way across the bottom.
#
multiplot <- function(..., plotlist=NULL, file, cols=1, layout=NULL) {
  require(grid)

  # Make a list from the ... arguments and plotlist
  plots <- c(list(...), plotlist)

  numPlots = length(plots)

  # If layout is NULL, then use 'cols' to determine layout
  if (is.null(layout)) {
    # Make the panel
    # ncol: Number of columns of plots
    # nrow: Number of rows needed, calculated from # of cols
    layout <- matrix(seq(1, cols * ceiling(numPlots/cols)),
                    ncol = cols, nrow = ceiling(numPlots/cols))
  }

 if (numPlots==1) {
    print(plots[[1]])

  } else {
    # Set up the page
    grid.newpage()
    pushViewport(viewport(layout = grid.layout(nrow(layout), ncol(layout))))

    # Make each plot, in the correct location
    for (i in 1:numPlots) {
      # Get the i,j matrix positions of the regions that contain this subplot
      matchidx <- as.data.frame(which(layout == i, arr.ind = TRUE))

      print(plots[[i]], vp = viewport(layout.pos.row = matchidx$row,
                                      layout.pos.col = matchidx$col))
    }
  }
}

Biri arsa nesneleri oluşturur:

p1 <- ggplot(...)
p2 <- ggplot(...)
# etc.

Ve sonra bunları şuraya aktarır multiplot:

multiplot(p1, p2, ..., cols = n)
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.