読者です 読者をやめる 読者になる 読者になる

ふんわり R-tips

ぜんぜんわからない、俺たちは雰囲気でRをやっている

Shinyサンプルアプリケーション「07_widgets」の説明

Shiny

07_widgetsは、02_textにhelpTextsubmitButtonといったwidgetsを追加した例です。

「07_widgets」の実行

library(shiny)
runExample("07_widgets")

f:id:phmpk:20161230155834p:plain

server.R

library(shiny)
library(datasets)

# 選択されたデータのsummaryと、入力された数のデータを表示するサーバー側を定義
function(input, output) {
  
  # 選択されたデータセットを返す
  datasetInput <- reactive({
    switch(input$dataset,
           "rock" = rock,
           "pressure" = pressure,
           "cars" = cars)
  })
  
  # データセットのsummaryを生成
  output$summary <- renderPrint({
    dataset <- datasetInput()
    summary(dataset)
  })
  
  # 最初のn個のデータを表示
  output$view <- renderTable({
    head(datasetInput(), n = input$obs)
  })
}

Code license:MIT

  • datasetInputは、switch()の引数で指定したinput$datasetの値が変わると動的に値が変化

  • output$summaryは、datasetInput()の値が変化したとき、すなわちinput$datasetが変化したときに値が変化。input$obsを変えても変化しない

  • output$viewは、datasetInput()とinput$obsの2つのどちらか一方でも変化したときに値が変化

ui.R

library(shiny)

# データセットビューワのUIを定義
fluidPage(
  
  # タイトル
  titlePanel("More Widgets"),
  
  # サイドバーに、データセット選択と表示するデータ数入力を配置
  # helpText関数で、説明用のテキストを追加
  # submitButtonは、入力が変化したときではなく、ユーザにより明示的にボタンが押されたときに
  # はじめて出力が変化するよう動作させるために配置
  # 時間のかかる計算をサーバー側で行っているときに、有効なコントロールに使い方
  sidebarLayout(
    sidebarPanel(
      selectInput("dataset", "Choose a dataset:", 
                  choices = c("rock", "pressure", "cars")),
      
      numericInput("obs", "Number of observations to view:", 10),
      
      helpText("Note: while the data view will show only the specified",
               "number of observations, the summary will still be based",
               "on the full dataset."),
      
      submitButton("Update View")
    ),
    
    # datasetのsummaryと、入力された数のデータをHTMLの表として表示
    # h4関数は、出力の上側に表示する追加のヘッダ
    mainPanel(
      h4("Summary"),
      verbatimTextOutput("summary"),
      
      h4("Observations"),
      tableOutput("view")
    )
  )
)

Code license:MIT

  • helpText()で、複数行に渡る説明文を、文字列としてコントロールの下側に配置

  • submitButtonをサイドバーに配置。reactiveな入力の後でも、submitButtonが押されるまでは出力の表示が変化しない

Shinyサンプルアプリケーション「06_tabsets」の説明

Shiny

06_tabsetsは、サーバー側で分布を生成し、UI側で分布を3つの形式でタブ上に配置して表示する例です。

「06_tabsets」の実行

library(shiny)
runExample("06_tabsets")

f:id:phmpk:20161230155218p:plain

server.R

library(shiny)

# ランダムな分布を生成するサーバー側を定義
function(input, output) {
  
  # 分布を生成する
  # 入力が変化したときにreactiveに呼ばれる
  # 下部の出力関数は、ここで生成したreactiveな分布を使用する
  data <- reactive({
    dist <- switch(input$dist,
                   norm = rnorm,
                   unif = runif,
                   lnorm = rlnorm,
                   exp = rexp,
                   rnorm)
    
    dist(input$n)
  })
  
  # dataのプロットとラベルを生成
  # 入力は両方と依存関係があり、どちらかが変化したときはそれに追随して変化する
  output$plot <- renderPlot({
    dist <- input$dist
    n <- input$n
    
    hist(data(), 
         main=paste('r', dist, '(', n, ')', sep=''))
  })
  
  # データのsummaryを生成
  output$summary <- renderPrint({
    summary(data())
  })
  
  # HTMLで表記したデータの表を生成
  output$table <- renderTable({
    data.frame(x=data())
  })
  
}

