Ggplot2 ile yan yana grafikler


339

Ggplot2 paketini kullanarak yan yana iki parsel yerleştirmek istiyorum , yani eşdeğerini yapın par(mfrow=c(1,2)).

Örneğin, aşağıdaki iki grafiğin aynı ölçekte yan yana görünmesini istiyorum.

x <- rnorm(100)
eps <- rnorm(100,0,.2)
qplot(x,3*x+eps)
qplot(x,2*x+eps)

Onları aynı veri çerçevesine koymam gerekir mi?

qplot(displ, hwy, data=mpg, facets = . ~ year) + geom_smooth()

Bence bunu kafesle yapabilirsin. Ggplot2 zor bir gereklilik mi?
JD Long

8
Hayır. Ama qplotları değiştirerek zamana girmiştim, bu yüzden sevdim. :-) Ve ggplot ile oynamaya çalışıyorum.
Christopher DuBois


1
İyi bir genel bakış için, yumurta paketinin skeçine bakın : Bir sayfada birden fazla çizim düzenleme
Henrik

Yanıtlar:


505

Herhangi bir ggplots yan yana (veya ızgaradaki n grafiği)

Fonksiyon grid.arrange()içinde gridExtrapaketin birden araziler birleştirecek; ikisini yan yana koyarsınız.

require(gridExtra)
plot1 <- qplot(1)
plot2 <- qplot(1)
grid.arrange(plot1, plot2, ncol=2)

Bu, iki grafik aynı verilere dayanmadığında, örneğin reshape () kullanmadan farklı değişkenler çizmek istiyorsanız kullanışlıdır.

Bu, çıktıyı bir yan etki olarak çizecektir. Bir dosyaya yan etkisi yazdırmak için, (örneğin bir aygıt sürücüsünü belirlemek pdf, pngvb), örneğin

pdf("foo.pdf")
grid.arrange(plot1, plot2)
dev.off()

veya aşağıdakilerle arrangeGrob()kombinasyon halinde kullanın ggsave(),

ggsave("foo.pdf", arrangeGrob(plot1, plot2))

Bu, iki ayrı çizim kullanarak eşdeğerdir par(mfrow = c(1,2)). Bu sadece verileri düzenlemek için zaman kazandırmakla kalmaz, aynı zamanda iki farklı grafik istediğinizde de gereklidir.


Ek: Özelliklerin Kullanılması

Facets, farklı gruplar için benzer grafikler yapmak için yararlıdır. Bu, aşağıdaki birçok cevapta aşağıda belirtilmiştir, ancak yukarıdaki yaklaşıma eşdeğer örneklerle bu yaklaşımı vurgulamak istiyorum.

mydata <- data.frame(myGroup = c('a', 'b'), myX = c(1,1))

qplot(data = mydata, 
    x = myX, 
    facets = ~myGroup)

ggplot(data = mydata) + 
    geom_bar(aes(myX)) + 
    facet_wrap(~myGroup)

Güncelleme

plot_gridişlevi cowplotalternatif olarak incelenmeye değer grid.arrange. Bkz cevabı @ aşağıda Baba-Wilke tarafından bu skeç eşdeğer bir yaklaşım için; ancak işlev, bu vinyete dayalı olarak çizim konumu ve boyutu üzerinde daha ince denetimlere izin verir .


2
Kodunuzu ggplot nesneleri kullanarak çalıştırdığımda, sidebysideplot null. Çıktıyı bir dosyaya kaydetmek istiyorsanız gridArrange kullanın. Bkz. Stackoverflow.com/questions/17059099/…
Jim

@Jim bunu işaret ettiğiniz için teşekkür ederim. Cevabımı gözden geçirdim. Sorularınız varsa bana bildirin.
David LeBauer

1
Grid.aarange şimdi sınırlandırılmış mı?
Atticus29

?grid.arrangebu işlevin artık arrangeGrob olarak adlandırıldığını düşündürüyor. Yaparak istediğimi yapabildim a <- arrangeGrob(p1, p2)ve sonra print(a).
blakeoft

@blakeoft örneklere baktınız mı? grid.arrangehala geçerli, kullanımdan kaldırılmış bir işlevdir. İşlevi kullanmaya çalıştınız mı? Beklediğiniz gibi değilse ne olur.
David LeBauer

159

