결합 된 ggplot에 공통 범례 추가


138

가로로 정렬되는 두 개의 ggplot이 grid.arrange있습니다. 나는 많은 포럼 게시물을 살펴 보았지만 내가 시도하는 모든 것은 이제 업데이트되고 다른 이름이 지정된 명령 인 것 같습니다.

내 데이터는 다음과 같습니다.

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

이 플롯에서 범례를 추출하여 결합 된 플롯의 맨 아래 / 가운데에 추가하려면 어떻게해야합니까?


2
때때로이 문제가 발생합니다. 플롯을 패싯으로 표시하지 않으려는 경우 가장 쉬운 해결책은 범례를 사용하여 저장하고 Photoshop / Ilustrator를 사용하여 빈 범례 플롯에 붙여 넣는 것입니다. 내가 아는 우아하지만 실용적이고 빠르고 쉽습니다.
Stephen Henderson

@StephenHenderson 답변입니다. gfx 편집기로 패싯 또는 후 처리.
Brandon Bertelsen

답변:


107

2015 년 2 월 업데이트

아래 스티븐의 답변을 참조하십시오


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

결과 플롯은 다음과 같습니다. 공통 범례가있는 2 개의 플롯


2
두 답변 모두 동일한 버전의 위키 페이지 를 가리키며 ggplot2의 새로운 버전이 코드를 깨뜨릴 때 업데이트 될 수 있습니다.
baptiste

6 년이 지난 후이 답변은 내 문제를 해결했습니다. 감사!
SPK.z

이것은 일부 / 대부분의 사람들에게 간단 할 수 있지만, 나는 그것을 즉시 얻지 못했기 때문에 내가 의견을 말할 것이라고 생각했습니다. 아래가 아닌 플롯 위에 공통 범례를 원하면 인수를 전환하기 만하면됩니다. 위의 예에서 mylegend는 이전에갑니다 arrangeGrob(). 또한 높이를 반대로해야합니다 (예 :heights=c(1,10)
ljh2001

113

당신은 또한 사용할 수 있습니다 ggarrange을 에서 ggpubr의 "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")

여기에 이미지 설명을 입력하십시오


1
renderPlot ()을 사용하여 반짝이는 응용 프로그램 (또는 flexdashboard)에서 작동하지 않을 수 있습니까? 일반 플롯이있는 일반 R 스크립트에서 완벽하게 작동합니다. 그러나 flexdashboard에서 renderPlot ()으로 만든 플롯으로 똑같은 작업을 수행하면 아무 것도 나타나지 않습니다.
Tingolfin

1
나는 이것이 내가 찾던위한 가장 쉬운 해결책으로 생각 -이 주셔서 감사합니다
코멀 라티

대단해! 감사합니다!
yanes

@Tingolfin 때로는 다른 함수로 플롯해야 할 때 print(ggarrangeobject)ggarrange객체 중 하나를 감싸 야 했습니다 renderPlot().
브랜든

common.legend = TRUE내가 필요한 전부입니다!
아요

62

롤랜드의 답변을 업데이트해야합니다. 참조 : https://github.com/hadley/ggplot2/wiki/Share-a-legend-between-two-ggplot2-graphs

이 방법은 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)

ggplot_gtable및 의 부재에 유의하십시오 ggplot_build. ggplotGrob대신 사용됩니다. 이 예제는 위의 솔루션보다 약간 복잡하지만 여전히 나를 위해 해결되었습니다.


10
안녕하세요, 나는 6 개의 플롯을 가지고 있으며 6 플롯을 2 행 × 3 열로 정렬하고 상단에 범례를 그리려면 함수를 변경하는 방법은 grid_arrange_shared_legend무엇입니까? 감사합니다!
just_rookie

4
@ just_rookie 함수를 변경하는 방법에 대한 해결책을 찾았으므로 다른 ncol 및 nrow 배열 만 사용할 수 ncol = 1있습니까?
주세페

안녕하세요,이 솔루션을 사용해 보았지만 제대로 작동하지만 인쇄 할 때 1 대신 2 pdf 페이지를 얻었습니다. 첫 번째는 비어있는 반면 나중에 내 음모가 포함되어 있습니다. 왜 그런 동작이 있습니까? 감사합니다,
HanniBaL90