Code license:MIT

  • switch()distに、分布を生成するための関数名を与える。rnorm()は正規分布を、runif()は連続一様分布、rlnorm()は対数正規分布、rexp()は指数分布である

  • 例として、input$distnorminput$nが50のとき、17行目のdist(input$n)ではrnorm(50)が実行され、以下の分布を返す

> rnorm(50)
 [1] -0.62914536 -0.73371948  0.30965080 -0.27329928 -1.18324678  1.06704008 -0.93215703
 [8] -0.73117791 -1.65166615 -0.36209932 -0.76875906  0.54347454  1.17110890  0.03704137
[15] -1.86078985  1.37193112  0.76647807  1.91547888 -1.04685644 -1.19995233 -0.13173718
[22]  1.32920123  1.19872686  0.01525256  0.33566227 -1.95291135  0.58520576  0.04062392
[29] -0.73173476  2.41503834  0.17942321  0.30430169 -1.43702559 -0.26643687 -0.09946178
[36] -1.61477804  0.65289756 -0.18279837  1.32254177  0.31122224  0.24928538 -0.91399839
[43]  0.75083835 -0.76780444  0.13232907  1.28965217  0.26054202  0.64163957  2.09648604
[50]  1.10425454
  • hist()で生成したデータのヒストグラムを生成

  • summary()でデータのsummaryを文字列として生成

  • data.frame()でデータの表を生成

ui.R

library(shiny)

# ランダムな分布を表示するUIを定義
fluidPage(
    
  # タイトル
  titlePanel("Tabsets"),
  
  # サイドバーに、ランダムな分布の種類と、データ数を選択するコントロールを配置
  # br()は、余分な垂直のスペースを作るために挿入
  sidebarLayout(
    sidebarPanel(
      radioButtons("dist", "Distribution type:",
                   c("Normal" = "norm",
                     "Uniform" = "unif",
                     "Log-normal" = "lnorm",
                     "Exponential" = "exp")),
      br(),
      
      sliderInput("n", 
                  "Number of observations:", 
                   value = 500,
                   min = 1, 
                   max = 1000)
    ),
    
    # 生成された分布のプロット、summary、HTMLの表を含むタブを表示
    mainPanel(
      tabsetPanel(type = "tabs", 
        tabPanel("Plot", plotOutput("plot")), 
        tabPanel("Summary", verbatimTextOutput("summary")), 
        tabPanel("Table", tableOutput("table"))
      )
    )
  )
)

Code license:MIT

  • サイドバーに、radioButtons()でラジオボタンを、sliderInput()でスライダーを配置

  • tabsetPanelで3つのタブtabPanel()を配置。それぞれ、plotOutput(), verbatimTextOutput(), tableOutput()でプロット、テキスト、HTML表を出力f:id:phmpk:20161230155218p:plain

Shinyサンプルアプリケーション「05_sliders」の説明

Shiny

05_slidersは、5つのスライダーと、その値をテキスト表示する例です。

「05_sliders」の実行

library(shiny)
runExample("05_sliders")

f:id:phmpk:20161230154703p:plain

server.R

library(shiny)

# サーバー側のスライダーの動作を定義
function(input, output) {
  
  # すべての変数に対応するreactiveな動作を定義
  sliderValues <- reactive({
    
    # データフレームの構成
    data.frame(
      Name = c("Integer", 
               "Decimal",
               "Range",
               "Custom Format",
               "Animation"),
      Value = as.character(c(input$integer, 
                             input$decimal,
                             paste(input$range, collapse=' '),
                             input$format,
                             input$animation)), 
      stringsAsFactors=FALSE)
  }) 
  
  # HTMLの表を出力
  output$values <- renderTable({
    sliderValues()
  })
}

Code license:MIT

  • スライドバーからの入力を、as.character()で文字列としてデータフレームを構成して、reactiveにsliderValuesに代入

  • sliderValues()をoutput$valuesとしてHTMLの表を出力

