RStudio Shiny チュートリアル レッスン5 Rスクリプトとデータの利用

> この記事は Shiny 公式サイトのチュートリアルを翻訳したものです。
> http://shiny.rstudio.com/tutorial/lesson5/

チュートリアル目次：http://d.hatena.ne.jp/hoxo_m/20151222/p1

# LESSON5 Rスクリプトとデータの利用

このレッスンでは、Shiny アプリの中で「データ」「R スクリプト」「パッケージ」を使用するために、どうやって読み込むのかを見ていきます。
そのために、アメリカの国勢調査データを可視化する、少し複雑なアプリを構築していきます。

![views.png](https://qiita-image-store.s3.amazonaws.com/0/2570/db7c016f-9459-f902-c349-c99fb488a438.png)

## counties.rds

`counties.rds` は、`UScensus2010` パッケージに付属する、アメリカの各郡(county)に対する人口統計のデータセットをファイル化したものです。
このデータセットファイルは、[ここ](https://shiny.rstudio.com/tutorial/written-tutorial/lesson5/census-app/data/counties.rds)からダウンロードできます。

このデータファイルを入手したら、

- `census-app` ディレクトリの下に `data` フォルダを作成して下さい。
- `data` フォルダの中に `counties.rds` ファイルを置いて下さい。

これにより、`census-app` フォルダの中身は次のようになります。

![example2-folder.png](https://qiita-image-store.s3.amazonaws.com/0/2570/52a2f16a-91d8-b5d1-7b76-80492a3e9689.png)

`counties.rds` の中のデータセットには、次が含まれます。

- アメリカの各郡の名前
- 郡の総人口
- 郡に住む白人、黒人、ヒスパニック、アジア人の住民の割合

```r
counties <- readRDS("census-app/data/counties.rds")
head(counties)
             name total.pop white black hispanic asian
1 alabama,autauga     54571  77.2  19.3      2.4   0.9
2 alabama,baldwin    182265  83.5  10.9      4.4   0.7
3 alabama,barbour     27457  46.8  47.8      5.1   0.4
4    alabama,bibb     22915  75.0  22.9      1.8   0.1
5  alabama,blount     57322  88.9   2.5      8.1   0.2
6 alabama,bullock     10914  21.9  71.0      7.1   0.2
```

## helpers.R

`helpers.R` は、上で見たような[コロプレス地図](https://ja.wikipedia.org/wiki/%E9%9A%8E%E7%B4%9A%E5%8C%BA%E5%88%86%E5%9B%B3)を作るための R スクリプトです。
コロプレス地図とは、色によって変数の地域差を表示する地図のことです。
この `helpers.R` は、`counties.rds` のデータを地図上に表示するための関数 `percent_map` を生成します。
`helpers.R` は[ここ](http://shiny.rstudio.com/tutorial/lesson5/census-app/helpers.R)からダウンロードできます。

`helpers.R` は、`maps` および `mapproj` パッケージを使用します。
これらのパッケージをインストールしていない場合は、このアプリを作成する前にインストールしておく必要があります。
これらのパッケージをインストールするには、次のコードを実行します。

```r
install.packages(c("maps", "mapproj"))
```

`helpers.R` を `census-app` ディレクトリに保存して下さい。
次のようになります。

![example2-folder2.png](https://qiita-image-store.s3.amazonaws.com/0/2570/8e70c024-8a94-1071-f444-73aef10af8d6.png)

`helpers.R` 内の `percent_map` 関数は、次の 5 つの引数を持ちます：

|引数|入力するもの|
|:---|:---|
|`var`|`counties.rds` データセット内の列名のベクトル|
|`color`|色を指定するための文字列。使用可能な色は `colors()` で見ることができる|
|`legend.title`|プロットの凡例のタイトルに使われる文字列|
|`max`|陰の範囲を制御するための数値(デフォルト100)|
|`min`|陰の範囲を制御するための数値(デフォルト0)|

`percent_map` 関数は次のようにコマンドラインから使うことができます。
`percent_map` 関数は郡データをコロプレス地図としてプロットします。

```r
library(maps)
library(mapproj)
source("census-app/helpers.R")
counties <- readRDS("census-app/data/counties.rds")
percent_map(counties$white, "darkgreen", "% white", 0, 100)
```

注意：上記のコードでは、`census-app` はワーキングディレクトリの下にあると仮定しています。ワーキングディレクトリが `census-app` の親ディレクトリになっているか確認 して下さい。ワーキングディレクトリを変更するには、RStudio のメニューバーから Session > Set Working Directory > Choose Directory... をクリックします。

`percent_map` 関数は、郡データをコロプレス地図としてプロットします。
ここでは、郡内の白人の住民の割合を深緑(dark green)でプロットしています。

![census4.png](https://qiita-image-store.s3.amazonaws.com/0/2570/95d420fe-d33d-1dde-08fd-9c3ac13d5520.png)

## ファイルの読み込みとファイルパス

上のコードを見てみましょう。
`percent_map` 関数を使うために、まず `source` 関数によって `helpers.R` を実行し、次に、`readRDS` 関数によって `counties.rds` を読み込みました。
また、`library(maps)` および `library(mapproj)` を実行しました。

Shiny がアプリの中で `percent_map` 関数を呼び出す前に、これらの関数を実行しておく必要があります。
しかし、どのように書いたら良いのでしょうか？
`source` 関数と `readRDS` 関数には、ファイルパスを入力する必要があります。
そして、ファイルパスは Shiny アプリの中ではコマンドラインと同じようには動きません。

Shiny は、`server.R` の中でコマンドを実行するとき、すべてのファイルパスを `server.R` と同じディレクトリから始まるように取り扱います。
別の言い方をすれば、`server.R` を保存したディレクトリは、Shiny アプリのワーキングディレクトリとなります。

`helpers.R` は `server.R` と同じディレクトリに保存されているため、これを読み込むには、次のようにします。


```r
source("helpers.R")
```

`counties.rds` は `data` サブディレクトリに保存されているため、これを読み込むには、次のようにします。


```r
counties <- readRDS("data/counties.rds")
```

`maps` および `mapproj` パッケージを読み込むのは、通常の方法で大丈夫です。


```r
library(maps)
library(mapproj)
```

これらにはファイルパスを入力する必要はありません。

## 実行

`server.R` の中にこれらのコードを書けば、Shiny はすべてのコマンドを実行してくれます。
しかし、`server.R` のどこに書くかで、何回実行されるのかが異なります。
これは、アプリの実行速度に影響するため注意が必要です。

`server.R` の中には、Shiny が何度もコードを実行するセクションがあります。

Shiny は、`runApp` 関数が呼ばれた際に、一度だけコード全体を実行します。
これは、Shiny が `shinyServer` 関数を実行する引き金となります。
`shinyServer` 関数は、最初の引数である無名関数を Shiny に渡します。

![run-once.png](https://qiita-image-store.s3.amazonaws.com/0/2570/d6e4fc5d-c20b-9931-99c6-a8bca0d54dbe.png)

Shiny は、新しいユーザが訪問するまで、この関数を保存しておきます。
新しいユーザがアプリを訪問したとき、Shiny はこの無名関数を再実行します。
この関数は、Shiny が各ユーザに対して異なる reactive オブジェクトを構築するために使われます。

![run-once-per-user.png](https://qiita-image-store.s3.amazonaws.com/0/2570/4e5699f0-d2b7-20d8-842c-a4f0313f05d8.png)

ユーザがウィジェットを変更すると、Shiny は reactive オブジェクトに代入された表現式を再実行します。
この表現式は、ユーザによって、短い時間の間に何度も何度も実行される可能性があります。

![run-many-times.png](https://qiita-image-store.s3.amazonaws.com/0/2570/3a5e395b-6bf4-399f-8ff2-64709a98cc92.png)

ここまでで学んだことは、以下のとおりです：

- `server.R` スクリプトは、アプリを立ち上げた時に一度だけ実行されます。
- `shinyServer` 内の無名関数は、ユーザがアプリを**訪問するたびに**実行されます。
- `render*` 関数の中の表現式は、ユーザがウィジェットを変更するたびに、何度も実行されます。

ここから何が言えるでしょうか？

「スクリプト」「ライブラリ」「データセット」を読み込むためのコードは、`server.R` の最初、`shinyServer` 関数の**外側に**書いて下さい。
Shiny は、そのコードを一度だけ実行します。
これにより、`shinyServer` に含まれる表現式を実行するための準備がすべて完了します。

ユーザごとに必要なオブジェクトは、`shinyServer` の無名関数の中、`render*` 関数の外に定義して下さい。
このようなオブジェクトが必要になるのは、各ユーザに対して個人的な情報が必要になるときです。
例えば、ユーザの[セッション情報](http://shiny.rstudio.com/articles/client-data.html)を記録したいときなどです。

`render*` 関数の中には、Shiny が本当に再構築する必要のあるオブジェクトだけを書いてください。
ユーザが `render*` 関数内に記載されたウィジェットを変更するたびに、`render*` 関数内の**すべての**コードが再実行されます。
これはかなりの頻度になる可能性があります。

`render*` 関数の中では、必要のないコードを書くのを避けるべきです。
余分なコードはアプリ全体の実行速度を落とす原因となります。

## やってみよう 1

以下に示す `ui.R` と `server.R` をコピー & ペーストし、`census-app` ディレクトリ内にファイルとして保存しましょう。
そして、次のコードを `server.R` に加えて下さい。


```r
source("helpers.R")
counties <- readRDS("data/counties.rds")
library(maps)
library(mapproj)
```

必ず、効率的になるような場所に、これらのコマンドを置くようにして下さい。

注意：これはアプリを完成させるための最初のステップです。上のコードを挿入する最適な場所を選んで下さい。ただし、アプリはまだ実行してはいけません。ステップ 2 で `# some arguments` を実際のコードにするまでは、このアプリはエラーを返すでしょう。

### ui.R


```r
# ui.R

shinyUI(fluidPage(
  titlePanel("censusVis"),
  
  sidebarLayout(
    sidebarPanel(
      helpText("Create demographic maps with 
        information from the 2010 US Census."),
    
      selectInput("var", 
        label = "Choose a variable to display",
        choices = c("Percent White", "Percent Black",
          "Percent Hispanic", "Percent Asian"),
        selected = "Percent White"),
    
      sliderInput("range", 
        label = "Range of interest:",
        min = 0, max = 100, value = c(0, 100))
    ),
  
    mainPanel(plotOutput("map"))
  )
))
```

### server.R


```r
# server.R

shinyServer(
  function(input, output) {

    output$map <- renderPlot({
      
        percent_map( # some arguments )
    })

  }
)
```

(訳注：模範解答は公式サイトの [Model Answer 1](http://shiny.rstudio.com/tutorial/lesson5/#model-answer-1) にあります)

## アプリを完成させる

この censusVis アプリは、1 つの reactive オブジェクトを持ちます。
"map" という名前のプロットオブジェクトです。
このプロットは、`percent_map` 関数によって生成されます。
`percent_map` 関数は、5 つの引数を持ちます。

- 最初の 3 つの引数は、`var`, `color`, `legend.title` です。これらの引数は、セレクトボックスウィジェットの値に依存します。
- 最後の 2 つの引数は、`max` と `min` です。これらは、スライダーバーウィジェットの最大値と最小値になります。

下記の `server.R` スクリプトは、`percent_map` 関数に対する reactive な引数を作る方法を示しています。
R の `switch` 関数を使えば、セレクトボックスウィジェットの出力を好きなように変換することができます。
ただし、このスクリプトは不完全です。
`color`, `legend.title`, `max`, `min` に対する値が与えられていません。
注意：このスクリプトはこのままでは動きません。「やってみよう 2」でこのスクリプトを完成させてから実行して下さい。


```r
# server.R

library(maps)
library(mapproj)
counties <- readRDS("data/counties.rds")
source("helpers.R")

shinyServer(
  function(input, output) {
    output$map <- renderPlot({
      data <- switch(input$var, 
        "Percent White" = counties$white,
        "Percent Black" = counties$black,
        "Percent Hispanic" = counties$hispanic,
        "Percent Asian" = counties$asian)
  
      percent_map(var = data, color = ?, legend.title = ?, max = ?, min = ?)
    })
  }
)
```

## やってみよう 2

censusVis アプリが動くようにコードを完成させて下さい。

アプリを起動する準備が整ったら、`server.R` と `ui.R` を保存して、`runApp("census-app")` を実行して下さい。
もし、すべてがうまくいったら、アプリは下の画像のようになります。

アプリを完成させるためには、次のことを決める必要があります。

- どのようにして `percent_map` に渡す引数の値を作るか
- それらの引数を作るためのコードをどこに書くか

引数の値は、ユーザが対応するウィジェットを変化させると切り替わることを忘れないで下さい。
コードが完成するか、または行き詰まってしまったら、模範解答を見て下さい。

(訳注：模範解答は公式サイトの [Model Answers 2](http://shiny.rstudio.com/tutorial/lesson5/#model-answers-2) にあります)

![censusvis.png](https://qiita-image-store.s3.amazonaws.com/0/2570/c0ee4751-7b75-d10c-336a-29819e2f900f.png)

## まとめ

このレッスンでは、「R スクリプト」「パッケージ」「データセット」を使った、より複雑な Shiny アプリの作り方を学びました。

次のことを忘れないで下さい：

- `server.R` ファイルのあるディレクトリが、Shiny アプリのワーキングディレクトリになる。
- `server.R` のコードの中で、`shinyServer` より前にあるコードは、Shiny アプリの起動時に一度だけ実行される。
- `shinyServer` の中に書かれたコードは、何度も実行されるため、アプリの速度を低下させる原因となる。

また、`switch` 関数が、複数選択の Shiny ウィジェットとの対応付けに便利であることを学びました。
ウィジェットの値を R の表現式に変換するには、`switch` 関数を使って下さい。

アプリが複雑になるにつれて、非効率的で遅くなってしまう可能性がでてきます。
[レッスン6](http://qiita.com/hoxo_m/items/eac52edc2ee59534415d) では、reactive な表現式を使って、高速かつ部品化されたアプリを作る方法を学びます。

- [レッスン6 - reactiveな表現式の使用](http://qiita.com/hoxo_m/items/eac52edc2ee59534415d) 
- [チュートリアル目次へ戻る](http://d.hatena.ne.jp/hoxo_m/20151222/p1)