Çözümlere dayanan bir dezavantaj, grid.arrangeçoğu derginin gerektirdiği gibi, arsaları harflerle (A, B, vb.) Etiketlemeyi zorlaştırmalarıdır.

Bu (ve birkaç diğer) sorunu, özellikle işlevi çözmek için cowplot paketini yazdım plot_grid():

library(cowplot)

iris1 <- ggplot(iris, aes(x = Species, y = Sepal.Length)) +
  geom_boxplot() + theme_bw()

iris2 <- ggplot(iris, aes(x = Sepal.Length, fill = Species)) +
  geom_density(alpha = 0.7) + theme_bw() +
  theme(legend.position = c(0.8, 0.8))

plot_grid(iris1, iris2, labels = "AUTO")

resim açıklamasını buraya girin

Nesne plot_grid()döndürür başka ggplot2 nesnesidir ve bunu kaydedebilirsiniz ggsave()zamanki gibi:

p <- plot_grid(iris1, iris2, labels = "AUTO")
ggsave("plot.pdf", p)

Alternatif olarak, kombine araziler için doğru boyutları elde etmeyi kolaylaştıran, save_plot()etrafındaki ince bir sargı olan kovboy işlevini kullanabilirsiniz ggsave(), örneğin:

p <- plot_grid(iris1, iris2, labels = "AUTO")
save_plot("plot.pdf", p, ncol = 2)

( ncol = 2Argüman, save_plot()yan yana iki çizim olduğunu söyler save_plot()ve kaydedilen görüntüyü iki kat daha geniş yapar.)

Bir ızgarada parsellerin nasıl düzenleneceğine dair daha ayrıntılı bir açıklama için bu skeçe bakın . Paylaşılan bir efsane ile nasıl arsa yapılacağını açıklayan bir skeç de var .

Sık rastlanan bir karışıklık noktası, önizleme paketinin varsayılan ggplot2 temasını değiştirmesidir. Paket bu şekilde davranır çünkü başlangıçta dahili laboratuvar kullanımları için yazılmıştır ve asla varsayılan temayı kullanmayız. Bu sorunlara neden oluyorsa, bunları çözmek için aşağıdaki üç yaklaşımdan birini kullanabilirsiniz:

1. Temayı her çizim için manuel olarak ayarlayın. + theme_bw()Yukarıdaki örnekte yaptığım gibi her konu için her zaman belirli bir tema belirtmenin iyi bir uygulama olduğunu düşünüyorum . Belirli bir tema belirtirseniz, varsayılan tema önemli değildir.

2. Varsayılan temayı tekrar ggplot2 varsayılanına döndürün. Bunu bir kod satırı ile yapabilirsiniz:

theme_set(theme_gray())

3. Paketi bağlamadan börülce fonksiyonlarını çağırın. Ayrıca, önizleme fonksiyonlarını arayarak arayamaz library(cowplot)veya require(cowplot)onun yerine çağrı yapamazsınız cowplot::. Örneğin, ggplot2 varsayılan temasını kullanan yukarıdaki örnek:

## Commented out, we don't call this
# library(cowplot)

iris1 <- ggplot(iris, aes(x = Species, y = Sepal.Length)) +
  geom_boxplot()

iris2 <- ggplot(iris, aes(x = Sepal.Length, fill = Species)) +
  geom_density(alpha = 0.7) +
  theme(legend.position = c(0.8, 0.8))

cowplot::plot_grid(iris1, iris2, labels = "AUTO")

resim açıklamasını buraya girin

Güncellemeler:

  • Cowplot 1.0'dan itibaren varsayılan ggplot2 teması artık değiştirilmiyor.
  • Ggplot2 3.0.0'dan itibaren, grafikler doğrudan etiketlenebilir, bkz. Örneğin .

çıktı da, her iki grafik arka plan temasını kaldırıyor? alternatif var mı?
VAR121

@ VAR121 Evet, bir kod satırı. Tanıtım vinyetinin
Claus Wilke

Bu pakete sahip tüm araziler için aynı y ölçeğine sahip olmak mümkün müdür?
Herman Toothrot

Y ölçeklerini eşleşecek şekilde manuel olarak ayarlamanız gerekir. Veya yüzleşmeyi düşünün.
Claus Wilke

