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

この記事では、R言語のShinyとleafletライブラリを使った簡単なWebアプリケーションの実装例をご紹介したいと思います。私自身、Webアプリケーションに関する言語に詳しいわけではないのですが、Shinyを使えば、このようなWebアプリケーションを簡単に作成することができます。Shinyの基本操作についてはNp_Urさんの[こちらの記事](http://www.randpy.tokyo/entry/shiny_5)にて詳しく解説されています。
機能としては、国名を選択すると国旗画像が出力され、leaflet状にその国の首都の位置にマーカーが配置されるというものです。
![rekov-s5m6x.gif](https://qiita-image-store.s3.amazonaws.com/0/234290/56bcc32a-6887-c1e3-16c0-6a92e358720b.gif)

ソースコードは[こちら](https://github.com/YAhiroya/training_shiny/tree/master/CapitalCityMap)のgithubレポジトリにて公開しています。

それでは、具体的な実装方法について紹介していきます。
#Step.1　データの入手とShinyアプリ用フォルダの準備
今回は[leaflet](https://rstudio.github.io/leaflet/)ライブラリを使用します。このライブラリによる地図は、緯度経度の数値データを関連付けることができます。[平成30年（2018年）6月1日現在の世界の首都（未承認含む）の所在地・位置座標データ](http://www.amano-tec.com/data/world.html)ならびに[平成27年（2015年）6月1日現在の世界の国旗画像データ](http://www.amano-tec.com/data/worldflags.html)がアマノ技研から提供されているのでダウンロードをしてください。アプリのディレクトリツリーは次のようになります（120pixの国旗画像を使用しています）。
![世界地図アプリディレクトリツリー.PNG](https://qiita-image-store.s3.amazonaws.com/0/234290/66c8eeb8-5037-0626-6ccd-cb4fef6855cf.png)
位置座標データをダウンロードフォルダに保存していると仮定して.RDataの準備に移ります。

```R: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さんの[こちらの記事](https://qiita.com/uri/items/6b94609f156173ed43ed)にて
ちなみに、Rで読み込んだデータセットはこのようになります。
![位置座標データ.PNG](https://qiita-image-store.s3.amazonaws.com/0/234290/9efe6df2-d936-67b7-4bd3-b661ef4f7bba.png)

#Step.2　読み込んだデータをもとにプルダウンリストのUIを出力する
それでは、`server.R`と`ui.R`の設計に移ります。まず、読み込むライブラリは以下となります。

```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`に渡します。

```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　プルダウンリストの選択によってデータを整形
続いて、対話式のアプリケーション応答を実現するために変容データ`passData`を`reactive`関数を使用して定義します。

```R
### 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()`とコーディングすることに注意してください。

```R
### 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`を指定しないと画像ファイルが出力するたびに消去されてしまうので、注意が必要です。

```R
### 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ファイルとおわりに
```R: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)
  
})
```
```R:ui.R
library(shiny)
library(leaflet)

# shinyユーザーインターフェース
shinyUI(fluidPage(
  
  # タイトル
  titlePanel("世界の首都を確認しよう"),
  
  # サイドバー 
  sidebarLayout(
    sidebarPanel(
      uiOutput("pulldownUI"),
      imageOutput("Flag")
    ),
    
    # メイン
    mainPanel(
      leafletOutput("leaflet")
    )
  )
))
```

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

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