본문 바로가기

[R] 여러 그래프 한 번에 나타내기 1: ggplot2, gridExtra

R Programming/Data Visualization by Mandarim_ 2022. 7. 24.
여러 그래프 한 번에 나타내기의 필요성

 

결과 비교를 목적으로 한 그래프를 그릴 때, 여러 상황의 그래프를 한 번에 나열하는 것이 효율적이다.

예시의 논문 (Qian과 Murphy, 2011) 그림처럼 말이다. 확실히 깔끔하다.

논문은 다른 연구자/에디터에게 내 결과를 설득시키고 인정 받아야하는 하나의 글이기 때문에, 내 발견의 노벨티 그 자체도 중요하지만 자신의 결과를 잘 전달하는 것도 중요하다.

그러니 각 그래프를 하나씩 캡쳐해서 짜집기 할 순 없다.

 

 

따라하고 싶은 논문의 그림
doi:  10.1214/10-AOS864

 


 

R 코드 - 기본

 

여러 그래프를 한 번에 나타내주는 par() 라는 함수가 이미 R에 내장되어 있지만 ggplot에선 적용되지 않기 때문에 나는 잘 사용하진 않는다.

그리고 위의 논문 그래프처럼 대제목(전체 그래프에 대한 제목) 만들거나 전체 그래프에 대한 범례 옵션은 없는 것 같다. (글쓴이 추측)

내가 자주쓰는 패키지는 gridExtra 패캐지의 grid.arrange()이다.

 

임의로 작성한 데이터인데, 아래의 형태로 되어 있는 것이 그래프 그리기 편하다.

Example1에서는 A 방법이 잘 하고 Example2에서는 B방법이 더 잘하는 가상의 결과를 갖는 데이터셋을 생성하였다.

grid.arrange()는 아래의 코드처럼 간단하게 작성되며, ncol과 nrow 옵션을 통해 분할하려는 수 조정이 가능하다.

 

results <- data.frame("Example" = c("1","1","2","2", "1","1","2","2"),
                      "N" = c("100", "200", "100", "200", "100", "200", "100", "200"),
                      "Method" = c("A","A","A","A", "B","B","B","B"),
                      "Accuracy" = c(0.98, 0.9, 0.8, 0.7, 0.95, 0.84,0.92,0.88))

tmp1 <- results[results$Example==1, ]
tmp2 <- results[results$Example==2, ]

theme_set(theme_bw())
g1 <- ggplot(data=tmp1) + geom_point(aes(x=N, y=Accuracy, shape=Method, color=Method)) + ggtitle("Example 1")
g2 <- ggplot(data=tmp2) + geom_point(aes(x=N, y=Accuracy, shape=Method, color=Method)) + ggtitle("Example 2")

grid.arrange(g1, g2, ncol=2)

 

 

예시 그림 1
만들어진 데이터셋에 대한 그래프는 다음과 같이 그려진다. (위의 코드가 작동되었을 때 나오는 결과입니다.)


반응형

R코드 - 옵션 조정

 

그래프를 합쳤다! 하지만 이게 끝은 아니다.

예시로 든 논문의 그래프는 example 마다 y축이 달라지는 그래프지만,

이 포스팅에서 직접 생성한 예제 데이터의 경우 y축이 Accuracy 이다. Accuracy의 경우 example에 상관없이 항상 0과 1 사이를 갖는데, 함께 나열한 그래프지만 y축의 눈금이 다르면 처음 보는 사람들은 오해할 수 있다.

또한 중복되는 정보를 없애고, 부족한 설명을 채워주어야 한다.

 

간단하게 몇 가지 세부 옵션들을 조정해보자.


1. 범례 합치기

 

extract_legend 라는 함수를 새로 정의해준다. 이 함수는 참고자료 2번에서 그대로 가져온 함수이다.

기존에 범례(legend)가 있는 그래프에서 범례를 추출해주는 함수이다.

추출이 끝났다면 범례가 없는 그래프를 새로 만들어준다. (theme 함수의 legend.position = "none")

 

(주의)

이 방식으로 생성된 legend의 경우  grid.arrange()에서 기존의 g1, g2 처럼 하나의 공간을 차지한다.