ui.R

library(shiny)

# スライダーデモのUIを定義
fluidPage(

  # タイトル
  titlePanel("Sliders"),

  # サイドバーに多様なオプションを付けたスライドバーを配置
  sidebarLayout(
    sidebarPanel(
      # シンプルな整数
      sliderInput("integer", "Integer:",
                  min=0, max=1000, value=500),

      # 指定したステップ刻みの10進数
      sliderInput("decimal", "Decimal:",
                  min = 0, max = 1, value = 0.5, step= 0.1),

      # 幅を指定
      sliderInput("range", "Range:",
                  min = 1, max = 1000, value = c(200,500)),

          # アニメーション付きのカスタムフォーマットを指定
      sliderInput("format", "Custom Format:",
                  min = 0, max = 10000, value = 0, step = 2500,
                  pre = "$", sep = ",", animate=TRUE),

          # ループありのアニメーション付きのカスタムフォーマットを指定
      sliderInput("animation", "Looping Animation:", 1, 2000, 1,
                        step = 10, animate=
                            animationOptions(interval=300, loop=TRUE))
    ),

    # 変数のsummaryを表示する表を出力
    mainPanel(
      tableOutput("values")
    )
  )
)

Code license:MIT

Shinyサンプルアプリケーション「04_mpg」の説明

Shiny

04_mpgは、(車で走行する場合の)ガロンとマイルの関係(MPG:mile per gallon)を箱ひげ図で表示する例です。ガロンはガソリンの単位で、マイルは距離の単位。

「04_mpg」の実行

library(shiny)
runExample("04_mpg")

f:id:phmpk:20161230154313p:plain

server.R

library(shiny)
library(datasets)

# 使用するデータセットmtcarsをmpgDataに代入
# mpgDataのam特徴量を、よりわかりやすい変数に置き換え
mpgData <- mtcars
mpgData$am <- factor(mpgData$am, labels = c("Automatic", "Manual"))

# 選択された項目に対してプロットを返すサーバー側を定義
function(input, output) {

  # formula textをreactiveな式として計算
  # formula textは、以下でoutput$captionとoutput$mpgPlotそれぞれの計算で使用される
  formulaText <- reactive({
    paste("mpg ~", input$variable)
  })

  # formula textをcaptionとして返す
  output$caption <- renderText({
    formulaText()
  })

  # formula textで指定された変数に対応するplotを返す
  # outlineの指定があれば、表示する
  output$mpgPlot <- renderPlot({
    boxplot(as.formula(formulaText()),
            data = mpgData,
            outline = input$outliers)
  })
}

Code license:MIT

  • mtcarsは以下に示す、車種ごとのデータセット
> library(datasets)
> mtcars
                     mpg cyl  disp  hp drat    wt  qsec vs am gear carb
