Birleşik ggplotlar için ortak bir Efsane ekleyin


138

Yatay olarak hizaladığım iki ggplotum var grid.arrange. Birçok forum gönderisine baktım, ancak denediğim her şey şimdi güncellenen ve başka bir şey olarak adlandırılan komutlar gibi görünüyor.

Verilerim şöyle görünüyor;

# Data plot 1                                   
        axis1     axis2   
group1 -0.212201  0.358867
group2 -0.279756 -0.126194
group3  0.186860 -0.203273
group4  0.417117 -0.002592
group1 -0.212201  0.358867
group2 -0.279756 -0.126194
group3  0.186860 -0.203273
group4  0.186860 -0.203273

# Data plot 2   
        axis1     axis2
group1  0.211826 -0.306214
group2 -0.072626  0.104988
group3 -0.072626  0.104988
group4 -0.072626  0.104988
group1  0.211826 -0.306214
group2 -0.072626  0.104988
group3 -0.072626  0.104988
group4 -0.072626  0.104988

#And I run this:
library(ggplot2)
library(gridExtra)


groups=c('group1','group2','group3','group4','group1','group2','group3','group4')

x1=data1[,1]
y1=data1[,2]

x2=data2[,1]
y2=data2[,2]

p1=ggplot(data1, aes(x=x1, y=y1,colour=groups)) + geom_point(position=position_jitter(w=0.04,h=0.02),size=1.8)

p2=ggplot(data2, aes(x=x2, y=y2,colour=groups)) + geom_point(position=position_jitter(w=0.04,h=0.02),size=1.8)

#Combine plots
p3=grid.arrange(
p1 + theme(legend.position="none"), p2+ theme(legend.position="none"), nrow=1, widths = unit(c(10.,10), "cm"), heights = unit(rep(8, 1), "cm")))

Efsaneyi bu grafiklerden herhangi birinden nasıl çıkarabilirim ve birleşik grafiğin altına / merkezine nasıl eklerim?


2
Bazen bu problemim var. Grafiği düzeltmek istemiyorsanız, bildiğim en kolay çözüm sadece bir efsane ile kurtarmaktır, sonra boş efsane arazilere yapıştırmak için Photoshop / Ilustrator kullanın. Yetersiz biliyorum - ama pratik hızlı ve kolay.
Stephen Henderson

@StephenHenderson Bu bir cevap. Gfx editörü ile faset veya post-process.
Brandon Bertelsen

Yanıtlar:


107

Güncelleme 2015-Şubat

Aşağıdaki Steven'ın cevabına bakın


