Shinyでリアクティブなグラフ

この記事は[RStudio Advent Calendar 2016](http://qiita.com/advent-calendar/2016/rstudio-ide)の18日目の記事です。

超入門編ですのでお気を付けください。
RStudioでプロジェクトを新規作成しようとすると、
![image](https://qiita-image-store.s3.amazonaws.com/0/83530/5f6cf6f8-906b-e0dc-c6d6-99b1c622a783.png)

Shiny Web Applicationというメニューが出てきます。
これはR言語でWebページを作れるもので、ちょっとしたデータの可視化を行う時に非常に便利なので作り方を紹介します。

# ui.Rとserver.R

作り方とは言いましても、ウィザードに沿って新規作成すると、グラフが表示されるサンプル付のプロジェクトが作成されます。
ui.Rとserver.Rが作成されますので、その2つを拡張していく形になります。

## ui.R

画面を構築するところです。
ここでは情報入力用のウィジェットの配置と、server.R側で処理した結果を受け取る場所の確保をします。
ウィジェットはボタンやチェックボックス、スライダーや日付入力など、かなりの種類が用意されています。

- [Shiny - Add control widgets](http://shiny.rstudio.com/tutorial/lesson3/)

server.Rからの処理結果受け取りは
xxxOutputという関数を利用します。plotOutputやtextOutputなどがありますので出力するものの種類によって配置していきます。

- [Shiny - Display reactive output](http://shiny.rstudio.com/tutorial/lesson4/)

## server.R

ui.R側から入力された情報を受け取り、処理を行って結果を返すいわゆるサーバー側の処理を行うところです。
こちらは引数にあるinputとoutputを参照/操作することで組み立てていきます。
`input$xxx`で、ui.Rからの入力を受け取ることができます。
`output$xxx`で、ui.Rに用意しているxxxOutputに処理結果を渡すことができます。
処理結果の渡し方はrenderXxx()という関数を利用します。（詳細は下記サンプルコードで。）


# リアクティブプログラミング

ここからui.Rとserver.Rを拡張していくわけですが、Shinyではリアクティブプログラミングというプログラミングモデルが採用されています。
初めてShinyを触ったときにこの辺りで混乱することがあったので、特徴をまとめておきます。

リアクティブプログラミングはよくExcelに例えられることがあります。
Excelではセルを編集した際に、そのセルを参照している別のセルが自動的に変更されます。
これをWebページで考えてみると、
![image](https://qiita-image-store.s3.amazonaws.com/0/83530/0c9adf48-74b5-107c-23f0-3285aa1a1488.png)
入力項目とそれを反映させるボタンがあるとして、ユーザが情報を入力のためスライダーやラジオボタンを変更すると勝手にグラフが反映されるのがリアクティブな動き（上の図）で、入力が完了し何らかのアクション（「plot!」ボタンを押すとか）があるまでグラフが更新されない、というのが通常のWebの動き（画像なので分かりにくいですが下の図）です。

となると、「各ウィジェットの変更イベントを逐一監視しておくようなプログラムを書けばいいのかな？」と最初思っていましたが、そうではなく「入力と出力の関係を記述するプログラムを書けばいい」と頭を切り替えてから違和感なくプログラムが組めるようになってきました。

#リアクティブにしないプログラミング

入力の変化があったごとに出力を更新、という聞くと難しそうに感じますが、変更の監視や再描画のタイミングなどはShinyが管理してくれていますので、入力と出力を定義していくとグラフが自動描画されるWebページができます。なかなか感動します。
例えば入力項目とグラフをそのまま紐づける場合は、グラフを生成するrenderPlotの中に`input$xxx`を書いておくだけです。

```R:入力に応じてグラフが描画
output$plot1 <- renderPlot({
  color <- input$xxx
  hist(x, breaks = bins, col = color, border = 'white')
})
```
しかし、場合によっては常に再描画をやめて通常のWebのように特定のアクションがあったときのみ動かしたいということもあります。
そのようなときはisolate()という関数を利用すると便利です。
isolateを使うとその中にある`input$xxx`はrenderPlotとの紐づきが分離されます。

```R:isolate
output$plot1 <- renderPlot({
  color <- isolate({
    input$xxx
  })
  input$yyy
  hist(x, breaks = bins, col = color, border = 'white')
})
```
この状態ですと、`input$xxx`が変更してもグラフは再描画されません、`input$yyy`が変更されると全体が再描画されます。

自動生成されるプログラムに少し足しただけですが、入力項目を変更したタイミングでグラフが更新されるグラフとボタンを押して初めて更新されるグラフを並べた例を紹介します。（実行画面は上の図）

```R:ui.R
library(shiny)

shinyUI(pageWithSidebar(
  
  headerPanel("RStudio Advent Calendar 2016"),
  #サイドに表示するウィジェットを並べていきます
  sidebarPanel(
    sliderInput("bins",
                "Number of bins:",
                min = 1,
                max = 50,
                value = 30),
    radioButtons("rad_color", label = h3("Select color"),
                 choices = list("Red" = "red", "Blue" = "blue",
                                "Yellow" = "yellow"),selected = "red"),
    hr(),
    actionButton("btn_go","plot!")
  ),
  #plot表示エリアを２つ確保
  mainPanel( 
    plotOutput("plot1"),
    plotOutput("plot2")
  )
))
```

```R:server.R
library(shiny)

shinyServer(function(input, output) {
  #リアクティブなグラフを出力
  output$plot1 <- renderPlot({
    
    x    <- faithful[, 2] 
    bins <- seq(min(x), max(x), length.out = input$bins + 1)
    
    hist(x, breaks = bins, col = input$rad_color, border = 'white')
    
  })
  #ボタンを押したときのみグラフを更新
  output$plot2 <- renderPlot({
    
    x    <- faithful[, 2] 
    #スライダーの変化監視を分離
    bins <- isolate({
      seq(min(x), max(x), length.out = input$bins + 1)
    })
    #ラジオボタンの変化監視を分離
    color <- isolate({
      input$rad_color
    })
    
    input$btn_go
    
    hist(x, breaks = bins, col = color, border = 'white')
  })
})
```

Shinyは実際触ってみると、ぐりぐり動くこともあって非常に面白いフレームワークです。RStudioを導入していればすぐに始めることができるので、いろいろ作ってみましょう。

# 参考とおすすめ

- [Shiny - Welcome to Shiny](http://shiny.rstudio.com/tutorial/lesson1/)
- [RStudio Shiny チュートリアル レッスン1 ようこそ Shiny へ](http://qiita.com/hoxo_m/items/c8365117f3444fb51df4)

Shinyのチュートリアルと日本語訳されている記事です。英語が苦手な身としては非常にありがたい…。

- [Shinyのチートシート](http://shiny.rstudio.com/articles/cheatsheet.html)

これがあれば大丈夫！