Thêm một chú thích chung cho các ggplots kết hợp


138

Tôi có hai ggplots mà tôi sắp xếp theo chiều ngang grid.arrange. Tôi đã xem qua rất nhiều bài đăng trên diễn đàn, nhưng mọi thứ tôi thử dường như là các lệnh hiện được cập nhật và đặt tên khác.

Dữ liệu của tôi trông như thế này;

# 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")))

Làm thế nào tôi có thể trích xuất huyền thoại từ bất kỳ cốt truyện nào và thêm nó vào dưới cùng / trung tâm của cốt truyện kết hợp?


2
Tôi thỉnh thoảng có vấn đề này. Nếu bạn không muốn tạo ra cốt truyện, giải pháp đơn giản nhất mà tôi biết chỉ là lưu một câu chuyện với một huyền thoại, sau đó sử dụng Photoshop / Ilustrator để dán nó vào các ô huyền thoại trống. Inelegant tôi biết - nhưng thực tế nhanh chóng và dễ dàng.
Stephen Henderson

@StephenHenderson Đó là một câu trả lời. Khía cạnh hoặc hậu xử lý với trình soạn thảo gfx.
Brandon Bertelsen

Câu trả lời:


107

Cập nhật 2015-tháng 2

Xem câu trả lời của Steven dưới đây


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

Đây là cốt truyện kết quả: 2 mảnh đất với truyền thuyết chung


2
cả hai câu trả lời đều trỏ đến cùng một trang wiki có thể được cập nhật khi các phiên bản mới của ggplot2 phá vỡ mã.
baptiste

Hơn sáu năm sau câu trả lời này đã giải quyết vấn đề của tôi. Cảm ơn!
SPK.z

Điều này có thể đơn giản đối với một số / hầu hết mọi người, nhưng tôi đã không hiểu ngay lập tức nên tôi nghĩ tôi sẽ bình luận. Nếu bạn muốn chú thích chung ở đầu cốt truyện (chứ không phải bên dưới), tất cả những gì bạn cần làm là chuyển đổi các đối số. Trong ví dụ trên, mylegend đi trước arrangeGrob(). Bạn cũng cần đảo ngược độ cao (ví dụheights=c(1,10)
ljh2001

113

Bạn cũng có thể sử dụng ggarrange từ gói ggpubr và đặt "common.legend = TRUE":

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")

nhập mô tả hình ảnh ở đây


1
Có thể là điều này không hoạt động trong một ứng dụng sáng bóng (hoặc bảng flexdash) với renderPlot ()? Nó hoạt động hoàn toàn tốt trong một tập lệnh R bình thường với các ô bình thường. Nhưng khi tôi thực hiện chính xác điều tương tự với các ô được tạo bằng renderPlot () trong bảng điều khiển flexd của tôi, không có gì xuất hiện.
Tingolfin

1
Cảm ơn bạn vì điều này - Tôi nghĩ rằng đây là giải pháp đơn giản nhất cho những gì tôi đang tìm kiếm
Komal Rathi

Điều này thật tuyệt! Cảm ơn bạn!
yanes

@Tingolfin Đôi khi tôi phải quấn print(ggarrangeobject)quanh một trong những ggarrangeđồ vật của mình khi tôi cần nó để được vẽ bởi một số chức năng khác, điều đó có thể tương tự như giải pháp cho bạn renderPlot()không?
Brandon

common.legend = TRUElà tất cả những gì tôi cần!
Aryo

62

Câu trả lời của Roland cần cập nhật. Xem: https://github.com/hadley/ggplot2/wiki/Share-a-legend-b between-two-ggplot2-gs

Phương pháp này đã được cập nhật cho ggplot2 v1.0.0.

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)

Lưu ý thiếu ggplot_gtableggplot_build. ggplotGrobđược sử dụng thay thế. Ví dụ này phức tạp hơn một chút so với giải pháp trên nhưng nó vẫn giải quyết được cho tôi.


10
Xin chào, tôi có 6 ô, và tôi muốn sắp xếp 6 ô thành 2 hàng × 3 col và vẽ chú thích trên đầu, vậy làm thế nào để thay đổi chức năng grid_arrange_shared_legend? Cảm ơn bạn!
just_rookie

4
@just_rookie bạn đã tìm ra giải pháp làm thế nào để thay đổi chức năng sao cho người ta có thể sử dụng các cách sắp xếp ncol và nrow khác nhau thay vì chỉ ncol = 1?
Giuseppe

Xin chào, tôi đã thử giải pháp này, nó hoạt động tốt, tuy nhiên khi in nó, tôi có 2 trang pdf thay vì chỉ 1, trang đầu tiên trống trong khi phần sau chứa cốt truyện của tôi, tại sao tôi lại có hành vi như vậy? cảm ơn,
HanniBaL90