df1 <- read.table(text="group   x     y   
group1 -0.212201  0.358867
group2 -0.279756 -0.126194
group3  0.186860 -0.203273
group4  0.417117 -0.002592
group1 -0.212201  0.358867
group2 -0.279756 -0.126194
group3  0.186860 -0.203273
group4  0.186860 -0.203273",header=TRUE)

df2 <- read.table(text="group   x     y   
group1  0.211826 -0.306214
group2 -0.072626  0.104988
group3 -0.072626  0.104988
group4 -0.072626  0.104988
group1  0.211826 -0.306214
group2 -0.072626  0.104988
group3 -0.072626  0.104988
group4 -0.072626  0.104988",header=TRUE)


library(ggplot2)
library(gridExtra)

p1 <- ggplot(df1, aes(x=x, y=y,colour=group)) + geom_point(position=position_jitter(w=0.04,h=0.02),size=1.8) + theme(legend.position="bottom")

p2 <- ggplot(df2, aes(x=x, y=y,colour=group)) + geom_point(position=position_jitter(w=0.04,h=0.02),size=1.8)

#extract legend
#https://github.com/hadley/ggplot2/wiki/Share-a-legend-between-two-ggplot2-graphs
g_legend<-function(a.gplot){
  tmp <- ggplot_gtable(ggplot_build(a.gplot))
  leg <- which(sapply(tmp$grobs, function(x) x$name) == "guide-box")
  legend <- tmp$grobs[[leg]]
  return(legend)}

mylegend<-g_legend(p1)

p3 <- grid.arrange(arrangeGrob(p1 + theme(legend.position="none"),
                         p2 + theme(legend.position="none"),
                         nrow=1),
             mylegend, nrow=2,heights=c(10, 1))

Ortaya çıkan çizim: Ortak efsane ile 2 parsel


2
her iki yanıt da aynı wiki sayfasına işaret eder ve ggplot2'nin yeni sürümleri kodu kırarken güncellenebilir.
vaftiz

Altı yıldan fazla bir süre sonra bu cevap sorunumu çözdü. Teşekkürler!
SPK.z

Bu, bazı / çoğu insan için basit olabilir, ama hemen alamadım, bu yüzden yorum yapacağımı düşündüm. Ortak efsanenin çizimin üstünde olmasını istiyorsanız (aşağıda değil), tek yapmanız gereken argümanları değiştirmek. Yukarıdaki örnekte, mylegend daha önce gitmektedir arrangeGrob(). Ayrıca yükseklikleri ters çevirmeniz gerekir (yaniheights=c(1,10)
ljh2001

113

Ayrıca kullanabilir ggarrange gelen ggpubr "common.legend DOĞRU =" paket ve seti:

library(ggpubr)

dsamp <- diamonds[sample(nrow(diamonds), 1000), ]
p1 <- qplot(carat, price, data = dsamp, colour = clarity)
p2 <- qplot(cut, price, data = dsamp, colour = clarity)
p3 <- qplot(color, price, data = dsamp, colour = clarity)
p4 <- qplot(depth, price, data = dsamp, colour = clarity) 

ggarrange(p1, p2, p3, p4, ncol=2, nrow=2, common.legend = TRUE, legend="bottom")

resim açıklamasını buraya girin


1
Bunun renderPlot () ile parlak bir uygulama (veya flexdashboard) içinde çalışmaması mümkün mü? Normal grafiklerle normal bir R komut dosyasında mükemmel çalışır. Ancak flexdashboard'umda renderPlot () ile yapılan arazilerle aynı şeyi yaptığımda hiçbir şey görünmüyor.
Tingolfin

1
Bunun için teşekkür ederim - Bence bu aradığım şey için en kolay çözümdü
Komal Rathi

Bu harika! Teşekkür ederim!
yanes

@Tingolfin Bazen başka bir fonksiyon tarafından çizilmesi gerektiğinde nesnelerimden print(ggarrangeobject)birinin etrafına sarmak zorunda kaldım ggarrange, bu sizin çözümünüze benzer olabilir renderPlot()mi?
Brandon

common.legend = TRUEihtiyacım olan tek şey!
Aryo

62

Roland'ın cevabının güncellenmesi gerekiyor. Bkz. Https://github.com/hadley/ggplot2/wiki/Share-a-legend-between-two-ggplot2-graphs

Bu yöntem ggplot2 v1.0.0 için güncellendi.

library(ggplot2)
library(gridExtra)
library(grid)


grid_arrange_shared_legend <- function(...) {
    plots <- list(...)
    g <- ggplotGrob(plots[[1]] + theme(legend.position="bottom"))$grobs
    legend <- g[[which(sapply(g, function(x) x$name) == "guide-box")]]
    lheight <- sum(legend$height)
    grid.arrange(
        do.call(arrangeGrob, lapply(plots, function(x)
            x + theme(legend.position="none"))),
        legend,
        ncol = 1,
        heights = unit.c(unit(1, "npc") - lheight, lheight))
}

dsamp <- diamonds[sample(nrow(diamonds), 1000), ]
p1 <- qplot(carat, price, data=dsamp, colour=clarity)
p2 <- qplot(cut, price, data=dsamp, colour=clarity)
p3 <- qplot(color, price, data=dsamp, colour=clarity)
p4 <- qplot(depth, price, data=dsamp, colour=clarity)
grid_arrange_shared_legend(p1, p2, p3, p4)

Olmayışına dikkat ggplot_gtableve ggplot_build. ggplotGrobyerine kullanılır. Bu örnek yukarıdaki çözümden biraz daha kıvrımlıdır, ancak yine de benim için çözdü.


10
Merhaba, 6 parselim var ve 6 parsel 2 satır × 3 col olarak düzenlemek ve efsaneyi üstte çizmek istiyorum, bu yüzden işlevi nasıl değiştirebilirim grid_arrange_shared_legend? Teşekkür ederim!
just_rookie

4
@just_rookie işlevi değiştirmek yerine sadece farklı ncol ve nrow düzenlemeleri kullanabilmek için bir çözüm buldunuz ncol = 1mu?
Giuseppe

Merhaba, ben bu çözümü denedim, iyi çalışıyor, ancak yazdırırken, ben sadece 1 yerine 2 pdf sayfa var, ilk boş ise daha sonra benim arsa içeriyor, neden böyle bir davranış var? teşekkürler,
HanniBaL90

benim için nasıl aynı olsun, herkes için bir çözüm var: stackoverflow.com/questions/12481267/…
HanniBaL90 20:17

1
Burada harika şeyler. Tüm parseller için tek bir başlık nasıl eklenebilir?
Pertinax

27

Yeni, çekici bir çözüm kullanmaktır patchwork. Sözdizimi çok basit:

library(ggplot2)
library(patchwork)

p1 <- ggplot(df1, aes(x = x, y = y, colour = group)) + 
  geom_point(position = position_jitter(w = 0.04, h = 0.02), size = 1.8)
p2 <- ggplot(df2, aes(x = x, y = y, colour = group)) + 
  geom_point(position = position_jitter(w = 0.04, h = 0.02), size = 1.8)

combined <- p1 + p2 & theme(legend.position = "bottom")
combined + plot_layout(guides = "collect")

2019-12-13 tarihinde reprex paketi tarafından oluşturuldu (v0.2.1)


2
Komutların sırasını biraz değiştirirseniz, bunu bir satırda yapabilirsiniz: combined <- p1 + p2 + plot_layout(guides = "collect") & theme(legend.position = "bottom")
mlcyo

17

Cowplot kullanmanızı öneririm. Onların Gönderen R skeç :

# load cowplot
library(cowplot)

# down-sampled diamonds data set
dsamp <- diamonds[sample(nrow(diamonds), 1000), ]

# Make three plots.
# We set left and right margins to 0 to remove unnecessary spacing in the
# final plot arrangement.
p1 <- qplot(carat, price, data=dsamp, colour=clarity) +
   theme(plot.margin = unit(c(6,0,6,0), "pt"))
p2 <- qplot(depth, price, data=dsamp, colour=clarity) +
   theme(plot.margin = unit(c(6,0,6,0), "pt")) + ylab("")
p3 <- qplot(color, price, data=dsamp, colour=clarity) +
   theme(plot.margin = unit(c(6,0,6,0), "pt")) + ylab("")

# arrange the three plots in a single row
prow <- plot_grid( p1 + theme(legend.position="none"),
           p2 + theme(legend.position="none"),
           p3 + theme(legend.position="none"),
           align = 'vh',
           labels = c("A", "B", "C"),
           hjust = -1,
           nrow = 1
           )

# extract the legend from one of the plots
# (clearly the whole thing only makes sense if all plots
# have the same legend, so we can arbitrarily pick one.)
legend_b <- get_legend(p1 + theme(legend.position="bottom"))

# add the legend underneath the row we made earlier. Give it 10% of the height
# of one plot (via rel_heights).
p <- plot_grid( prow, legend_b, ncol = 1, rel_heights = c(1, .2))
p

altta efsane ile birleşik araziler


Bu tek yoluydu, bu bir arsaya bir legend_b () kullanarak manuel bir efsane annotate_figure(ggarrange())koyma olasılığını yarattı. Çok teşekkür ederim, tanrı seni kutsasın!
Jean Karlos

12

@Giuseppe, bunu parsel düzenlemesinin ( buradan değiştirilmiş ) esnek bir spesifikasyonu için düşünmek isteyebilirsiniz :

library(ggplot2)
library(gridExtra)
library(grid)

grid_arrange_shared_legend <- function(..., nrow = 1, ncol = length(list(...)), position = c("bottom", "right")) {

  plots <- list(...)
  position <- match.arg(position)
  g <- ggplotGrob(plots[[1]] + theme(legend.position = position))$grobs
  legend <- g[[which(sapply(g, function(x) x$name) == "guide-box")]]
  lheight <- sum(legend$height)
  lwidth <- sum(legend$width)
  gl <- lapply(plots, function(x) x + theme(legend.position = "none"))
  gl <- c(gl, nrow = nrow, ncol = ncol)

  combined <- switch(position,
                     "bottom" = arrangeGrob(do.call(arrangeGrob, gl),
                                            legend,
                                            ncol = 1,
                                            heights = unit.c(unit(1, "npc") - lheight, lheight)),
                     "right" = arrangeGrob(do.call(arrangeGrob, gl),
                                           legend,
                                           ncol = 2,
                                           widths = unit.c(unit(1, "npc") - lwidth, lwidth)))
  grid.newpage()
  grid.draw(combined)

}

Ekstra argümanlar nrowve ncoldüzenlenmiş grafiklerin düzenini kontrol et:

dsamp <- diamonds[sample(nrow(diamonds), 1000), ]
p1 <- qplot(carat, price, data = dsamp, colour = clarity)
p2 <- qplot(cut, price, data = dsamp, colour = clarity)
p3 <- qplot(color, price, data = dsamp, colour = clarity)
p4 <- qplot(depth, price, data = dsamp, colour = clarity)
grid_arrange_shared_legend(p1, p2, p3, p4, nrow = 1, ncol = 4)
grid_arrange_shared_legend(p1, p2, p3, p4, nrow = 2, ncol = 2)

resim açıklamasını buraya girin resim açıklamasını buraya girin


Diğer çözüm için aynı, ben denedim, iyi çalışıyor, ancak yazdırırken, sadece 1 yerine 2 pdf sayfa var, ilk boş ise daha sonra benim arsa içeriyor, neden böyle bir davranış var? teşekkürler,
HanniBaL90

benim için nasıl aynı olsun, herkes için bir çözüm var: stackoverflow.com/questions/12481267/…
HanniBaL90 20:17

Birisi bana çözümü açıklayabilir mi? Efsaneyi alt yerine üste nasıl yerleştirebilirim? Teşekkürler
HanniBaL90

8

Her iki grafikte de aynı değişkenleri çiziyorsanız, en basit yol veri çerçevelerini birde birleştirmek ve sonra facet_wrap kullanmaktır.

Örneğiniz için:

big_df <- rbind(df1,df2)

big_df <- data.frame(big_df,Df = rep(c("df1","df2"),
times=c(nrow(df1),nrow(df2))))

ggplot(big_df,aes(x=x, y=y,colour=group)) 
+ geom_point(position=position_jitter(w=0.04,h=0.02),size=1.8) 
+ facet_wrap(~Df)

Arsa 1

Elmas veri kümesini kullanan başka bir örnek. Bu, grafikleriniz arasında ortak tek bir değişkeniniz varsa bile çalıştırabileceğinizi gösterir.

diamonds_reshaped <- data.frame(price = diamonds$price,
independent.variable = c(diamonds$carat,diamonds$cut,diamonds$color,diamonds$depth),
Clarity = rep(diamonds$clarity,times=4),
Variable.name = rep(c("Carat","Cut","Color","Depth"),each=nrow(diamonds)))

ggplot(diamonds_reshaped,aes(independent.variable,price,colour=Clarity)) + 
geom_point(size=2) + facet_wrap(~Variable.name,scales="free_x") + 
xlab("")

Arsa 2

İkinci örnekle ilgili sadece zor olan şey, her şeyi tek bir veri çerçevesine birleştirdiğinizde faktör değişkenlerinin sayısal olarak zorlanmasıdır. İdeal olarak, bunu tüm ilgilenen değişkenleriniz aynı tipte olduğunda yapacaksınız.


1

@Guiseppe:

Ben Grobs vb hiçbir fikrim yok, ama ben birlikte iki parsel için bir çözüm kesmek, keyfi sayıya genişletmek mümkün olmalı ama seksi bir işlevi değil:

plots <- list(p1, p2)
g <- ggplotGrob(plots[[1]] + theme(legend.position="bottom"))$grobs
legend <- g[[which(sapply(g, function(x) x$name) == "guide-box")]]
lheight <- sum(legend$height)
tmp <- arrangeGrob(p1 + theme(legend.position = "none"), p2 + theme(legend.position = "none"), layout_matrix = matrix(c(1, 2), nrow = 1))
grid.arrange(tmp, legend, ncol = 1, heights = unit.c(unit(1, "npc") - lheight, lheight))

1

Gösterge her iki grafik için de aynıysa, basit bir çözüm vardır grid.arrange(efsanenizin dikey veya yatay olarak her iki grafikle hizalanmasını istediğinizi varsayarsak). Biri için efsaneyi çıkarırken efsaneyi en altta veya en sağda olan arsa için saklayın. Ancak, yalnızca bir grafiğe bir açıklama eklemek, bir grafiğin boyutunu diğerine göre değiştirir. Bunu önlemek heightsiçin manuel olarak aynı boyutta ayarlama ve koruma komutunu kullanın. grid.arrangeOrtak eksen başlıkları oluşturmak için bile kullanabilirsiniz . Buna library(grid)ek olarak gerekeceğini unutmayın library(gridExtra). Dikey grafikler için:

y_title <- expression(paste(italic("E. coli"), " (CFU/100mL)"))

grid.arrange(arrangeGrob(p1, theme(legend.position="none"), ncol=1), arrangeGrob(p2, theme(legend.position="bottom"), ncol=1), heights=c(1,1.2), left=textGrob(y_title, rot=90, gp=gpar(fontsize=20)))

İşte üzerinde çalıştığım bir proje için benzer bir grafiğin sonucu: resim açıklamasını buraya girin

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.