data visualization
데이터 시각화는 데이터 분석에서 중요한 역할을 한다. 다행히 R은 이 방면에서는 ggplot2
를 필두로 다른 프로그래밍 언어들 이상의 뛰어난 여러 기능들을 사용할 수 있다는 장점이 있다.
한편 데이터 시각화는 제작 이후 색상이나 레이아웃 등의 추가적인 커스텀 수정 을 필요로 하기도 한다. 이를 위해 R 내에서 할 수 있다면 더할 나위 없이 좋지만 떄로는 단순한 작업을 위해 여러줄 코드를 사용하는 것보다 간단히 ppt 같은 외부 프로그램을 활용하는 것이 더 간편한 경우도 많다.
이전의 다른 아티클 에서 officer
패키지를 활용해 MS powerpoint로 벡터 이미지를 만들고 편집하는 방법을 소개하였는데, 이번 글에서는 여러 장의 이미지를 대상으로 R에서 할 수 있는 고급 방법들과 이에 쓰이는 R 패키지를 소개한다.
result
이번 글에서 소개하는 방법들을 적용한 ppt 결과물을 먼저 소개한다.
우선 위 이미지는
R에서 ggplot2
를 사용하여 만든 시각화 를
cowplot
을 이용하여 박스 로 감싸고
patchwork
와 를 사용해 시각화 와 설명을 위한 텍스트 를 레이아웃 에 따라 배치한 뒤
officer
를 활용하여 와이드스크린(혹은 16:9) 해상도 크기의 MS powerpoint 로 만들어 낸 결과물이다.
이 결과물들은 벡터 그래픽스를 활용한 만큼, 다음 이미지처럼 ppt에서 편리하게 커스텀 수정이 가능하다.
patchwork
예시에서 사용할 이미지는 ggplot2
의 mtcars
데이터셋을 사용하는 patchwork
의 예시 코드를 사용한다. ggplot2
과 각 차트에 대해서는 별도로 설명하지 않는다.
Mazda RX4
21.0
6
160.0
110
3.90
2.620
16.46
0
1
4
4
Mazda RX4 Wag
21.0
6
160.0
110
3.90
2.875
17.02
0
1
4
4
Datsun 710
22.8
4
108.0
93
3.85
2.320
18.61
1
1
4
1
Hornet 4 Drive
21.4
6
258.0
110
3.08
3.215
19.44
1
0
3
1
Hornet Sportabout
18.7
8
360.0
175
3.15
3.440
17.02
0
0
3
2
Valiant
18.1
6
225.0
105
2.76
3.460
20.22
1
0
3
1
Duster 360
14.3
8
360.0
245
3.21
3.570
15.84
0
0
3
4
Merc 240D
24.4
4
146.7
62
3.69
3.190
20.00
1
0
4
2
Merc 230
22.8
4
140.8
95
3.92
3.150
22.90
1
0
4
2
Merc 280
19.2
6
167.6
123
3.92
3.440
18.30
1
0
4
4
Merc 280C
17.8
6
167.6
123
3.92
3.440
18.90
1
0
4
4
Merc 450SE
16.4
8
275.8
180
3.07
4.070
17.40
0
0
3
3
Merc 450SL
17.3
8
275.8
180
3.07
3.730
17.60
0
0
3
3
Merc 450SLC
15.2
8
275.8
180
3.07
3.780
18.00
0
0
3
3
Cadillac Fleetwood
10.4
8
472.0
205
2.93
5.250
17.98
0
0
3
4
Lincoln Continental
10.4
8
460.0
215
3.00
5.424
17.82
0
0
3
4
Chrysler Imperial
14.7
8
440.0
230
3.23
5.345
17.42
0
0
3
4
Fiat 128
32.4
4
78.7
66
4.08
2.200
19.47
1
1
4
1
Honda Civic
30.4
4
75.7
52
4.93
1.615
18.52
1
1
4
2
Toyota Corolla
33.9
4
71.1
65
4.22
1.835
19.90
1
1
4
1
Toyota Corona
21.5
4
120.1
97
3.70
2.465
20.01
1
0
3
1
Dodge Challenger
15.5
8
318.0
150
2.76
3.520
16.87
0
0
3
2
AMC Javelin
15.2
8
304.0
150
3.15
3.435
17.30
0
0
3
2
Camaro Z28
13.3
8
350.0
245
3.73
3.840
15.41
0
0
3
4
Pontiac Firebird
19.2
8
400.0
175
3.08
3.845
17.05
0
0
3
2
Fiat X1-9
27.3
4
79.0
66
4.08
1.935
18.90
1
1
4
1
Porsche 914-2
26.0
4
120.3
91
4.43
2.140
16.70
0
1
5
2
Lotus Europa
30.4
4
95.1
113
3.77
1.513
16.90
1
1
5
2
Ford Pantera L
15.8
8
351.0
264
4.22
3.170
14.50
0
1
5
4
Ferrari Dino
19.7
6
145.0
175
3.62
2.770
15.50
0
1
5
6
Maserati Bora
15.0
8
301.0
335
3.54
3.570
14.60
0
1
5
8
Volvo 142E
21.4
4
121.0
109
4.11
2.780
18.60
1
1
4
2
mtcars
patchwork
는 여러 개의 ggplot 결과물들을 하나(한장)의 그래픽에 간단하게 배치할 수 있게 하는 R 패키지이다. 유사한 목적으로 patchwork
외에 gridExtra
나 cowplot
등의 다른 패키지도 사용할 수 있다.
patchwork
의 사용법은 크게 +
, |
, ( )
, /
로 구성된다.
| (vertical bar)
먼저 |
는 여러 이미지를 하나의 행 에 배치하는 역할을 한다.
+
두번째로 +
는 여러 이미지를 배치하는데 이때 행과 열은 grid 형태로, 행 순서 로 채우는 방식을 사용한다.
이때 이미지 배치를 특별히 지정을 하기 위해서는 plot_layout
이라는 함수를 사용한다.
p1 + p2 + p3 + p4 + p5 +
plot_layout ( ncol = 3 , byrow = FALSE )
/
이어서 /
를 사용하면 이미지를 열 로 이어서 배치할 수 있다.
( )
마지막으로 ( )
를 사용하면 이미지를 하나의 그룹 으로 묶어서 배치할 수 있다.
물론 이 외에도 patchwork
는 다양한 기능을 제공하는데, 자세한 내용은 공식 문서 를 참고하자.
이를 활용해서 이제 앞에서 만들었던 예시 이미지 6개를 한장의 ppt에 배치해보자.
combined_plot <- ( p1 | p2 | p3 ) /
( p4 | p5 | p6 ) +
theme ( plot.margin = margin ( 1 , 10 , 1 , 10 ) )
combined_plot
cowplot
이어서 cowplot
을 사용해 이미지 사이에 캡션 과 박스 를 추가하는 방법을 다루겠다.
우선 첫 이미지 3장을 표현하는 가상의 캡션을 list
형태로 생성한다. 참고로 <br>
은 줄넘김을 의미한다.
내용은 lorem ipsum 을 활용했다.
text <- list (
p1 = "Lorem ipsum dolor sit amet <br> consectetur adipiscing elit." ,
p2 = "Integer lectus risus, <br> tincidunt eget felis non." ,
p3 = "Cras varius sapien et est consectetur porttitor."
)
이를 이전 combined_plot
에 추가한다.
combined_plot <- ( p1 | p2 | p3 ) /
( text $ p1 | text $ p2 | text $ p3 ) /
( p4 | p5 | p6 ) +
theme ( plot.margin = margin ( 1 , 10 , 1 , 10 ) )
# combined_plot
# ERROR !!
그러나 이 상태로는 text 오브젝트가 ggplot 결과가 아닌 단순 텍스트만을 포함하기 때문에 에러가 발생한다. 이를 해결하기 위해 cowplot
의 ggdraw
함수를 사용한다.
ggdraw
우선 cowplot
은 ggplot2의 결과물에 annotation, theme를 추가하는 기능등을 제공하는 R 패키지로, ggdraw
는 ggplot2의 결과물에 추가적인 그래픽을 그릴 수 있게 제일 상위 레벨에 레이어를 추가한다고 생각하면 편하다.
scatter <- ggplot ( mpg , aes ( displ , cty ) ) +
geom_point ( ) +
theme_minimal_grid ( )
draft <- ggdraw ( scatter ) +
draw_label ( "Draft" , colour = "#80404080" , size = 120 , angle = 45 )
scatter | draft
이 ggdraw
를 사용해 이전의 text 내용 중 첫번째 라벨(p1)을 label로 갖는 ggplot 오브젝트 를 생성하고 이를 combined_plot
에 추가한다.
combined_plot <- ( p1 | p2 | p3 ) /
(
ggdraw ( ) +
labs ( subtitle = text $ p1 ) +
theme_void ( ) +
theme (
text = element_text ( size = 8 ) ,
plot.subtitle = ggtext :: element_textbox_simple (
hjust = 0 ,
halign = 0 ,
margin = margin ( 3 , 0 , 0 , 0 )
) ,
plot.margin = margin ( 0 , 0 , 0 , 0 )
)
) /
( p4 | p5 | p6 ) +
theme ( plot.margin = margin ( 1 , 10 , 1 , 10 ) )
combined_plot
이어서 남은 라벨을 추가하기 전, 라벨 커스텀에 반복적으로 쓰이는 기능들을 별도의 함수로 만들어 사용하자. 추가로 caption과 그래프를 동일한 1:1:1의 높이로 할당하지 않고 caption 부분을 줄이기 위해 plot_layout
의 height
로 높이를 조절한다.
다음은 각 시각화를 박스(테두리)로 감싸는 방법을 다룬다. 이를 위해 각 시각화에 ggdraw
를 사용하여 레이어를 만들고, 그 레이어에 draw_line
함수를 사용해 (0,0) 부터 (1,1)을 지나는 직선을 추가하는 방법을 사용한다.
추가로 각 시각화에 text 속성을 조절하기 위해 theme
함수를 사용한다.
text_theme <- theme (
text = element_text ( size = 6 ) ,
axis.text = element_text ( size = 6 ) ,
axis.title = element_text ( size = 6 ) ,
axis.title.x = element_text ( size = 6 ) ,
axis.title.y = element_text ( size = 6 ) ,
plot.title = element_text ( size = 6 ) ,
legend.text = element_text ( size = 6 ) ,
legend.title = element_text ( size = 6 )
)
(
p1 |
ggdraw ( p1 + text_theme ) +
draw_line (
x = c ( 0 , 1 , 1 , 0 , 0 ) ,
y = c ( 0 , 0 , 1 , 1 , 0 ) ,
color = "black" ,
size = 0.5
)
)
이전과 마찬가지로 (반복되는) 박스를 만드는 기능들을 함수로 만들어 사용하자.
officer
이제 officer
패키지를 사용해 위에서 만든 그래프를 ppt에 추가해보자.
기본적인 officer
에 대한 소개는 이전 아티클 을 참고하면 좋다.
officer
에서는 read_pptx
함수로 ppt 오브젝트를 생성하는데 이때 읽을 파일을 입력하지 않으면 너비와 높이가 4:3 비율 인 새로운 오브젝트를 생성하여 사용한다.
만약 이를 그대로 사용한다면 다음 그림과 같이 애써만든 레이아웃이 깨지는 상황이 발생할 수 있기 때문에, ppt에서 임의의 사이즈를 갖는 템플릿을 만들고 이를 파일로 읽어 사용한다.
ppt를 생성한 다음, 페이지 설정
에서 16:9 혹은 와이드 스크린 으로 변경하는 방법도 있지만, 이 방법 또한 마찬가지로 그래프 요소들을 다시 배치해야 한다는 점은 동일하다.
read_pptx ("~/Documents/template.pptx" ) |>
remove_slide (1 ) |>
add_slide () |>
ph_with (
value = "Example Title (baseline ~ X)" ,
location = ph_location_type (type = "title" )
) |>
ph_with (
rvg:: dml (ggobj = combined_plot),
location = ph_location (left = 0 , top = 1.5 , height = 6 , width = 13.333 )
) |>
print (target = "output2.pptx" )
위 코드에서 2번째 줄 remove_slide
함수를 사용하지 않으면, 기존 템플릿의 슬라이드 이후 에 ggplot 결과를 담는 슬라이드를 만들기 때문에 아래와 같이 불필요한 첫페이지를 가지고 시작하게 된다.
한편 remove_slide
와 add_slide
를 둘 다 제거하고 ph_with
으로 이미지만 더하게 되면 아래와 같이 템플릿의 제목과 새로 추가한 제목이 겹쳐서 보여지게 된다.
read_pptx ( "~/Documents/template.pptx" ) |>
ph_with (
value = "Example Title (baseline ~ X)" ,
location = ph_location_type ( type = "title" )
) |>
ph_with (
rvg :: dml ( ggobj = combined_plot ) ,
location = ph_location ( left = 0 , top = 1.5 , height = 6 , width = 13.333 )
) |>
print ( target = "output2.pptx" )
그러므로 템플릿을 사용하는 경우에는 remove_slide
와 add_slide
를 활용하는 것을 권장한다.
summary
이번 아티클에서는 patchwork
와 cowplot
을 사용해 여러 그래프를 하나로 합치고 약간의 커스텀을 거쳐, officer
를 사용해 ppt에 추가하는 방법을 알아보았다. 이처럼 R의 기능과 ppt를 연결하는 방법은 다양하게 활용할 수 있으며, 이를 통해 보다 효율적인 작업을 할 수 있을 것이다.
최종 코드는 다음과 같다.
Code library ( ggplot2 )
library ( patchwork )
library ( cowplot )
library ( officer )
p1 <- ggplot ( mtcars ) + geom_point ( aes ( mpg , disp ) )
p2 <- ggplot ( mtcars ) + geom_boxplot ( aes ( gear , disp , group = gear ) )
p3 <- ggplot ( mtcars ) + geom_bar ( aes ( gear ) ) + facet_wrap ( ~ cyl )
p4 <- ggplot ( mtcars ) + geom_bar ( aes ( carb ) )
p5 <- ggplot ( mtcars ) + geom_violin ( aes ( cyl , mpg , group = cyl ) )
p6 <- ggplot ( mtcars ) + geom_point ( aes ( mpg , disp ) ) + facet_wrap ( ~ cyl )
text <- list (
p1 = "Lorem ipsum dolor sit amet <br> consectetur adipiscing elit." ,
p2 = "Integer lectus risus, <br> tincidunt eget felis non." ,
p3 = "Cras varius sapien et est consectetur porttitor."
)
cap <- function ( text ) {
ggdraw ( ) +
labs ( subtitle = text ) +
theme_void ( ) +
theme (
text = element_text ( size = 8 ) ,
plot.margin = margin ( 0 , 0 , 0 , 0 )
)
}
text_theme <- theme (
text = element_text ( size = 6 ) ,
axis.text = element_text ( size = 6 ) ,
axis.title = element_text ( size = 6 ) ,
axis.title.x = element_text ( size = 6 ) ,
axis.title.y = element_text ( size = 6 ) ,
plot.title = element_text ( size = 6 ) ,
legend.text = element_text ( size = 6 ) ,
legend.title = element_text ( size = 6 )
)
with.box <- function ( p ) {
ggdraw ( p + text_theme ) +
cowplot :: draw_line (
x = c ( 0 , 1 , 1 , 0 , 0 ) ,
y = c ( 0 , 0 , 1 , 1 , 0 ) ,
color = "black" ,
size = 0.5
)
}
combined_plot <- ( with.box ( p1 ) | with.box ( p2 ) | with.box ( p3 ) ) /
( cap ( text $ p1 + text_theme ) | cap ( text $ p2 + text_theme ) | cap ( text $ p3 + text_theme ) ) /
( with.box ( p4 ) | with.box ( p5 ) | with.box ( p6 ) ) +
plot_layout ( heights = c ( 5 , 0.1 , 5 ) ) +
theme ( plot.margin = margin ( 1 , 10 , 1 , 10 ) )
combined_plot
read_pptx ( "~/Documents/template.pptx" ) |>
ph_with (
value = "Example Title (baseline ~ X)" ,
location = ph_location_type ( type = "title" )
) |>
ph_with (
rvg :: dml ( ggobj = combined_plot ) ,
location = ph_location ( left = 0 , top = 1.5 , height = 6 , width = 13.333 )
) |>
print ( target = "output2.pptx" )
Citation BibTeX citation:
@online{kim2024,
author = {Kim, Jinhwan},
title = {Patchwork를 {활용한} {고급} {시각화}},
date = {2024-05-17},
url = {https://blog.zarathu.com/posts/2024-05-17-patchwork/},
langid = {en}
}
For attribution, please cite this work as:
Kim, Jinhwan. 2024.
“Patchwork를 활용한 고급 시각화.” May
17, 2024.
https://blog.zarathu.com/posts/2024-05-17-patchwork/ .