Mazda RX4           21.0   6 160.0 110 3.90 2.620 16.46  0  1    4    4
Mazda RX4 Wag       21.0   6 160.0 110 3.90 2.875 17.02  0  1    4    4
Datsun 710          22.8   4 108.0  93 3.85 2.320 18.61  1  1    4    1
Hornet 4 Drive      21.4   6 258.0 110 3.08 3.215 19.44  1  0    3    1
Hornet Sportabout   18.7   8 360.0 175 3.15 3.440 17.02  0  0    3    2
Valiant             18.1   6 225.0 105 2.76 3.460 20.22  1  0    3    1
Duster 360          14.3   8 360.0 245 3.21 3.570 15.84  0  0    3    4
Merc 240D           24.4   4 146.7  62 3.69 3.190 20.00  1  0    4    2
Merc 230            22.8   4 140.8  95 3.92 3.150 22.90  1  0    4    2
Merc 280            19.2   6 167.6 123 3.92 3.440 18.30  1  0    4    4
Merc 280C           17.8   6 167.6 123 3.92 3.440 18.90  1  0    4    4
Merc 450SE          16.4   8 275.8 180 3.07 4.070 17.40  0  0    3    3
Merc 450SL          17.3   8 275.8 180 3.07 3.730 17.60  0  0    3    3
Merc 450SLC         15.2   8 275.8 180 3.07 3.780 18.00  0  0    3    3
Cadillac Fleetwood  10.4   8 472.0 205 2.93 5.250 17.98  0  0    3    4
Lincoln Continental 10.4   8 460.0 215 3.00 5.424 17.82  0  0    3    4
Chrysler Imperial   14.7   8 440.0 230 3.23 5.345 17.42  0  0    3    4
Fiat 128            32.4   4  78.7  66 4.08 2.200 19.47  1  1    4    1
Honda Civic         30.4   4  75.7  52 4.93 1.615 18.52  1  1    4    2
Toyota Corolla      33.9   4  71.1  65 4.22 1.835 19.90  1  1    4    1
Toyota Corona       21.5   4 120.1  97 3.70 2.465 20.01  1  0    3    1
Dodge Challenger    15.5   8 318.0 150 2.76 3.520 16.87  0  0    3    2
AMC Javelin         15.2   8 304.0 150 3.15 3.435 17.30  0  0    3    2
Camaro Z28          13.3   8 350.0 245 3.73 3.840 15.41  0  0    3    4
Pontiac Firebird    19.2   8 400.0 175 3.08 3.845 17.05  0  0    3    2
Fiat X1-9           27.3   4  79.0  66 4.08 1.935 18.90  1  1    4    1
Porsche 914-2       26.0   4 120.3  91 4.43 2.140 16.70  0  1    5    2
Lotus Europa        30.4   4  95.1 113 3.77 1.513 16.90  1  1    5    2
Ford Pantera L      15.8   8 351.0 264 4.22 3.170 14.50  0  1    5    4
Ferrari Dino        19.7   6 145.0 175 3.62 2.770 15.50  0  1    5    6
Maserati Bora       15.0   8 301.0 335 3.54 3.570 14.60  0  1    5    8
Volvo 142E          21.4   4 121.0 109 4.11 2.780 18.60  1  1    4    2
  • factor()で、mpgDataのam特徴量を”Automatic”, "Manual"の2つの文字列に置き換え

  • paste()で、"mpg ~"に指定されたinput$variableを結合

  • boxplot()で、箱ひげ図のプロットを返す。as.formulaで式を指定、dataでformulaで指定するデータを指定、outlineで外れ値を表示するかどうかを指定

ui.R

library(shiny)

# ガロン/マイルを表示するUI定義
fluidPage(
  
  # タイトル
  titlePanel("Miles Per Gallon"),
  
  # サイドバーに、mpgをプロットするための変数選択と、外れ値を指定するかどうかを
  # 指定するチェックボックスを配置
  sidebarLayout(
    sidebarPanel(
      selectInput("variable", "Variable:",
                  c("Cylinders" = "cyl",
                    "Transmission" = "am",
                    "Gears" = "gear")),
  
      checkboxInput("outliers", "Show outliers", FALSE)
    ),
    
     # captionとplotをmainPanelに配置
    mainPanel(
      h3(textOutput("caption")),
      
      plotOutput("mpgPlot")
    )
  )
)

Code license:MIT

  • selectInput()で、Cylinders, Transmission, Gearsのいずれかの文字列を選択

  • checkboxInput()でチェックボックスを配置。チェックした場合の返り値はTRUEで、初期値はFALSE

  • h3()で、h3の大きさのcaptionを配置

  • plotOutput()でmpgPlotで指定した箱ひげ図を表示

Shinyサンプルアプリケーション「03_reactivity」の説明

Shiny

03_reactivityは、inputとoutputがどのようにreactiveに変化するのかを説明する例。02_textと同様の変数や関数で、input$dataset, input$caption, output$caption, output$viewそれぞれの計算に依存関係がある場合に、どの変数を変えると、どの出力がreactiveに変化するのか理解できる例になっています。

「03_reactivity」の実行

library(shiny)
runExample("03_reactivity")

f:id:phmpk:20161230153325p:plain

server.R

library(shiny)
library(datasets)