사람이 어떻게 나 같은 ISSE를 얻기 위해, 여기에 해결 방법은 다음과 같습니다 stackoverflow.com/questions/12481267/...
HanniBaL90

1
여기 좋은 물건. 모든 플롯에 대해 하나의 제목을 추가하는 방법에 대한 아이디어가 있습니까?
Pertinax

27

새롭고 매력적인 솔루션은 사용하는 것 patchwork입니다. 구문은 매우 간단합니다.

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

reprex 패키지로 2019-12-13에 작성 (v0.2.1)


2
명령 순서를 약간 변경하면 한 줄로 수행 할 수 있습니다. combined <- p1 + p2 + plot_layout(guides = "collect") & theme(legend.position = "bottom")
mlcyo

17

cowplot을 사용하는 것이 좋습니다. 그들의 R 삽화에서 :

# 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

맨 아래에 범례가있는 플롯을 결합


이것은 유일한 방법으로, legend_b ()를 사용하여 와 함께 내 플롯에 수동 범례 를 넣을 수있게했습니다 annotate_figure(ggarrange()). 정말 고마워요, 신 이여!
Jean Karlos

12

@Giuseppe, 당신은 플롯 배열의 유연한 사양 ( 여기 에서 수정)을 위해 이것을 고려할 수 있습니다 :

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)

}

추가 인수 nrowncol배열 된 플롯의 레이아웃을 제어합니다.

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)

여기에 이미지 설명을 입력하십시오 여기에 이미지 설명을 입력하십시오


다른 솔루션과 동일하게 시도했지만 잘 작동했지만 인쇄 할 때 1 대신 2 pdf 페이지를 얻었습니다. 첫 번째는 비어있는 반면 나중에 내 줄거리가 포함 된 이유는 무엇입니까? 감사합니다,
HanniBaL90

사람이 어떻게 나 같은 ISSE를 얻기 위해, 여기에 해결 방법은 다음과 같습니다 stackoverflow.com/questions/12481267/...
HanniBaL90

누군가 나에게 해결책을 설명 할 수 있습니까? 어떻게 범례를 맨 아래 대신 맨 위에 배치 할 수 있습니까? 감사합니다
HanniBaL90 2016 년

8

두 플롯 모두에 동일한 변수를 플롯하는 경우 가장 간단한 방법은 데이터 프레임을 하나로 결합한 다음 facet_wrap을 사용하는 것입니다.

예를 들어 :

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)

줄거리 1

다이아몬드 데이터 세트를 사용하는 다른 예. 이것은 플롯 사이에 하나의 변수 공통이있는 경우에도 작동하게 할 수 있음을 보여줍니다.

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

줄거리 2

두 번째 예의 까다로운 점은 모든 것을 하나의 데이터 프레임으로 결합 할 때 요인 변수가 숫자로 강제 변환된다는 것입니다. 따라서 이상적으로는 모든 관심 변수가 동일한 유형일 때 주로이 작업을 수행합니다.


1

@Guiseppe :

나는 Grobs 등을 전혀 모릅니다.하지만 두 음모에 대한 해킹을 해킹했습니다. 임의의 숫자로 확장 할 수는 있지만 섹시한 기능은 아닙니다.

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

범례가 두 플롯에 대해 동일 grid.arrange하면 다음을 사용하는 간단한 해결책 이 있습니다 (범례가 두 플롯과 수직 또는 수평으로 정렬되기를 원한다고 가정). 범례는 맨 아래 또는 맨 오른쪽 줄거리에 대한 범례를 유지하면서 다른 쪽 범례는 생략하십시오. 그러나 하나의 플롯에 범례를 추가하면 한 플롯의 크기가 다른 플롯에 비해 변경됩니다. 이를 피하려면 heights명령을 사용하여 수동으로 조정하고 동일한 크기를 유지하십시오. grid.arrange공통 축 제목을 만드는 데 사용할 수도 있습니다 . 이 외에도을 (를) 필요 library(grid)로합니다 library(gridExtra). 수직 플롯의 경우 :

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

내가 작업 한 프로젝트와 비슷한 그래프의 결과는 다음과 같습니다. 여기에 이미지 설명을 입력하십시오

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.