ふんわり R-tips

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

renderUIを用いた動的なShinyのユーザインタフェース

このエントリでは、rstudio::conf 2017で紹介されたShinyのinsertUIを解説します。

https://github.com/bborgesr/rstudio-conf2017

githubで公開されたソースコードを引用しています。

Shinyアプリケーションでは、予めui.R、または (app.R中の) uiオブジェクトとして、固定のUIを配置する必要があります。

動的なUIでは、入力に応じて表示されるUIコンポーネントの種類が変わります。Shinyで動的なUIを実現するための方法の一つがrenderUIです。

renderUIの使用例

「01-renderUI.R」はrenderUIの使用例です。ユーザの入力により、renderUIで動的なUIを表示します。

実行例

runAppでアプリケーションを実行すると、初期状態で、選択されたdatasetのsummaryが表示されています。

f:id:phmpk:20170227191436p:plain

plot, headを選択すると、summaryが表示されていたUIコンポーネントのあったメインパネルに、plotとheadが表示されます。

f:id:phmpk:20170227191456p:plain

f:id:phmpk:20170227191511p:plain

ソースコード

renderUIの使用例のコードを以下に示します。

library(shiny)
library(datasets)

shinyApp(
  ui = fluidPage(
    titlePanel('Using renderUI'),
    sidebarLayout(
      sidebarPanel(
        selectInput('data', 'Choose a dataset', c('rock', 'pressure', 'cars')),
        radioButtons('tool', 'Choose a tool', c('summary', 'plot', 'head'))
      ),
      mainPanel(
        uiOutput('result')
      )
    )
  ),
  server = function(input, output, session) {
    dataset <- reactive({ switch(input$data,
      'rock' = rock, 'pressure' = pressure, 'cars' = cars)
    })
    
    output$result <- renderUI({
      switch(input$tool,
        'summary' = verbatimTextOutput('summary'),
        'plot' = plotOutput('plot'),
        'head' = tableOutput('head'))
    })
    
    output$summary <- renderPrint({ summary(dataset()) })
    output$plot <- renderPlot({ plot(dataset()) })
    output$head <- renderTable({ head(dataset()) })
  }
)

ui側での定義

ui側でrenderUIを用いるためには、uiOutput(id)でコンポーネントを定義します。

使用例では、メインパネル中に宣言があります。

uiOutput('result')

server側でresultで定義されたuiコンポーネントを表示します。

server側での定義

server側では、renderUIで、以下のいずれかの方法で出力を返します。

  • output[[id]] <- renderUI({ ... }

  • output[[id]] <- renderUI({ tagList(...) })

使用例では、switch文を用いて、

output$result <- renderUI({
  switch(input$tool,
    'summary' = verbatimTextOutput('summary'),
    'plot' = plotOutput('plot'),
    'head' = tableOutput('head'))
})

ユーザの入力に対応して、verbatimTextOutput, plotOutput, tableOutputのいずれかを出力に指定します。

出力として定義したsummary, plot, headはそれぞれ対応するrender関数によるオブジェクトの定義が必要です。

output$summary <- renderPrint({ summary(dataset()) })
output$plot <- renderPlot({ plot(dataset()) })
output$head <- renderTable({ head(dataset()) })

まとめ

  • renderUIを用いて、ui中にuiOutputで指定したコンポーネントを動的に表示することができます。

  • ui側でuiOutputによるコンポーネントの定義、server側でrenderUIを用いて入力に応じて動的に表示するコンポーネントを変えます。

  • 表示するコンポーネントを変えるだけでなく、新たにコンポーネントを追加表示する場合には、uiOutputで確保したスロットに再度renderによる表示が必要となります。これを回避して、より動的にコンポーネントの追加表示を行うのに使用するのがinsertUIです。