2018-09-21

R Shiny を使ってみる (3)

Shiny は R のパッケージの一つで、 このパッケージを使うと R を用いて対話的に操作する Web アプリケーションを作成することができます。Web 上のユーザーインタフェース部分を司る ui.R と、内部動作を司る server.R の二つの R 言語スクリプトで、サーバーサイドのコンテンツを作成できることが大きな特徴です。

参考サイト [1] より引用

RStudio 上で Shiny による Web アプリケーションを作り始めたので、理解したことを備忘録としてまとめたことを不定期に紹介していきます。

本記事で使用している動作環境は次の通りです。

  • OS: Fedora 28 (x86_64)
  • R: R-core-3.5.0-4.fc28.x86_64, R-core-devel-3.5.0-4.fc28.x86_64
  • RStudio: rstudio-1.1.456-1.x86_64

自分が R を使って解析したい特定の分野について、Web アプリケーションを作成し、参考サイト [2] にある Shiny Server を Linux で稼働させて、作った Web アプリケーションを利用できるようにすることが目標です。しかし現時点では、その Web アプリケーションを作るだけの知識が伴っていないので、しばらくの間、簡単なサンプルで試行錯誤を続けて、判ったことをまとめていきたいと思います。

Web App の作成 : Iris explorer ver. 2

前回の Shiny の記事 [3] で紹介した Iris explorer のレイアウトを変更してプロットを追加しました。

Web アプリケーションでは、限られた面積の中でより多くの情報にアクセスできるようにやりくりしなければなりません。そのため Shiny ではいくつかのレイアウトを利用できるようになっていますが、今回は navlistPaneltabPanel を組み合わせてみました。

まず、実行例を以下に示しました。

Iris explorer ver. 2 の実行例

画面の左側にナビゲーションリストが表示されており、リストのアイテムをクリックすると、そのアイテムに対応した内容が画面右側に表示されるという構成です。これで画面のスクロールバーを動かすことなく、複数のプロットを表示できるようになりました。

このサンプルのコードを紹介します。

まず、ui.R を以下に示しました。

リスト:ui.R 
library(shiny)

fluidPage(
    titlePanel("Iris explorer ver. 2"),
    navlistPanel(
        widths = c(2, 10),
        # Scatter plot
        tabPanel(title = "Scatter",
                 plotOutput("scatter"),
                 selectInput(
                     inputId = "scatX",
                     label = "Select the X variable",
                     choices = c("Sepal.Length" = 1, "Sepal.Width" = 2, "Petal.Length" = 3, "Petal.Width" = 4)),
                 selectInput(
                     inputId = "scatY",
                     label = "Select the Y variable",
                     choices = c("Sepal.Length" = 1, "Sepal.Width" = 2, "Petal.Length" = 3, "Petal.Width" = 4), selected = 2)
        ),
        # Density plot
        tabPanel(title = "Density2D",
                 plotOutput("dense"),
                 selectInput(
                     inputId = "denseX",
                     label = "Select the X variable",
                     choices = c("Sepal.Length" = 1, "Sepal.Width" = 2, "Petal.Length" = 3, "Petal.Width" = 4)),
                 selectInput(
                     inputId = "denseY",
                     label = "Select the Y variable",
                     choices = c("Sepal.Length" = 1, "Sepal.Width" = 2, "Petal.Length" = 3, "Petal.Width" = 4), selected = 2)
        ),
        # Boxplot
        tabPanel(title = "Boxplot",
                 plotOutput("box"),
                 selectInput(
                     inputId = "boxY",
                     label = "Select the Y variable",
                     choices = c("Sepal.Length" = 1, "Sepal.Width" = 2, "Petal.Length" = 3, "Petal.Width" = 4))
        ),
        # Histogram
        tabPanel(title = "Histogram",
                 plotOutput("hist"),
                 selectInput(
                     inputId = "histX",
                     label = "Select the X variable",
                     choices = c("Sepal.Length" = 1, "Sepal.Width" = 2, "Petal.Length" = 3, "Petal.Width" = 4)),
                 sliderInput(
                     inputId = "bins",
                     label = "Number of bins:",
                     min = 1,
                     max = 50,
                     value = 25)
        )
    )
)