Grid.arrange () yöntemini kullanmadan önce her çizim için bir ggtitle () ayarlayabilirsiniz?
Seanosapien

49

Winston Chang'in R yemek kitabından aşağıdaki multiplotişlevi kullanabilirsiniz

multiplot(plot1, plot2, cols=2)

multiplot <- function(..., plotlist=NULL, cols) {
    require(grid)

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

    numPlots = length(plots)

    # Make the panel
    plotCols = cols                          # Number of columns of plots
    plotRows = ceiling(numPlots/plotCols) # Number of rows needed, calculated from # of cols

    # Set up the page
    grid.newpage()
    pushViewport(viewport(layout = grid.layout(plotRows, plotCols)))
    vplayout <- function(x, y)
        viewport(layout.pos.row = x, layout.pos.col = y)

    # Make each plot, in the correct location
    for (i in 1:numPlots) {
        curRow = ceiling(i/plotCols)
        curCol = (i-1) %% plotCols + 1
        print(plots[[i]], vp = vplayout(curRow, curCol ))
    }

}

24

Patchwork paketini kullanarak, +operatörü kullanabilirsiniz :

library(ggplot2)
library(patchwork)

p1 <- ggplot(mtcars) + geom_point(aes(mpg, disp))
p2 <- ggplot(mtcars) + geom_boxplot(aes(gear, disp, group = gear))


p1 + p2

yama işi


Tam olarak söylemek gerekirse, patchwork artık CRAN'da. Umarım benim küçük düzenlememden
memnunsun

18

Evet, verilerinizi uygun şekilde ayarlamanız gereken methinks. Bunun bir yolu şöyle olabilir:

X <- data.frame(x=rep(x,2),
                y=c(3*x+eps, 2*x+eps),
                case=rep(c("first","second"), each=100))

qplot(x, y, data=X, facets = . ~ case) + geom_smooth()

Eminim plyr ya da yeniden şekillendirme daha iyi hileler vardır - Ben hala Hadley tarafından tüm bu güçlü paketleri hızlandırmak için yeterli değilim.


16

Yeniden şekillendirme paketini kullanarak böyle bir şey yapabilirsiniz.

library(ggplot2)
wide <- data.frame(x = rnorm(100), eps = rnorm(100, 0, .2))
wide$first <- with(wide, 3 * x + eps)
wide$second <- with(wide, 2 * x + eps)
long <- melt(wide, id.vars = c("x", "eps"))
ggplot(long, aes(x = x, y = value)) + geom_smooth() + geom_point() + facet_grid(.~ variable)

12

Ayrıca, bahsetmeye değer çok değişkenli bir paket var. Ayrıca bu cevaba bakınız .

library(ggplot2)
theme_set(theme_bw())

q1 <- ggplot(mtcars) + geom_point(aes(mpg, disp))
q2 <- ggplot(mtcars) + geom_boxplot(aes(gear, disp, group = gear))
q3 <- ggplot(mtcars) + geom_smooth(aes(disp, qsec))
q4 <- ggplot(mtcars) + geom_bar(aes(carb))

library(magrittr)
library(multipanelfigure)
figure1 <- multi_panel_figure(columns = 2, rows = 2, panel_label_type = "none")
# show the layout
figure1

figure1 %<>%
  fill_panel(q1, column = 1, row = 1) %<>%
  fill_panel(q2, column = 2, row = 1) %<>%
  fill_panel(q3, column = 1, row = 2) %<>%
  fill_panel(q4, column = 2, row = 2)
figure1

# complex layout
figure2 <- multi_panel_figure(columns = 3, rows = 3, panel_label_type = "upper-roman")
figure2

figure2 %<>%
  fill_panel(q1, column = 1:2, row = 1) %<>%
  fill_panel(q2, column = 3, row = 1) %<>%
  fill_panel(q3, column = 1, row = 2) %<>%
  fill_panel(q4, column = 2:3, row = 2:3)
figure2

2018-07-06 tarihinde reprex paketi (v0.2.0.9000) tarafından oluşturuldu .


9

ggplot2, bir sayfada arsa düzenlemek için farklı bir sistem sağlayan ızgara grafiklerini temel alır. par(mfrow...)Komut ızgara nesneleri (denilen, doğrudan bir eşdeğer olmayan Grobs ) mutlaka hemen çizilmiş değildir, ancak bir grafik çıkışı için dönüştürülmeden önce depolanmış ve düzenli R nesneleri olarak manipüle edilebilir. Bu, bu temel grafik modelini çizmekten daha fazla esneklik sağlar , ancak strateji mutlaka biraz farklıdır.