그래서 추출된 범례 shared_legend를 g1, g2 와 같은 파라미터로 넣어야 하므로 ncol = 3 이 된다.

shared_legend를 통해 범례를 따로 생성하였으므로, 최종 grid.arrange 에서 사용되는 그래프는 범례가 없는 그래프이다.

범례는 그래프가 아니므로, 그래프와 같은 크기를 차지하지 않도록 너비 파라미터를 조정할 수 있다. (widths= c(3,3,1))

extract_legend <- function(my_ggp) {
  step1 <- ggplot_gtable(ggplot_build(my_ggp))
  step2 <- which(sapply(step1$grobs, function(x) x$name) == "guide-box")
  step3 <- step1$grobs[[step2]]
  return(step3)
}

shared_legend <- extract_legend(g1)

g1 <- ggplot(data=tmp1) + geom_point(aes(x=N, y=Accuracy, shape=Method, color=Method)) + ggtitle("Example 1") + theme(legend.position="none")
g2 <- ggplot(data=tmp2) + geom_point(aes(x=N, y=Accuracy, shape=Method, color=Method)) + ggtitle("Example 2") + theme(legend.position="none")
grid.arrange(g1, g2, shared_legend, ncol=3, widths=c(3,3,1))

2. 그래프 제목, x축과 y축 제목 설정

 

패키지 함수 혹은 옵션 설명
ggplot2 ggtitle() 그래프의 제목을 정하는 함수
xlab(), ylab() 축의 제목을 정하는 함수
gridExtra top =  grid.arrange 함수에서 그래프 위에 글을 삽입하는 옵션
bottom =  grid.arrange 함수에서그래프 아래에 글을 삽입하는 옵션

 

grid.arrange에서 요악된 정보를 한 번에 제시할 수 있다.

grid.arrange에서는  top =  bottom =  옵션을 통해, 그래프 전체에 대한 설명을 추가할 수 있는 옵션이 있어 편리하다.

 

g1 <- ggplot(data=tmp1) + geom_point(aes(x=N, y=Accuracy, shape=Method, color=Method)) + ggtitle("Example 1") + xlab("") + ylab("Accuracy") + theme(legend.position="none")
g2 <- ggplot(data=tmp2) + geom_point(aes(x=N, y=Accuracy, shape=Method, color=Method)) + ggtitle("Example 2") + xlab("") + ylab("") + theme(legend.position="none")
grid.arrange(g1, g2, shared_legend, ncol=3, widths=c(3,3,1), top = "Results of simulation", bottom = "sample szie (N)")

3. 눈금 설정

 

마지막으로 눈금 간격을 설정할 수 있다.

scale_y_continuous(limit=c(0.6, 1.0))는 ggplot에서 그려진 그래프 y축의 의 눈금을 0.6~1.0 사이로 나타내는 함수이다.

마찬가지로 x축에 대해서도 같은 기능을 제공하는 함수가 존재한다.

 


최종 그래프

 

g1 <- ggplot(data=tmp1) + geom_point(aes(x=N, y=Accuracy, shape=Method, color=Method)) + ggtitle("Example 1") + xlab("") + ylab("Accuracy") + theme(legend.position="none") + scale_y_continuous(limit=c(0.6, 1.0))
g2 <- ggplot(data=tmp2) + geom_point(aes(x=N, y=Accuracy, shape=Method, color=Method)) + ggtitle("Example 2") + xlab("") + ylab("") + theme(legend.position="none") + scale_y_continuous(limit=c(0.6, 1.0))
grid.arrange(g1, g2, shared_legend, ncol=3, widths=c(3,3,1), top = "Results of simulation", bottom = "sample szie (N)")

예시 그림 2
최종 코드를 작동 시켰을 때의 그래프입니다.

 

참고자료

1. girdExtra

https://cran.r-project.org/web/packages/egg/vignettes/Ecosystem.html

 

2. 범례 합치기 (링크에서 2번째꺼 사용)

https://statisticsglobe.com/add-common-legend-to-combined-ggplot2-plots-in-r/

반응형