# 選択されたデータセットのsummaryと全体を表示するためのサーバ側を定義
function(input, output) {

  # datasetInputをreactiveな式として宣言
  #  1) reactiveなので、入力が変化したときだけ呼ばれる
  #  2) 計算結果は、すべての関数呼び出しで共有される
  datasetInput <- reactive({
    switch(input$dataset,
           "rock" = rock,
           "pressure" = pressure,
           "cars" = cars)
  })
  
  # output$captionは、input$captionが返す値の変化に合わせてreactiveに値を変える
  # 
  # ただし、以下のoutput$summaryは、input$captionに依存しないので、input$captionを変えても
  # reactiveに変化しない
  output$caption <- renderText({
    input$caption
  })
  
  # reactiveなdatasetInputに合わせて、output$summaryの結果が変化
  # datasetInputの結果が変わるのは、input$datasetが変わったときなので、
  # 入力が変わったときに、output$summaryはreactiveに値を変化させる
  output$summary <- renderPrint({
    dataset <- datasetInput()
    summary(dataset)
  })
  
  # output$viewはdatasetInput()とinput$obs両方に依存して値が変わるので、
  # 入力のinput$datasetとinput$obsのどちらか一方でも変化した場合に、reactiveに値を変える
  output$view <- renderTable({
    head(datasetInput(), n = input$obs)
  })
}

Code license:MIT

  • datasetInputは、switch()の引数で指定したinput$datasetの値が変わると動的に値が変化

  • output$captionは、input$captionの値が変わると動的に値が変化

  • output$summaryは、datasetInput()の値が変化したとき、すなわちinput$datasetが変化したときに値が変化。input$obsを変えても変化しない

  • output$viewは、datasetInput()とinput$obsの2つのどちらか一方でも変化したときに値が変化

ui.R

library(shiny)

# データセットビューワのUIを定義
fluidPage(
  
  # タイトル
  titlePanel("Reactivity"),
  
  # サイドバーには、caption, データセット選択, 表示するデータ数入力の3つのコントロール
  # captionを変えたときには、出力が直ちに変化する
  sidebarLayout(
    sidebarPanel(
      textInput("caption", "Caption:", "Data Summary"),
      
      selectInput("dataset", "Choose a dataset:", 
                  choices = c("rock", "pressure", "cars")),
      
      numericInput("obs", "Number of observations to view:", 10)
    ),
    
    
    # captionとデータセットのsummary、入力された数のデータセットのHTML表示
    mainPanel(
      h3(textOutput("caption", container = span)),
      
      verbatimTextOutput("summary"), 
      
      tableOutput("view")
    )
  )
)

Code license:MIT

  • sideberPanel()で、3つのコントロールtextInput, selectInput, numericInputをサイドバーに配置

  • mainPalen()で、3つのコントロールh3, verbatimTextOutput, tableOutputを配置

  • h3は、h3の大きさの文字列を配置

  • verbatimTextOutput()で、summaryで指定された文字列をそのまま出力

  • tableOutput()で、viewで指定された表をHTML出力

Shinyサンプルアプリケーション「02_text」の説明

Shiny

02_textは、データセット選択と表示するデータ数を入力として、選択されたデータセットのsummaryと入力されたデータ数のデータセットをHTMLで表として出力する例となっています。

「02_text」の実行

library(shiny)
runExample("02_text")

f:id:phmpk:20161230152939p:plain

server.R

library(shiny)
library(datasets)

# 選択されたデータセットの合計と全体を表示するためのサーバ側を定義
function(input, output) {
  
  # 選択されたデータセットを返す
  datasetInput <- reactive({
    switch(input$dataset,
           "rock" = rock,
           "pressure" = pressure,
           "cars" = cars)
  })
  
  # データセットのsummaryを計算
  output$summary <- renderPrint({
    dataset <- datasetInput()
    summary(dataset)
  })
  
  # 最初のn個のデータを表示するテーブル
  output$view <- renderTable({
    head(datasetInput(), n = input$obs)
  })
}