Ben grid.arrange()mümkün olduğunca yakın basit bir arayüz sağlamak için yazdı par(mfrow). En basit haliyle, kod şöyle görünecektir:

library(ggplot2)
x <- rnorm(100)
eps <- rnorm(100,0,.2)
p1 <- qplot(x,3*x+eps)
p2 <- qplot(x,2*x+eps)

library(gridExtra)
grid.arrange(p1, p2, ncol = 2)

resim açıklamasını buraya girin

Bu vinyette daha fazla seçenek ayrıntılı .

Sık karşılaşılan bir şikayet, örneklerin farklı boyutlarda eksen etiketlerine sahip olmaları durumunda zorunlu olarak hizalanmamalarıdır, ancak bu tasarım gereğidir: grid.arrangeözel durum ggplot2 nesnelerine girişimde bulunmaz ve bunları diğer grob'lara eşit davranır (örneğin kafes grafikleri) ). Sadece grobları dikdörtgen bir düzende yerleştirir.

Özel ggplot2 nesneleri için, ggarrangebenzer bir arayüzle, çizim panellerini (yönlü grafikler dahil) hizalamaya çalışan ve kullanıcı tarafından tanımlandığında en boy oranlarına uymaya çalışan başka bir işlev yazdım .

library(egg)
ggarrange(p1, p2, ncol = 2)

Her iki işlev de ile uyumludur ggsave(). Farklı seçeneklere ve bazı tarihsel bağlamlara genel bir bakış için, bu vinyet ek bilgi sunar .


9

Güncelleme: Bu cevap çok eski. gridExtra::grid.arrange()artık önerilen yaklaşımdır. Yararlı olması ihtimaline karşı burada bırakıyorum.


Stephen Turner , Genetiği Tamamlama blogunda arrange()işlevi yayınladı (uygulama talimatları için gönderiye bakın)

vp.layout <- function(x, y) viewport(layout.pos.row=x, layout.pos.col=y)
arrange <- function(..., nrow=NULL, ncol=NULL, as.table=FALSE) {
 dots <- list(...)
 n <- length(dots)
 if(is.null(nrow) & is.null(ncol)) { nrow = floor(n/2) ; ncol = ceiling(n/nrow)}
 if(is.null(nrow)) { nrow = ceiling(n/ncol)}
 if(is.null(ncol)) { ncol = ceiling(n/nrow)}
        ## NOTE see n2mfrow in grDevices for possible alternative
grid.newpage()
pushViewport(viewport(layout=grid.layout(nrow,ncol) ) )
 ii.p <- 1
 for(ii.row in seq(1, nrow)){
 ii.table.row <- ii.row 
 if(as.table) {ii.table.row <- nrow - ii.table.row + 1}
  for(ii.col in seq(1, ncol)){
   ii.table <- ii.p
   if(ii.p > n) break
   print(dots[[ii.table]], vp=vp.layout(ii.table.row, ii.col))
   ii.p <- ii.p + 1
  }
 }
}

9
temelde çok eski bir sürümü grid.arrange(o zamanlar posta listelerinde yayınlamamış olsaydım - bu çevrimiçi kaynakları güncellemenin bir yolu yoktur), bana sorarsanız paketlenmiş sürüm daha iyi bir seçimdir
baptiste

4

Kullanma tidyverse:

x <- rnorm(100)
eps <- rnorm(100,0,.2)
df <- data.frame(x, eps) %>% 
  mutate(p1 = 3*x+eps, p2 = 2*x+eps) %>% 
  tidyr::gather("plot", "value", 3:4) %>% 
  ggplot(aes(x = x , y = value)) + 
    geom_point() + 
    geom_smooth() + 
    facet_wrap(~plot, ncol =2)

df

resim açıklamasını buraya girin


1

