Edited at
R ShinyDay 23

世界の首都の位置座標データをleafletに関連させてみよう

この記事では、R言語のShinyとleafletライブラリを使った簡単なWebアプリケーションの実装例をご紹介したいと思います。私自身、Webアプリケーションに関する言語に詳しいわけではないのですが、Shinyを使えば、このようなWebアプリケーションを簡単に作成することができます。Shinyの基本操作についてはNp_Urさんのこちらの記事にて詳しく解説されています。

機能としては、国名を選択すると国旗画像が出力され、leaflet状にその国の首都の位置にマーカーが配置されるというものです。

ソースコードはこちらのgithubレポジトリにて公開しています。

それでは、具体的な実装方法について紹介していきます。


Step.1 データの入手とShinyアプリ用フォルダの準備

今回はleafletライブラリを使用します。このライブラリによる地図は、緯度経度の数値データを関連付けることができます。平成30年(2018年)6月1日現在の世界の首都(未承認含む)の所在地・位置座標データならびに平成27年(2015年)6月1日現在の世界の国旗画像データがアマノ技研から提供されているのでダウンロードをしてください。アプリのディレクトリツリーは次のようになります(120pixの国旗画像を使用しています)。



位置座標データをダウンロードフォルダに保存していると仮定して.RDataの準備に移ります。


preparation.R

library(readr)

user <- Sys.getenv("USERPROFILE")
datapath <- paste0(user, "\\Downloads\\asti-dath3006wc\\asti-dath3006wc\\h3006world_utf8.csv")
Data <- read_delim(datapath, "\t", escape_double = FALSE, trim_ws = TRUE)
setwd("CapitalCityMap/")
save(Data, file = "Data.RData")

4行目のコードに関しては、Rstudioのimport Datasetを利用するとGUI操作でデータを読み込むことができます。またshinyアプリケーションでは複数ファイルのバージョン管理が想定されるのでGitレポジトリを利用することをお勧めします。Rstudioでは、Git用の管理パネルがサポートされています。詳しくはuriさんのこちらの記事にて

ちなみに、Rで読み込んだデータセットはこのようになります。


Step.2 読み込んだデータをもとにプルダウンリストのUIを出力する

それでは、server.Rui.Rの設計に移ります。まず、読み込むライブラリは以下となります。

# server.R

library(shiny)
library(leaflet)
library(dplyr)
# ui.R
library(shiny)
library(leaflet)

そして、shinyServer()関数の前にload("Data.RData")を記述します。そして、ローカル環境でGoogle Chromeのようなブラウザでアプリを起動したい場合は、options(shiny.launch.browser = T)を記述します。読み込んだデータの列name_jpsの要素をプルダウンリストの選択肢として、表示させます(初期選択肢は"日本"、複数選択不可とする)。要素が重複している場合は、unique関数を利用することで重複した値を一つの値として返してくれます。そしてserver.Rのアウトプット要素pulldownUIとして、ui.Rに渡します。

### shinyServer()の内部(server.R) ###

# 国名のプルダウンリストのUI
output$pulldownUI <- renderUI({
countryList <- unique(as.character(Data$name_jps))

selectInput(inputId = "theCountries", label = "国名を選択してください",
choices = countryList, selected = "日本", multiple = F)
})

### sidebarPanel()の内部(ui.R) ###
uiOutput("pulldownUI")


Step.3 プルダウンリストの選択によってデータを整形

続いて、対話式のアプリケーション応答を実現するために変容データpassDatareactive関数を使用して定義します。

### shinyServer()の内部(ui.R) ###

# プルダウンリストの選択によって変化するデータ
passData <- reactive({
firstData <- Data %>% filter(name_jps == input$theCountries)
return(firstData)
})


Step.4 地図の出力と、地図上の首都の位置にマーカーを配置

次に、passData()から経度lon,緯度lat,首都の日本名capital_jpを取得し、leafletライブラリのaddMarkers()setView()関数の引数として渡しています。この際、整形データはpassDataではなくpassData()とコーディングすることに注意してください。

### shinyServer()の内部(server.R) ###

# リーフレットの出力
output$leaflet <- renderLeaflet({
# 選択された国の経度
lng <- passData()$lon
# 選択された国の緯度
lat <- passData()$lat

leaflet() %>% addTiles() %>%
addMarkers(lng = lng, lat = lat,
popup = as.character(passData()$capital_jp)) %>%
setView(lng = lng, lat = lat, zoom = 2)
})

### mainPanel()の内部 ###
leafletOutput("leaflet")


Step.5 サイドバーに国旗画像の出力

これだけでは何か味気ない感じがあり、さらに国旗画像ファイルも提供されているということであるので、最後にサイドバーに国旗画像を出力して完成形とします。renderImage()関数の引数としてdeleteFile=Fを指定しないと画像ファイルが出力するたびに消去されてしまうので、注意が必要です。

### shinyServer()の内部(server.R) ###

# 国旗の出力
output$Flag <- renderImage({
return(list(
src = paste0("./120pix/", passData()$country_code, "@3x.png"),
contentType = "image/png"
))
}, deleteFile = F)

### sidebarPanel(ui.R)の内部 ###
imageOutput("Flag")


完成するShinyファイルとおわりに


server.R

library(shiny)

library(leaflet)
library(dplyr)

# アプリをブラウザ上で立ち上げる
options(shiny.launch.browser = T)
# 緯度経度データの読み込み
load("Data.RData")

# shinyサーバー
shinyServer(function(input, output) {

# 国名のプルダウンリストのUI
output$pulldownUI <- renderUI({
countryList <- unique(as.character(Data$name_jps))

selectInput(inputId = "theCountries", label = "国名を選択してください",
choices = countryList, selected = "日本", multiple = F)
})

# プルダウンリストの選択によって変化するデータ
passData <- reactive({
firstData <- Data %>% filter(name_jps == input$theCountries)
return(firstData)
})

# リーフレットの出力
output$leaflet <- renderLeaflet({
# 選択された国の経度
lng <- passData()$lon
# 選択された国の緯度
lat <- passData()$lat

leaflet() %>% addTiles() %>%
addMarkers(lng = lng, lat = lat,
popup = as.character(passData()$capital_jp)) %>%
setView(lng = lng, lat = lat, zoom = 2)
})

# 国旗の出力
output$Flag <- renderImage({
return(list(
src = paste0("./120pix/", passData()$country_code, "@3x.png"),
contentType = "image/png"
))
}, deleteFile = F)

})



ui.R

library(shiny)

library(leaflet)

# shinyユーザーインターフェース
shinyUI(fluidPage(

# タイトル
titlePanel("世界の首都を確認しよう"),

# サイドバー
sidebarLayout(
sidebarPanel(
uiOutput("pulldownUI"),
imageOutput("Flag")
),

# メイン
mainPanel(
leafletOutput("leaflet")
)
)
))


今までのステップどおりに、進めていただければ大体のshinyライブラリによるWebアプリケーションの実装方法を掴んでいただけるのではないかと思います。比較的少ないコーディング量で対話式の分析環境を容易に実現することができるので、1年ほど前から利用しています。ネットからも割と多くの情報を得ることができます。また、サーバーで運用をしたくなった場合は、これまたNp_Urさんのこちらの記事をまずは参考にしてみてください。AWSでShinyアプリケーションを公開する方法を分かりやすく解説されています。ぜひ、自作のshinyアプリを生み出してみてください。

それでは、皆さんLet's Shiny!