Add a common Legend for combined ggplots
我有两个ggplots,它们与
我的数据看起来像这样;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | # 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"))) |
如何从任何这些图中提取图例并将其添加到组合图的底部/中心?
您也可以从ggpubr包中使用ggarrange并设置" common.legend = TRUE":
1 2 3 4 5 6 7 8 9 | 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") |
2015年2月更新
请参阅下面的史蒂文答案
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | 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)) |
这是结果图:
罗兰的答案需要更新。参见:https://github.com/hadley/ggplot2/wiki/Share-a-legend-between-two-ggplot2-graphs
此方法已针对ggplot2 v1.0.0更新。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | 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) |
请注意缺少
一种新的,有吸引力的解决方案是使用
1 2 3 4 5 6 7 8 9 10 | 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") |
我建议使用Cowplot。从他们的R小插图:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | # 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 |
@Giuseppe,您可能需要考虑这一点,以灵活地指定地块布置(从此处进行修改):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | 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) } |
额外的参数
1 2 3 4 5 6 7 | 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) |
如果要在两个图中绘制相同的变量,则最简单的方法是将数据帧组合为一个,然后使用facet_wrap。
例如:
1 2 3 4 5 6 7 8 | 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) |
使用Diamonds数据集的另一个示例。这表明,如果您的绘图之间只有一个公用变量,您甚至可以使它起作用。
1 2 3 4 5 6 7 8 | 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("") |
第二个示例唯一棘手的事情是,当您将所有内容组合到一个数据框中时,因子变量将被强制转换为数值。因此,理想情况下,主要是在所有感兴趣的变量都属于同一类型时才执行此操作。
如果两个图例的图例都相同,则有一个使用
这是我正在从事的项目的类似图形的结果:
@吉塞佩:
我完全不知道Grobs等问题,但是我为两个图表共同制定了一个解决方案,应该可以扩展到任意数,但不能扩展为性感函数:
1 2 3 4 5 6 | 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)) |