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/ .