Code license:MIT

  • input$dataset, input$obsを入力として、出力output$summary, output$viewを描画

  • datasetInputに、"rock","pressure","cars"のいずれかの文字列に対応したinput$datasetの値を動的に代入

  • summary(dataset)でdatasetの最小・最大・平均などを計算してrenderPrint()で文字列として出力

  • input$obsで指定したn個のデータをrendrTable()で表として描画

ui.R

library(shiny)

# データセットを表示するUIを定義
fluidPage(
  
  # タイトル
  titlePanel("Shiny Text"),
  
  # サイドバーに、データセット選択と表示するデータ数を
  # 決定するコントロールを配置
  sidebarLayout(
    sidebarPanel(
      selectInput("dataset", "Choose a dataset:", 
                  choices = c("rock", "pressure", "cars")),
      
      numericInput("obs", "Number of observations to view:", 10)
    ),
    
    # データセットのsummaryとHTMLテーブルを表示
    mainPanel(
      verbatimTextOutput("summary"),
      
      tableOutput("view")
    )
  )
)

Code license:MIT

  • selectInput()でプルダウンメニューを配置。選択した文字列はdatasetに格納される。

  • numericInput()で整数値入力を配置。選択した整数値はobsに格納される。

  • verbatimTextOutput()で、summaryで指定された文字列をそのまま出力

  • tableOutput()で、viewで指定された表をHTML出力

Shinyサンプルアプリケーション「01_hello」の説明

Shiny

01_helloは、入力用スライダーと出力用のプロットがあり、server.Rで入力された値をプロットに変換するプログラムとなっています。

「01_hello」の実行

library(shiny)
runExample("01_hello")

f:id:phmpk:20161230151451p:plain

server.R

library(shiny)

# ヒストグラムを描くためのサーバ側を定義
function(input, output) {

  # ヒストグラムを描く式は、以下に示すrenderPlot関数の呼び出しの中で定義
  #
  #  1) renderPlot関数はreactive、すなわち入力が変化したときに自動的に再計算される
  #  2) 出力型はプロット

  output$distPlot <- renderPlot({
    x    <- faithful[, 2]  # オルド・フェイスフル・ガイザーデータ
    bins <- seq(min(x), max(x), length.out = input$bins + 1)

    # 特定のbinごとにヒストグラムを描画
    hist(x, breaks = bins, col = 'darkgray', border = 'white')
  })

}

Code license:MIT

  • function(input, output)の宣言により、入力はinput$で、表示する出力はoutput$で表記する。01_helloではinput$binsoutput$distPlotが対応しており、それぞれui.Rに同名の変数がある

  • output$distPlotには、renderPlot()が返すプロットが入る。renderPlot()はreactiveなので、ui.RでdistPlotは入力が変わるたびに再計算されて表示される。

  • faithfulは、イエローストーン国立公園のオルド・フェイスフル・ガイザーという有名な間欠泉の噴火と待ち時間のデータセット。

  • (input$ではない) binsに代入されているseq()の返す値は、待ち時間の最小値min(x)と最大値max(x)を含むbinsで指定された数のリスト

  • histでbinsで指定された値に対応する噴火時間xの値をヒストグラム化

ui.R

library(shiny)

# ヒストグラムを描くためのUI側を定義
fluidPage(

  # タイトル
  titlePanel("Hello Shiny!"),

  # 入力用スライダーのあるサイドバーレイアウト
  sidebarLayout(
    sidebarPanel(
      sliderInput("bins",
                  "Number of bins:",
                  min = 1,
                  max = 50,
                  value = 30)
    ),

    # 生成された分布のプロットを表示
    mainPanel(
      plotOutput("distPlot")
    )
  )
)

Code license:MIT

  • fluidPage()でuiオブジェクトを生成

  • titlePanel()でウィンドウのタイトルを定義

  • sidebarLayout()で、sidebarPanelとmainPanelの2つのパネルをサイドとメインに分けてレイアウト。

  • sliderInput()でサイドのスライドバーのタイトルや大きさを定義。

  • mainPanelでは、(server.Rで動的に値が変化する) distPlotを引数として、plotOutput()でプロットを表示