如何在r中的Shiny app中计算反应函数的时间

时间:2018-05-14 17:18:09

标签: r shiny reactive

我有一个我想要的时间函数,然后在UI上显示执行该函数需要多长时间。如何重新激活该功能的执行时间?我试图将变量放在反应函数中,围绕函数等。我只想计算反应函数运行多长时间然后显示它。我试图不使用其他包。

library(shiny)
# Define UI for application that draws a histogram
ui <- fluidPage(

  sidebarPanel(
    # User Input Text  Box
    textInput(inputId = "userText",
          label = "",
          placeholder = "Type in a partial sentence here..."),
    verbatimTextOutput(outputId = "textInput", placeholder = TRUE),

    # Show amount of execution time
    verbatimTextOutput(outputId = "timer", placeholder = TRUE)  
))

server <- function(input, output) {

  # Declare Timer variables
  startTime <- Sys.time()
  endTime <- Sys.time()

  # Some function to time: Trivial Paste Function
  textToDisplay <- reactive({
    req(input$userText)
    startTime <- Sys.time()
    textToDisplay <- paste("This is the user input text: ", input$userText)
    endTime <- Sys.time()
    return(textToDisplay)
  })

  # Display pasted text
  output$textInput <- renderText({
    req(input$userText)
    textToDisplay()

  })

  # Display execution time
  output$timer <- renderText({
    req(input$userText)
    paste0("Executed in: ",((endTime - startTime)*1000)," milliseconds")
  })
}

# Run the application 
shinyApp(ui = ui, server = server)

上述代码未正确更新或显示正确的时差。

3 个答案:

答案 0 :(得分:3)

Ah, the problem is that startTime and endTime aren't reactive values, so when they change they don't cause renderText to be invalidated and rerun and they don't persist properly outside the reactive expressions.

Just define a reactiveValues object, and make startTime and endTime part of that.

Replace the part where you define timer variables with:

rv <- reactiveValues()

Then, each time you call on startTime and endTime, use rv$startTime and rv$endTime.

You still won't see a result because textToDisplay runs too quickly, but if you make those changes and add Sys.sleep(2) into textToDisplay you'll see that it works properly.

答案 1 :(得分:1)

I think there is a bit of unnecessary code there. Your definition of startTime and endTime both within server and the individual reactive chunks is confusing (both to you and the readers); most certainly both locations are not required, and since I prefer the use of system.time, I suggest neither location is necessary.

There are two ways to deal with getting two return values (data and elapsed time) from a chunk: (1) return a list, and (2) reactiveValues().

Keeping your ui and shinyApp ...

For the first option (list), the server component becomes:

server <- function(input, output) {
  mydat <- eventReactive(input$userText, {
    req(input$userText)
    tm <- system.time({
      Sys.sleep(runif(1))
      out <- paste("This is the user input text:", sQuote(input$userText))
    })
    list(x=out, elapsed=tm['elapsed'])
  })
  # Display pasted text
  output$textInput <- renderText({
    req(mydat())
    mydat()$x
  })
  # Display execution time
  output$timer <- renderText({
    req(mydat())
    paste0("Executed in: ", round(mydat()$elapsed*1000), " milliseconds")
  })
}

For the second option, try:

server <- function(input, output) {
  times <- reactiveVal()
  mydat <- reactiveVal()
  # operates in side-effect
  observeEvent(input$userText, {
    req(input$userText)
    tm <- system.time({
      Sys.sleep(runif(1))
      out <- paste("This is the user input text:", sQuote(input$userText))
    })
    times(tm['elapsed'])
    mydat(out)
  })
  # Display pasted text
  output$textInput <- renderText({
    req(mydat())
    mydat()
  })
  # Display execution time
  output$timer <- renderText({
    req(times())
    paste0("Executed in: ", round(times()*1000), " milliseconds")
  })
}

(Instead of two reactiveVal() variables, you can also use @divibisan's suggestion to use reactiveValues(), the same end-result.)

答案 2 :(得分:0)

我使用的方法是你的建议@ r2evans和@divibisan的组合。我使用了reactiveValues,因为我认为它是用户可读的,可以很容易地扩展到其他用途。我按照建议使用了system.time。运行该函数时,它会更新无功值,并且return语句控制从函数返回适当的值。

server <- function(input, output) {
  options(digits.secs=2)

  # Declare Timer variables
  rv <- reactiveValues(
    exTime = Sys.time()
  )

  # Trivial Paste Function
  textToDisplay <- reactive({
    req(input$userText)
    t <- system.time({
      textToDisplay <- paste("This is the user input text: ", 
                             input$userText)
      })
    rv$exTime <- t[[3]]
    return(textToDisplay)
  })

  # Display pasted text
  output$textInput <- renderText({
    req(input$userText)
    textToDisplay()
  })

  # Display execution time
  output$timer <- renderText({
    req(input$userText)
    paste0("Executed in: ",((rv$exTime)*1000)," milliseconds")
  })
}

正如@divibisan建议的那样,这将显示0,因为代码运行得如此之快。您可以使用system.time()增加从options(digits.secs=2)返回的数字,我在服务器代码的顶部添加了这些数字。对于我的真实功能,这使我在Windows中运行了10毫秒的精度。