Bilinmeyenleri analiz etmek için istenen bir adım olan, bir döngü kullanarak birden fazla ggplot grafiği çizmek istiyorsanız yukarıdaki çözümler etkili olmayabilir (örn. Burada istendiği gibi: Bir döngü kullanarak ggplot'ta farklı Y ekseni değerlerine sahip birden fazla grafik oluşturmak ). veya büyük) veri kümeleri (örneğin, bir veri kümesindeki tüm değişkenlerin sayısını çizmek istediğinizde).

Aşağıdaki kod, kaynağı burada bulunan yukarıda belirtilen 'multiplot ()' kullanarak bunu nasıl yapacağınızı gösterir: http://www.cookbook-r.com/Graphs/Multiple_graphs_on_one_page_(ggplot2) :

plotAllCounts <- function (dt){   
  plots <- list();
  for(i in 1:ncol(dt)) {
    strX = names(dt)[i]
    print(sprintf("%i: strX = %s", i, strX))
    plots[[i]] <- ggplot(dt) + xlab(strX) +
      geom_point(aes_string(strX),stat="count")
  }

  columnsToPlot <- floor(sqrt(ncol(dt)))
  multiplot(plotlist = plots, cols = columnsToPlot)
}

Şimdi fonksiyonu çalıştırın - bir sayfada ggplot kullanarak yazdırılan tüm değişkenlerin sayımını almak için

dt = ggplot2::diamonds
plotAllCounts(dt)

Nota biri şeylerin olmasıdır:
kullanırken aes(get(strX))ile çalışırken normalde döngüler içinde kullanmak istiyorsunuz, hangi ggplotyerine yukarıdaki kodda, aes_string(strX)istenen araziler çizmek DEĞİL olacaktır. Bunun yerine, son çizimi birçok kez çizecektir. Neden olduğunu anlayamadım - bunu yapmak zorunda kalabilir aesve aes_stringçağrılır ggplot.

Aksi takdirde, işlevi yararlı bulacağınızı umuyoruz.


1
Kodunuzun plotsiçinde for-loopoldukça verimsiz olan ve önerilmeyen nesneler büyüdüğünü unutmayın R. Bunu yapmak için daha iyi yollar bulmak için bu büyük Mesajları bakınız: Ar Verimli birikimini , bir veri çerçevesinin satırlar üzerinde bir işlevi uygulamak ve tidyverse ile Ar iş akışları Row odaklı
Tung

Değişkenler arasında geçiş yapmanın daha verimli yolu stackoverflow.com/a/52045613/786542tidy evaluationggplot2 v.3.0.0
Tung

0

Benim deneyimime göre gridExtra: grid.arrange, bir döngüde grafikler oluşturmaya çalışıyorsanız mükemmel çalışır.

Kısa Kod Parçacığı:

gridExtra::grid.arrange(plot1, plot2, ncol = 2)

Vaftizcinin 2 Aralık 17: 4'teki cevabı üzerindeki cevabınız nasıl gelişiyor? Cevabınız bir kopya gibi görünüyor. Kabul edilebilir bir cevabı burada
Peter

Grafiği bir döngü içinde gerektiği gibi bölemedim ve dolayısıyla öneri. Başlangıçta, uygulama için döngü için tam snippet'i yazdım, ancak şimdilik buna karşı karar verdim. Tam kodu bir hafta içinde güncelleyecektir.
Mayank Agrawal

Ben ilk etapta kendisi de cowplot paketi kullanarak yapmaya çalıştı ama başarısız oldu. Hızlı taramamda, kimse bir for döngüsü içinde çoklu çizim çözümünden ve dolayısıyla yorumumdan bahsetmemişti. Yanılıyorsam bana herhangi bir yorum tavsiye.
Mayank Agrawal

Cevabınızdaki kod farklı bir for döngüsü içeriyorsa.
Peter

Ben burada bir hafta probs ve Kaggle tüm proje güncelleme. Şerefe.
Mayank Agrawal

-3

cowplotPaket şekli olduğunu takım elbise yayında, size bunu yapmak için güzel bir yol sağlar.

x <- rnorm(100)
eps <- rnorm(100,0,.2)
A = qplot(x,3*x+eps, geom = c("point", "smooth"))+theme_gray()
B = qplot(x,2*x+eps, geom = c("point", "smooth"))+theme_gray()
cowplot::plot_grid(A, B, labels = c("A", "B"), align = "v")

resim açıklamasını buraya girin


3
Ayrıca paket Yazarların daha detaylı cevap ve üzeri gerekçesini bakın stackoverflow.com/a/31223588/199217
David LeBauer
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.