画面の基本レイアウトは fluidPage を用いた、行 (row) の中に列 (column) を定義していく構成です。その一行を navlistPanel が占め、その中で複数の tabPanel のパネルを切り替えて表示するという作りです。

tabPanel 関数の title = "..." で指定した文字列が画面左側に列挙され、クリックしたら定義されている内容が表示されます。パネルなどで指定しなければ、複数のプロットあるいはウィジェットは順番に縦方向に右側のパネルに配置されます。

次に、server.R を以下に示しました。

リスト:server.R 
library(shiny)
library(ggplot2)

gtheme <- theme(
    axis.title = element_text(size = 16),
    axis.text = element_text(size = 16),
    axis.line = element_line(),
    legend.title =  element_text(size = 14),
    legend.text = element_text(size = 14),
    panel.grid.major = element_line(colour = "grey", size = rel(0.5)), 
    panel.grid.minor = element_blank(), 
    panel.background = element_rect(fill = "whitesmoke")
)

function(input, output) {
    # -------------------------------------------------------------------------
    # Scatter plot
    # -------------------------------------------------------------------------
    x.scat <- reactive(iris[, as.numeric(input$scatX)])
    y.scat <- reactive(iris[, as.numeric(input$scatY)])
    xl.scat <- reactive(names(iris[as.numeric(input$scatX)]))
    yl.scat <- reactive(names(iris[as.numeric(input$scatY)]))
    output$scatter <- renderPlot({
        p <- ggplot(data = iris, aes(x = x.scat(), y = y.scat(), colour = Species))
        p <- p + xlab(xl.scat()) + ylab(yl.scat())
        p <- p + geom_point(size = 4) 
        p <- p + gtheme
        plot(p)
    })
    
    # -------------------------------------------------------------------------
    # Density2d plot
    # -------------------------------------------------------------------------
    x.dense <- reactive(iris[, as.numeric(input$denseX)])
    y.dense <- reactive(iris[, as.numeric(input$denseY)])
    xl.dense <- reactive(names(iris[as.numeric(input$denseX)]))
    yl.dense <- reactive(names(iris[as.numeric(input$denseY)]))
    output$dense <- renderPlot({
        p <- ggplot(data = iris, aes(x = x.dense(), y = y.dense(), colour = Species))
        p <- p + xlab(xl.dense()) + ylab(yl.dense())
        p <- p + geom_density2d(size = 1) 
        p <- p + gtheme
        plot(p)
    })
    
    # -------------------------------------------------------------------------
    # Boxplot
    # -------------------------------------------------------------------------
    y.box <- reactive(iris[, as.numeric(input$boxY)])
    yl.box <- reactive(names(iris[as.numeric(input$boxY)]))
    output$box <- renderPlot({
        p <- ggplot(data = iris, aes(x = Species, y = y.box(), color = Species))
        p <- p + ylab(yl.box())
        p <- p + geom_boxplot(size = 1, outlier.size = 4)
        p <- p + gtheme
        plot(p)
    })

    # -------------------------------------------------------------------------
    # Histgram
    # -------------------------------------------------------------------------
    x.hist <- reactive(iris[, as.numeric(input$histX)])
    xl.hist <- reactive(names(iris[as.numeric(input$histX)]))
    output$hist <- renderPlot({
        p <- ggplot(data = iris, aes(x = x.hist()))
        p <- p + geom_histogram(bins = input$bins, color = "black", aes(fill = Species))
        p <- p + xlab(xl.hist()) +  ylab("Frequency")
        p <- p + gtheme
        plot(p)
    })
}

こちらは、プロットする処理が並んでいるだけです。それぞれ、input に紐づけられた変数の変化に応じて(再)描画する処理を実行します。

参考サイト

  1. Shiny - RjpWiki
  2. Download Shiny Server - RStudio
  3. bitWalk's: R Shiny を使ってみる (2)

 

ブログランキング・にほんブログ村へ
にほんブログ村