-
Notifications
You must be signed in to change notification settings - Fork 0
/
dw_dashboard.qmd
355 lines (258 loc) · 17.2 KB
/
dw_dashboard.qmd
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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
---
output: html_document
editor_options:
chunk_output_type: console
---
# 대쉬보드
저자가 디지털 글쓰기를 하면서 가장 충격을 받은 사례 중 하나가 `flexdashboard` 패키지를 접하면서다. 고정관념으로 대쉬보드(Dashboard) 제작은 웹사이트를 제작하는 것이라
소프트웨어 개발자가 아니면 불가능하다고 생각했다. 즉, HTML, CSS, JavaScript 등을 활용하여 웹사이트를 제작하는데 그래프와 표, Value 박스 등 데이터 과학 구성요소가 필요하기 때문에 통계전공 데이터 과학자와 공동으로 작업을 해야 한다고 생각했다. 하지만, `flexdashboard`패키지로 R 마크다운을 활용해 쉽게 대시보드를 만들 수 있어 HTML, CSS, JavaScript에 대한 지식이 없어도 대시보드를 제작할 수 있다는 점이다.
지금은 잊혀져가고 있지만, 몇년전 코로나19가 전세계를 휩쓸고 있을 때 국내 및 해외 코로나 진행현황을 대쉬보드로 필자가 제작한 사례가 있다. 이 대쉬보드는 `flexdashboard` 패키지를 활용하여 제작되었으며, 데이터셋은 `coronavirus` 패키지를 통해 자동으로 최신 데이터가 갱신되기 때문에 대쉬보드 개발 노력을 상당부분 절감시킬 수 있으며 `flexdashboard`에서 제공하는 다양한 레이아웃 기능을 통해 대시보드 설계를 수월히 진행할 수 있으며 `DT`, `highcharter`, `leaflet`, `plotly` 등 인터랙티브 패키지로 미려한 시각화 산출물도 제작이 가능하다. 마지막으로 `gh-pages`를 통해 무료지만 안정성이 가장 뛰어난 웹사이트에 배포도
했다.
## 대쉬보드 제작과정
대쉬보드 제작을 순차적으로 진행할 수도 있지만 경우에 따라서는 병렬도 동시작업도 가능하다. 가장 일반적인 순차적 대쉬보드 제작과정은 다음과 같다. 먼저, 전세계와 한국의 코로나19 데이터를 수집하고 수집된 데이터를 분석 가능한 형태로 데이터를 전처리하여 대쉬보드 각 구성요소에 맞게 데이터셋을 맞춘다. 대시보드 UI/UX 디자인을 계획하면서 적절한 시각화 도구(`highcharter`, `leaflet`, `plotly`)에 대한 기술적인 검토도 함께 진행한다. [@kulkarni2019building]
데이터와 UI/UX 디자인과 기술검토가 마무리된 다음, 대시보드 구성요소를 본격적으로 highcharter, ValueBox, DT 테이블, Plotly 그래프 등으로 개발한다. 대쉬보드 외양을 정의하는 대시보드 브랜딩과 디자인 작업은 CSS/SCSS 스타일링 작업을 통해 진행된다. 대시보드 테스트 단계는 모든 구성요소가 올바르게 작동하는지 테스트하고, 완성된 대시보드를 깃헙 페이지 웹사이트에 배포한다. 이후 자동화 및 업데이트 운영 및 유지보수 단계에서 데이터가 실시간으로 갱신되도록 자동화시키고 신규 개발 코드와 UI/UX 코드도 CI/CD를 통해 자동화한다.
![대쉬보드 제작 흐름](images/corona-flexdashboard.png)
## 코로나19 대쉬보드 {#corona-virus-dashboard}
코로나19 대시보드 제작은 여러 단계로 구성된다. 먼저, [코로나19 데이터](https://github.com/RamiKrispin/coronavirus)를 사용할 수 있는데 데이터는 `coronavirus` 데이터 팩키지로 제작되어 데이터 수집 과정이 간소화되고 이미 잘 구성되어 있어 데이터 수집에 따른 공수를 크게 줄일 수 있다. 데이터를 수집한 후, [`flexdashboard`](https://rmarkdown.rstudio.com/flexdashboard/)를 주요 엔진으로 사용하여 대시보드를 제작한다. `flexdashboard`는 R 마크다운을 기반으로 하며, 다양한 시각화 도구와 통합이 쉽다.
### 데이터셋 {#corona-dashboard-dataset}
코로나 19 데이터셋은 존스 홉킨스 대학(Johns Hopkins University)과 세계보건기구(WHO)에서 제공되는 두가지 형태로 제공되고 있지만 존스 홉킨스 대학 데이터셋이 WHO 데이터셋 보다 더 많은 호응을 받아 `coronavirus` 데이터 패키지를 사용한다.
- [`coronavirus`: The coronavirus dataset ](https://github.com/RamiKrispin/coronavirus)
- [`COVID-19`: Novel Coronavirus (COVID-19) Cases, provided by JHU CSSE](https://github.com/CSSEGISandData/COVID-19)
- [`covid`: Novel Coronavirus(2019-nCoV) updates from WHO daily reports](https://github.com/javierluraschi/covid)
- [PDF WHO 보고서](https://www.who.int/emergencies/diseases/novel-coronavirus-2019/situation-reports)
```{{r install-dataset}}
library(tidyverse)
# install.packages("coronavirus")
# devtools::install_github("RamiKrispin/coronavirus")
library(coronavirus)
data("coronavirus")
coronavirus <- coronavirus %>%
janitor::clean_names() %>%
rename(country = country_region,
province = province_state)
```
### 대쉬보드 디자인 {#corona-dashboard-design}
데이터 과학 요소가 들어간 대쉬보드 제작을 위한 UI 설계안을 작성한다.
디자인 작업을 완료한 후, 와이어프레임(wireframe)을 중심으로 데이터 과학 요소가 포함된 대시보드 UI 설계작업을 진행한다.
![코로나19 대쉬보드 UI 설계](images/corona-dashboard-ui.png){#id .class width="77%"}
아이콘과 디자인 요소를 위해 [Font Awesome](https://fontawesome.com/icons?from=io), [Ionicons](https://ionicons.com/), [Bootstrap](https://getbootstrap.com/docs/4.4/components/alerts/), Bootstrap과 같은 라이브러리를 활용하여 다양한 아이콘과 UI 컴포넌트를 통해 대시보드 시각적 표현을 풍부하게 한다.
작성한 wireframe을 기반으로 flexdashboard 문법에 맞춰 대시보드 구성요소를 적절히 배치하고 R 마크다운 코드로 대시보드를 구현한다. 전체적으로 ValueBox를 대시보드 상단에 배치하고, 아래 두 그래프 영역에 필요한 그래프를 삽입하고 전세계와 한국을 탭(tabset)으로 구분하여 표현하여 대쉬보드 복잡성을 단순화한다.
![`flexdashboard` 배치도(layout)](images/flexdashboard-layout.png)
`````markdown
---
layout: page
title: "데이터 과학을 위한 저작도구: Computational Documents"
subtitle: "대쉬보드(Dashboard)"
author:
name: "[Tidyverse Korea](https://www.facebook.com/groups/tidyverse/)"
date: "`r Sys.Date()`"
output:
html_document:
toc: yes
toc_float: true
highlight: tango
code_folding: show
number_section: true
self_contained: true
editor_options:
chunk_output_type: console
---
전세계 {data-icon="fa-globe"}
===================================
Row {data-width=150}
--------------------------------------------
### 확진자수
```{r, eval=FALSE}
infected <- 100
valueBox(infected, icon = "fa-procedures")
```
### 사망자수
```{r, eval=FALSE}
death <- 20
valueBox(death, icon = "fa-skull")
```
### 회복자수
```{r, eval=FALSE}
recovered <- 30
valueBox(recovered,
icon = "fa-walking",
color = ifelse(recovered > 10, "warning", "primary"))
```
Column {data-height=350}
-------------------------------------
### Chart 1
### Chart 2
한국 {data-icon="fa-map"}
===================================
-- 이하 동일
`````
### 시각화 구성요소 {#dashboard-graph}
#### 막대그래프: 코로나19 {#corona-19}
[`coronavirus`](https://ramikrispin.github.io/coronavirus/) 데이터 팩키지에서 수집한 코로나 관련 데이터를 "경주하는 막대그래프" 형태로 시각화하기 위해, 먼저 `gapminder`의 경주 막대그래프 사례를 참조한다. 이 사례를 통해 어떻게 데이터를 준비하고 그래프를 구성할지 아이디어를 얻는다. [@reynolds2019racing]
![`gapminder`: 경주하는 막대그래프](images/racing-barchart.png)
데이터 준비가 완료되면, 정적 막대그래프를 먼저 생성하고 애니메이션 기능을 추가하여 동적인 경주 막대그래프를 완성한다. 애니메이션을 작성한 후에는 `.gif` 파일 형식으로 저장하고 대시보드에 불러와 그래프 영역에 채워넣는다.
```{{r}}
library(gganimate)
options(gganimate.nframes = 100)
## 데이터
corona_ranked_by_date <- coronavirus %>%
filter(type == 'confirmed') %>%
group_by(country, date) %>%
summarise(confirmed = sum(cases)) %>%
ungroup() %>%
group_by(country) %>%
arrange(date) %>%
mutate(cum_confirmed = cumsum(confirmed)) %>% # 국가별 누적환자수
ungroup() %>%
group_by(date) %>%
arrange(date, -cum_confirmed) %>% # 일별 상위 국가 선정
mutate(rank = 1:n()) %>%
filter(rank <=7) %>%
ungroup()
## 테마
library(extrafont)
loadfonts()
corona_theme <- theme_classic(base_family = "NanumGothic") +
theme(legend.position = "none") +
theme(axis.text.y = element_blank()) +
theme(axis.ticks.y = element_blank()) +
theme(axis.line.y = element_blank()) +
theme(legend.background = element_rect(fill = "gainsboro")) +
theme(plot.background = element_rect(fill = "gainsboro")) +
theme(panel.background = element_rect(fill = "gainsboro"))
corona_plot <- corona_ranked_by_date %>%
ggplot() +
aes(xmin = 0 ,
xmax = cum_confirmed) +
aes(ymin = rank - .45,
ymax = rank + .45,
y = rank) +
facet_wrap(~date) +
geom_rect(alpha = .7) +
aes(fill = country) +
scale_fill_viridis_d(option = "magma",
direction = -1) +
scale_x_continuous(
limits = c(-15000, 80000)) +
geom_text(col = "gray13",
hjust = "right",
aes(label = country),
x = -50) +
labs(fill = NULL) +
labs(x = '감염자수') +
labs(y = "") +
scale_y_reverse() +
corona_theme
corona_gif <- corona_plot +
facet_null() +
aes(group = country) +
geom_text(x = 55000 , y = -7,
family = "NanumGothic",
aes(label = as.character(date) ),
size = 10, col = "grey18") +
gganimate::transition_time(date)
corona_gif # anim_save("images/corona.gif", corona_gif, duration=0.1)
knitr::include_graphics('images/corona.gif')
```
### 공간정보 시각화 {#corona-19-leaflet}
`leaflet` 라이브러리를 활용하여 공간정보 시각화 작업을 수행한다. 먼저, `coronavirus` 데이터 팩키지에서 수집한 코로나 관련 데이터 중 위경도 정보를 추출하여 `leaflet`에 입력하여 지도 위에 표시한다. `leaflet`의 다양한 기능을 활용하여 `coronavirus` 데이터에 담긴 공간정보를 인터랙티브 시각화를 구현한 후 `leaflet` 지도를 대시보드 일부로 통합한다.
```{{r}}
library(leaflet)
library(janitor)
coronavirus %>%
mutate(geo_name = glue::glue("{country} {province}")) %>%
select(-country, -province) %>%
group_by(geo_name, lat, long, type) %>%
summarise(cases = sum(cases, na.rm = TRUE)) %>%
spread(type, cases, fill=0) %>%
leaflet() %>%
addTiles() %>%
addProviderTiles(providers$OpenStreetMap) %>%
addMarkers(lng=~long, lat=~lat, clusterOptions = markerClusterOptions(),
popup = ~ as.character(paste0("<strong> 코로나19 현황: ", geo_name, "</strong><br>",
"-----------------------------------------------------------<br>",
"· 감염: ", scales::comma(confirmed), "<br>",
"· 사망: ", scales::comma(death), "<br>",
"· 회복: ", scales::comma(recovered), "<br>")))
```
## 한국 대쉬보드 {#corona-korea}
### 데이터셋 {#corona-korea-dataset}
한국 코로나19관련 데이터를 MBC 장슬기 기자의 도움으로 [이성규, "미디어고토사"](https://www.mediagotosa.com/korona19-hwagsan-ilbyeol-hyeonhwang-jeongri/)에서 찾을 수 있었다. 데이터를 `google sheet`에 정리해 두어서 [`googlesheets4`](https://github.com/tidyverse/googlesheets4)의 도움으로 수월하게 입수할 수 있다.
문제는 일자별로 데이터 정리가 체계적으로 되어 있지 않고, 코로나 관련 대쉬보드를 구성할 때 한계가 있다.
```{{r}}
## 데이터셋 --------------------
library(googlesheets4)
library(tidyverse)
library(lubridate)
cv_kor <- read_sheet('https://docs.google.com/spreadsheets/d/1fODH5PZJw9jxwV2GRe85BRQgc3mxdyyIpQ0I6MDJKXc/edit#gid=0')
cv_kor_df <- cv_kor %>%
select(날짜, 확진자=`누적 확진자수`, 검사자 = `누적 검사자수`, 사망자, 회복자=`누적 격리해제`) %>%
arrange(날짜) %>%
mutate(일자 = as.Date(날짜)) %>%
group_by(일자) %>%
summarise(검사자 = last(검사자),
확진자 = last(확진자),
사망자 = last(사망자),
회복자 = last(회복자)
) %>%
padr::pad(.)
```
### 대쉬보드 구성 {#corona-korea-dashboard}
전세계 코로나 사례와 다르게 검사자수가 포함되어 있어 이를 `valueBox`에 포함시킨다. 지역정보가 없기 때문에 이를 `DT` 표로 대신하는데 몇가지 인터랙티브 기능을 추가해서 기본 정렬에 추가하여 칼럼별 검색 및 다양한 파일 형태로 다운로드 가능하도록 한다. 일자별로 구성된 시계열 데이터 특성을 적극 활용하여 선그래프를 인터랙티브하게 구성한다.
![한국 대쉬보드 구성](images/corona-korea.png)
### 시각화 구성요소 {#corona-korea-dashboard-component}
시각화 구성요소로 `valueBox`, `DT`, `plotly`를 선택했기 때문에 이를 순차적으로 모듈화시켜 개발한 후에 대쉬보드에 적용시킨다.
### `valueBox()` {#corona-korea-valueBox}
검사자, 확진자, 사망자, 회복자를 `valueBox`로 만들어 현황을 파악하기 편하게 구성한다. `webshot`을 사용하면 굳이 화면을 캡쳐하지 않아도 R마크다운 코드에서 직접 가능하게 된다.
```{r}
#| echo: false
#| eval: false
library(webshot)
webshot("https://statkclee.github.io/comp_document/cd-corona.html",
"fig/korea-valueBox.png", selector = c("#row"))
```
![`valueBox`](images/korea-valueBox.png)
### 표와 그래프 {#corona-korea-table}
인터랙티브 표를 사용하게 되면 일단 기본기능으로 들어가 있는 정렬외에 `searchHighlight`를 사용해서 검색 기능을 넣고, `dom = 'Bfrtip'`을 통해 다양한 형태로 데이터를 내려받을 수 있도록 한다.
```{{r}}
cv_kor_df <-
read_rds("data/cv_kor_df.rds")
cv_kor_df %>%
arrange(desc(일자)) %>%
DT::datatable(filter = 'top',
options = list( searchHighlight = TRUE, pageLength = 15,
dom = 'Bfrtip',
buttons = c('copy', 'csv', 'excel', 'pdf', 'print')),
extensions = 'Buttons') %>%
DT::formatRound(c("검사자", "확진자", "사망자", "회복자"), digits=0)
```
`plotly` 라이브러리를 사용하면 정적 그래프를 쉽게 인터랙티브 그래프로 변환할 수 있다. 정적 그래프의 데이터와 설정을 `plotly` 형식으로 변환시키면 기본적인 인터랙티브 기능이 적용된다. 선 그래프나 막대 그래프에서는 데이터 포인트에 마우스를 가져가면 해당 값이 표시되고, 그래프를 드래그하여 끌어 확대하거나 축소할 수도 있다.
```{{r kor-df-viz}}
korea_theme <- theme_classic(base_family = "NanumGothic") +
theme(legend.position = "none") +
theme(legend.background = element_rect(fill = "gainsboro")) +
theme(plot.background = element_rect(fill = "gainsboro")) +
theme(panel.background = element_rect(fill = "gainsboro"))
cv_kor_plot <- cv_kor_df %>%
gather(유형, 사람수, -일자) %>%
mutate(유형 = factor(유형, levels=c("검사자", "확진자", "회복자", "사망자"))) %>%
ggplot(aes(x=일자, y=사람수, color=유형)) +
geom_line() +
geom_point() +
facet_wrap(~유형, scale="fixed") +
scale_y_continuous(labels = scales::comma_format(scale = 1)) +
korea_theme +
labs(x="", y="") +
scale_color_viridis_d(option = "magma",
direction = -1)
plotly::ggplotly(cv_kor_plot)
```
## 배포 대쉬보드
대시보드 제작이 완료되면 인터넷에 공개하기 위해 `gh-pages`를 사용해 웹사이트에 배포한다. `gh-pages`는 `GitHub`에서 제공하는 무료 웹 호스팅 서비스로, R 마크다운 파일을 HTML 형식으로 변환해 웹사이트를 만들 수 있다. `gh-pages`를 사용하면 웹사이트를 만들기 위한 별도의 서버를 구축할 필요가 없다.
배포 과정은 먼저 GitHub 저장소를 생성하고 대시보드 모든 파일을 업로드한 다음 GitHub 설정에서 `gh-pages`를 활성화하고 대시보드가 포함된 브랜치를 선택한다. 설정이 완료되면 GitHub은 자동으로 웹사이트를 생성하고 해당 URL을 제공한다.
코로나19 대시보드는 인터넷에 자유롭게 접근 가능하며, 누구나 코로나19 현황을 쉽게 파악하고 이해하도록 도움을 준다. 대쉬보드는 [코로나19 대쉬보드](https://statkclee.github.io/comp_document/cd-corona.html) 웹사이트에서 확인할 수 있다.
:::{layout="[49.5, -1, 49.5]"}
![코로나19 전세계 현황](images/corona_dashboard_world.jpg)
![코로나19 한국 현황](images/corona_dashboard_korea.jpg)
`flexdashboard` 코로나19 대쉬보드
:::