Đối với bất cứ ai có được isse giống như tôi, đây là một cách giải quyết: stackoverflow.com/questions/12481267/iêu
HanniBaL90

1
Công cụ tuyệt vời ở đây. Bất kỳ ý tưởng làm thế nào một người có thể thêm một tiêu đề cho tất cả các lô?
Pertinax

27

Một giải pháp mới, hấp dẫn là sử dụng patchwork. Cú pháp rất đơn giản:

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")

Được tạo vào ngày 2019-12-13 bằng gói reprex (v0.2.1)


2
Nếu bạn thay đổi một chút thứ tự các lệnh, bạn có thể thực hiện việc này trong một dòng: combined <- p1 + p2 + plot_layout(guides = "collect") & theme(legend.position = "bottom")
mlcyo

17

Tôi đề nghị sử dụng cowplot. Từ họa tiết R của họ :

# 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

cốt truyện kết hợp với huyền thoại ở phía dưới


Đây là cách duy nhất, đó là đánh dấu một possibled để đặt một tay huyền thoại trong cốt truyện của tôi với annotate_figure(ggarrange()), sử dụng một legend_b (). Cảm ơn bạn rất nhiều, chúa blesse bạn!
Jean Karlos

12

@Giuseppe, bạn có thể muốn xem xét điều này cho một đặc điểm kỹ thuật linh hoạt của sắp xếp lô (được sửa đổi từ đây ):

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)

}

Đối số bổ sung nrowncolkiểm soát bố cục của các ô được sắp xếp:

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)

nhập mô tả hình ảnh ở đây nhập mô tả hình ảnh ở đây


Tương tự như đối với giải pháp khác, tôi đã thử nó, nó hoạt động tốt, tuy nhiên khi in nó, tôi có 2 trang pdf thay vì chỉ 1, trang đầu tiên trống trong khi phần sau chứa cốt truyện của tôi, tại sao tôi lại có hành vi như vậy? cảm ơn,
HanniBaL90

Đối với bất cứ ai có được isse giống như tôi, đây là một cách giải quyết: stackoverflow.com/questions/12481267/iêu
HanniBaL90

Ai đó có thể giải thích cho tôi giải pháp? Làm thế nào tôi có thể đặt huyền thoại ở trên cùng thay vì dưới cùng? Cảm ơn
HanniBaL90

8

Nếu bạn đang vẽ các biến giống nhau trong cả hai ô, cách đơn giản nhất là kết hợp các khung dữ liệu thành một, sau đó sử dụng facet_wrap.

Ví dụ của bạn:

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)

Lô 1

Một ví dụ khác sử dụng bộ dữ liệu kim cương. Điều này cho thấy rằng bạn thậm chí có thể làm cho nó hoạt động nếu bạn chỉ có một biến chung giữa các lô của bạn.

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("")

Lô 2

Điều khó khăn duy nhất với ví dụ thứ hai là các biến nhân tố bị ép thành số khi bạn kết hợp mọi thứ vào một khung dữ liệu. Vì vậy, lý tưởng, bạn sẽ làm điều này chủ yếu khi tất cả các biến quan tâm của bạn là cùng một loại.


1

@ Hướng dẫn:

Tôi không biết Grobs, v.v., nhưng tôi đã hack cùng một giải pháp cho hai lô, có thể mở rộng thành số tùy ý nhưng nó không phải là một chức năng gợi cảm:

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

Nếu truyền thuyết giống nhau cho cả hai ô, có một giải pháp đơn giản bằng cách sử dụng grid.arrange(giả sử bạn muốn chú thích của mình thẳng hàng với cả hai ô theo chiều dọc hoặc chiều ngang). Đơn giản chỉ cần giữ huyền thoại cho cốt truyện dưới cùng hoặc bên phải nhất trong khi bỏ qua huyền thoại cho cái khác. Tuy nhiên, việc thêm một huyền thoại vào một cốt truyện, làm thay đổi kích thước của một âm mưu so với một âm mưu khác. Để tránh điều này, hãy sử dụng heightslệnh để điều chỉnh thủ công và giữ cho chúng có cùng kích thước. Bạn thậm chí có thể sử dụng grid.arrangeđể làm tiêu đề trục phổ biến. Lưu ý rằng điều này sẽ yêu cầu library(grid)ngoài library(gridExtra). Đối với các ô dọc:

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

Đây là kết quả cho một biểu đồ tương tự cho một dự án tôi đang thực hiện: nhập mô tả hình ảnh ở đây

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.