R 語言動態視覺化的 Hello World
利用 RSelenium、plotly 與 shiny 模仿 Hans Rosling 的視覺化大作
利用程式語言輸出 “Hello world” 是常見的程式學習第一課,時至今日涵義已經由單純印出字串衍生為第一個作品或者入門課題。讓我們以 RSelenium 擷取世界銀行資料然後使用 plotly 與 shiny 套件建立一個 Shiny App 模仿 Hans Rosling(1948–2017)最著名的 TED Talk: The Best Stats You’ve Ever Seen 視覺化大作,作為 R 語言動態視覺化的 Hello World 作品!
成為 DataInPoint 的贊助者
這篇文章的程式可以在這個 GitHub Repository 找到。
資料需求
要開始製作氣泡圖的動態視覺化之前來盤點資料需求:國家的人均國內生產總值 GDP Per Capita(X 軸變數)、平均壽命(Y 軸變數)、人口數(氣泡大小)、國家所屬區域(氣泡顏色)以及最重要的,讓這個氣泡圖可以動起來的年份(時間軸。)為了資料擷取的便利性,我們以世界銀行能夠查詢到的資料作為單一來源。
我們搜尋三個指標的關鍵字:gdp per capita、life expectancy 與 population,每一次搜尋網站都會導向資料頁面,接著就點選下載 CSV 連結:
這樣的動作其實只需要手動執行三次,但是為求貫徹自動化理念(需要重複進行兩次的動作就以程式解決),還是決定使用 RSelenium 來協助。
Selenium
在先前的文章探索主流深度學習框架在 GitHub 的活躍程度我們曾經介紹過 Selenium 是為了達到瀏覽器自動化而誕生的工具,讓程式可以直接驅動瀏覽器模擬使用者與網站的互動操作,過程中會真實執行瀏覽器像是 Chrome、Edge、Firefox 與 Safari 做出填寫表單與點選按鈕進而獲取網站即時的內容;在 Python 與 R 都能夠驅動 Selenium。
在 RSelenium 的文件中有建議兩種 Selenium 安裝方式,一是透過 docker 安裝,另一是直接下載 Selenium 的 .jar 檔並以 java 去啟動,由於電腦已經有安裝 java,故採用後者,預設在 localhost:4444 運行 Selenium server 。
# bash
cd ~/Downloads
java -jar selenium-server-standalone-3.7.1.jar
接著打開 RStudio,安裝並載入 RSelenium 套件後連接正在運行的 Selenium server,用來操作 Chrome 瀏覽器:
library(RSelenium)remDr <- remoteDriver(remoteServerAddr = "localhost"
, port = 4444L
, browserName = "chrome"
)
remDr$open()
接著使用 Chrome 外掛 SelectorGadget 或 XPath Helper 定位搜尋欄位與 csv 下載連結:
- 搜尋欄位:#selector
- csv 下載連結://div[@class=’btn-item download’]/p/a[1]
開始撰寫自動將 gdp per capita、life expectancy 與 population 資料下載的程式:
資料處理
接著利用 unzip()
函數將下載好的三個壓縮檔解壓縮,先以文字編輯器觀察 csv 檔的內容,再決定該讀入哪些部分。
setwd("~/Downloads")
zipfiles <- c("API_NY.GDP.PCAP.CD_DS2_en_csv_v2.zip", "API_SP.DYN.LE00.IN_DS2_en_csv_v2.zip", "API_SP.POP.TOTL_DS2_en_csv_v2.zip")
for (zipfile in zipfiles) {
unzip(zipfile, exdir = "~/Downloads/world_bank_csv")
}
以文字編輯器檢視三個 csv 檔案,就能夠知道世界銀行提供的指標資料要從第五列開始讀取,並且是以寬表格(Wide Format)儲存不同年度的指標。
繪製氣泡的顏色需要知道國家所屬區域,因此任選一個 metadata 的 csv 檔案:
接著進行資料載入、轉置與合併…等的繪圖前置作業,首先將這四個 csv 檔載入稍微整理後存到一個 list 中:
setwd("~/Downloads/world_bank_csv/")
csv_list <- list()
csv_files <- c("API_NY.GDP.PCAP.CD_DS2_en_csv_v2.csv", "API_SP.DYN.LE00.IN_DS2_en_csv_v2.csv", "API_SP.POP.TOTL_DS2_en_csv_v2.csv")
year_cols <- paste0("X", 1960:2015)
for (i in 1:length(csv_files)) {
df <- read.csv(csv_files[i], skip = 4L, stringsAsFactors = FALSE)
csv_list[[i]] <- df[, c("Country.Name", "Country.Code", year_cols)]
}
region_csv <- read.csv("Metadata_Country_API_SP.POP.TOTL_DS2_en_csv_v2.csv", stringsAsFactors = FALSE)
csv_list[[4]] <- region_csv[, c("Country.Code", "Region", "TableName")]
接著把指標的三個 data.frame 轉置為長表格的形式:
library(tidyr)
library(magrittr)indicators <- c("gdpPercap", "lifeExp", "pop")
for (i in 1:3) {
csv_list[[i]] <- gather(csv_list[[i]], key = "year", value = "indicator", X1960:X2015)
names(csv_list[[i]])[4] <- indicators[i]
csv_list[[i]]$year <- csv_list[[i]]$year %>%
gsub(pattern = "X", , replacement = "") %>%
as.integer
}
最後再將 list 中的四個 data.frame 整併為一個 tidy 資料框:
library(dplyr)merge_on_cols <- names(csv_list[[1]])[1:3]
tidy_df <- csv_list[[1]] %>%
merge(csv_list[[2]], by = merge_on_cols) %>%
merge(csv_list[[3]], by = merge_on_cols) %>%
merge(csv_list[[4]], by.x = c("Country.Name", "Country.Code"), by.y = c("TableName", "Country.Code")) %>%
arrange(Country.Name, year)
將資料整理的程式整理成一個函數 get_tidy_df()
:
只需指定存放三個 zip 檔案的路徑,就能夠呼叫 get_tidy_df()
函數獲取整併後的資料框。
# Call function
zipfile_path <- "~/Downloads"
tidy_df <- get_tidy_df(zipfile_path)
View(tidy_df)
dim(tidy_df)
Plotly
Plotly 能夠幫助 R 語言使用者不需要額外去學習 JavaScript 就能夠建立出互動性、具備 D3.js 及 WebGL 特性的動態繪圖;只要呼叫 plot_ly()
函數、調整參數就能夠製作動態的視覺化作品;氣泡圖與 tidy_df 資料對應關係為:
- X 軸變數:gdpPercap(*)
- Y 軸變數:lifeExp
- 氣泡大小:pop(*)
- 氣泡顏色:Region
- 時間軸:year
值得注意的是我們會在 X 軸應用 log scale 避免多數的氣泡都擠在左邊,並利用圓面積公式調整氣泡大小。
library(plotly)bubble_radius <- sqrt(tidy_df$pop / pi)
plot_ly(tidy_df, x = ~gdpPercap, y = ~lifeExp, size = ~pop, type = "scatter", mode = "markers", frame = ~year, color = ~Region, text = ~Country.Name, hoverinfo = "text", sizes = c(min(bubble_radius, na.rm = TRUE), max(bubble_radius, na.rm = TRUE))) %>%
layout(xaxis = list(type = "log"))
截至目前,我們的動態視覺化 Hello World 作品已經接近完成!
Shiny
Shiny 是能夠幫助 R 語言使用者建立互動網頁應用程式的套件,並且具備一鍵部署到雲端(shinyapps.io 與 RStudio Connect)的便利功能。我們打算在原本的氣泡圖旁邊增加一個 checkbox group 元件,讓使用者能夠選擇要呈現哪些區域的國家。首先要建立一個 Shiny 應用程式並將之命名為 gapminder_replica:
由於我們會將這個應用程式部署到 shinyapps.io,因此除了 RStudio 幫我們建立的 ui.R 與 server.R 以外,還需要自己建立其他的檔案與資料夾:
- ui.R
- server.R
- global.R
- plotlyGraphWidget.R
- www/plotlyGraphWidget.js
- data/tidy_df.csv
ui.R 是 Shiny 應用程式的使用者前端介面,只要呼叫 plotlyOutput()
就可以顯示 Plotly 元件:
server.R 負責 Shiny 應用程式的後端資料傳輸,依照前端 checkbox group 的選擇來篩選資料:
global.R 可以建立讓整個 Shiny 應用程式,不論前端或後端都能夠使用的物件或函數:
plotlyGraphWidget.R 與 plotlyGraphWidget.js 則負責讓 plotly 圖形在部署到 雲端時能夠正常作用:
最後是將本機的 Shiny 應用程式部署到雲端,設定好 shinyapps.io 的帳號認證後,只需要按 Publish Application 就能夠完成部署。
部署好的 Shiny 應用程式可以點選這個連結互動。
世界銀行的亞特蘭提斯
如果您喜歡這篇文章,請多按下方的「拍手」圖像幾次、分享到社群網站、成為我們的贊助者以及訂閱 DataInPoint 的新文章!