iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 24
0
Data Technology

你都在公司都在幹啥R? R語言資料分析經驗分享系列 第 24

【24】當老闆想了想問:可是有時候資料是分段處理的,這時候該怎麼使用shiny 處理呢?

大家可能看了標題會有些不懂,這邊我所指的分段處理意思是,有時候你的原始資料並不是很完善,要先做流程A 產生一定的結果,再去作流程B 去分析流程,或者是流程A 是一個非常費時的計算,你只需要執行A一次,之後再去做其他重覆跑的分析,說到底,我今天想介紹的就是Button 元件。

剛好,官方文件有一篇就是專門在講按鈕,我就用這篇為大家導讀。

Pattern 1 - Command
這是最直覺的使用方式,在ui 那邊宣告好按鈕後,直接在server 這邊寫監聽的事件,observeEvent 會去等待是否有按鈕的狀態改變了,而執行後面的程式碼。

library(shiny)

ui <- fluidPage(
  tags$head(tags$script(src = "message-handler.js")),
  actionButton("do", "Click Me")
)

server <- function(input, output, session) {
  observeEvent(input$do, {
    session$sendCustomMessage(type = 'testmessage',
      message = 'Thank you for clicking')
  })
}

shinyApp(ui, server)

Pattern 2 - Delay reactions
這個用法可以達到react 的效果,這邊直接看程式碼解釋比較清楚,因為有宣告繪圖的地方,所以一開始就會畫一次hist ,而randomVals() 為一個等待button 的觸發事件,因此只有點擊按鈕時才會執行。

library(shiny)

ui <- fluidPage(
  actionButton("go", "Go"),
  numericInput("n", "n", 50),
  plotOutput("plot")
)

server <- function(input, output) {

  randomVals <- eventReactive(input$go, {
    runif(input$n)
  })

  output$plot <- renderPlot({
    hist(randomVals())
  })
}

shinyApp(ui, server)

Pattern 3 - Dueling buttons
使用情境為同一事件可被兩個按鈕所觸發,先看reactiveValues 部分,他宣告了v 為react 元件,初始資料data 是null ,然後兩顆按鈕透過observeEvent 來改變v的data ,因此只要data 的狀態改變了,就會再次觸發renderPlot 去畫新的圖。

library(shiny)

ui <- fluidPage(
  actionButton("runif", "Uniform"),
  actionButton("rnorm", "Normal"), 
  hr(),
  plotOutput("plot")
)

server <- function(input, output){
  v <- reactiveValues(data = NULL)

  observeEvent(input$runif, {
    v$data <- runif(100)
  })

  observeEvent(input$rnorm, {
    v$data <- rnorm(100)
  })  

  output$plot <- renderPlot({
    if (is.null(v$data)) return()
    hist(v$data)
  })
}

shinyApp(ui, server)

另外,這邊要注意的是renderPlot 第一次的執行中必須要有使用到v$data,之後的react 才會成立,如果你寫成

output$plot <- renderPlot({
        if (round(runif(1)) %% 2 == 0) return()
        hist(v$data)
    })

然後亂數round(runif(1))剛好是0 直接return 出去,那麼就算你改變了v$data ,renderPlot也不會執行!

Pattern 4 - Reset buttons
其實和Patter 3 差不多,只是改成對data 設為null,使renderPlot 時直接return() 出去,就會有清空圖表的效果。

library(shiny)

ui <- fluidPage(
  actionButton("runif", "Uniform"),
  actionButton("reset", "Clear"), 
  hr(),
  plotOutput("plot")
)

server <- function(input, output){
  v <- reactiveValues(data = NULL)

  observeEvent(input$runif, {
    v$data <- runif(100)
  })

  observeEvent(input$reset, {
    v$data <- NULL
  })  

  output$plot <- renderPlot({
    if (is.null(v$data)) return()
    hist(v$data)
  })
}

shinyApp(ui, server)

Pattern 5 - Reset on tab change
這是文章裡最複雜的模式,ui 分了兩個tab 分頁,並指定元件id 為tabset,server 部分依樣指定v 為reactiveValues,然後監聽Plot 按鈕,只要一但按下,input$go 就會+1 ,另外也監聽tabset 是不是有切換分頁的行為,若有則將v$doPlot 設為0,這麼一來v$doPlot 只有在沒按過按鈕和切換分頁時會是false,最後在renderPlot 裡面可以看到isolate 函式,它可以將括號內程式碼脫離react,除去不該重覆跑的情況。

library(shiny)

ui <- fluidPage(
  sidebarLayout(
    sidebarPanel(
      tabsetPanel(id = "tabset",
        tabPanel("Uniform",
          numericInput("unifCount", "Count", 100),
          sliderInput("unifRange", "Range", min = -100, max = 100, value = c(-10, 10))
        ),
        tabPanel("Normal",
          numericInput("normCount", "Count", 100),
          numericInput("normMean", "Mean", 0),
          numericInput("normSd", "Std Dev", 1)
        )
      ),
      actionButton("go", "Plot")
    ),
    mainPanel(
      plotOutput("plot")
    )
  )
)

server <- function(input, output){
  v <- reactiveValues(doPlot = FALSE)

  observeEvent(input$go, {
    # 0 will be coerced to FALSE
    # 1+ will be coerced to TRUE
    v$doPlot <- input$go
  })

  observeEvent(input$tabset, {
    v$doPlot <- FALSE
  })  

  output$plot <- renderPlot({
    if (v$doPlot == FALSE) return()

    isolate({
      data <- if (input$tabset == "Uniform") {
        runif(input$unifCount, input$unifRange[1], input$unifRange[2])
      } else {
        rnorm(input$normCount, input$normMean, input$normSd)
      }
      
      hist(data)
    })
  })
}

shinyApp(ui, server)

以上就是大部分會用到button 的情況,今天的內容比較硬一些。

ref:
http://shiny.rstudio.com/articles/action-buttons.html
今天沒有程式碼


上一篇
【23】當老闆興奮地說:那太好了,就先來一個可以互動的表格當作示範吧!
下一篇
【25】當老闆扎了兩下眼問:那我們手邊資料有什麼情境適合這樣分段處理的嗎?
系列文
你都在公司都在幹啥R? R語言資料分析經驗分享30

尚未有邦友留言

立即登入留言