【问题标题】:Time interval between clicks on the same button - shiny R单击同一按钮之间的时间间隔 - 闪亮的 R
【发布时间】:2018-01-17 00:32:49
【问题描述】:

很抱歉问了一些愚蠢的问题。我很确定它有一个简单的解决方案,但我仍然无法弄清楚。

我有一个动作按钮,我点击它几次,我应该有点击之间的时间间隔。

示例,

我现在单击按钮,两分钟后再次单击,第二次单击后 4 分钟再次单击,第三次单击后再次单击 5 分钟,依此类推。

2 分钟 = 第二次点击和第一次点击之间的时间差

4 分钟 = 第三次点击和第二次点击之间的时间差

5 分钟 = 第四次点击和第三次点击之间的时间差

我可以用两个按钮做到这一点,这很容易,但一个按钮我不知道会怎样。

谢谢,

【问题讨论】:

  • 到目前为止,你用一键尝试过什么?

标签: r shiny


【解决方案1】:

这是一个简单的例子。您可以将所有点击时间存储在reactiveVal 中,在点击actionButton 时使用observeEvent 更新此向量,并在此向量上使用diff 以秒为单位计算时间间隔。希望这会有所帮助!

library(shiny)
ui <-   fluidPage(
  actionButton('mybutton','press me'),
  textOutput('mytext'),
  textOutput('mytext2')
)

server <- function(input,output)
{
  click_times <- reactiveVal()
  observeEvent(input$mybutton, {
    click_times(c(click_times(),Sys.time()))
  })

  # print all intervals in seconds
  output$mytext <- renderText({
    if(length(click_times())<2)
    {'Less than two clicks!'} else {
      paste0('Time intervals: ', paste(round(diff(click_times()),2),collapse=' seconds, '),' seconds.')}
  })

  # print last interval in minutes:seconds format
  output$mytext2 <- renderText({
    if(length(click_times())<2)
    {'Less than two clicks!'} else {
      ct <- as.POSIXct(round(tail(diff(click_times()),1),2), origin = "1970-01-01", tz = "UTC")
      paste0('Last interval: ' ,format(ct,'%M:%S')) }
  })
}

shinyApp(ui,server)

【讨论】:

  • 只是为了好奇@Florian。您的解决方案将如何持续几分钟而不是几秒钟?因为你使用 diff 函数。
  • 您可以将数字除以 60 得到秒数,然后执行 number %% 60 得到分钟数。或者,您可以转换为 POSIXct 并从那里格式化,请参阅我更新的答案。
【解决方案2】:

你可以用闭包来做到这一点。闭包允许函数在调用之间保持其状态。

每次timer() 运行时,它都会创建一个新环境并初始化该环境中的时间。然后它创建一个新函数来维护对其创建环境的访问。然后使用&lt;&lt;-操作符将x变量上一层修改,就可以存储每次函数调用的时间。


library(shiny)

timer <- function(){
  x <- Sys.time()
  y <- function(){
    y <- x
    x <<- Sys.time()
    return(x-y)
  }
  return(y)
}

# Implement a simple shiny app with an action button that
# prints the result of running click()
ui <- fluidPage(
  actionButton("do", "Click Me")
)

server <- function(input, output, session) {
  # click is defined within the server function so each
  # session has their own click function with a stored
  # time.
  click <- timer()
  observeEvent(input$do, {print(click())})
}

shinyApp(ui, server)

有关此技术的更多信息,您可以阅读 Hadley Wickham 的 Advanced R: Functional Programming

编辑:如果您想忽略第一次点击/在第一次点击时返回其他内容,您可以执行以下操作:

library(shiny)

timer <- function(){
  x <- NULL
  y <- function(){
    y <- x
    x <<- Sys.time()
    if(is.null(y))
      return("first click")
    return(x-y)
  }
  return(y)
}

# Implement a simple shiny app with an action button that
# prints the result of running click()
ui <- fluidPage(
  actionButton("do", "Click Me")
)

server <- function(input, output, session) {
  # click is defined within the server function so each
  # session has their own click function with a stored
  # time.
  click <- timer()
  observeEvent(input$do, {print(click())})
}

shinyApp(ui, server)

【讨论】:

  • 小菜一碟。
  • 这是一个不错的解决方案。但是,此技术的一个缺点是,如果您将应用程序托管在服务器(或本地)上,并且多个用户共享一个进程,则该技术将不起作用 - 尝试通过在浏览器中复制粘贴 URL 来一次打开两个会话。如果用户 1 点击然后用户 2 点击,您将获得用户 2 的最后一次点击和 user1 的最后一次点击之间的时间间隔,而不是一个用户后续点击之间的时间间隔。这是因为&lt;&lt;-操作符将值推送到全局环境中,由一个进程中的所有用户共享。
  • @Florian 你是对的,当然。我已经编辑了我最初应该提出的答案。使用&lt;&lt;- 运算符的好处是它将值存储在click() 函数的环境中,而不是全局环境中。将click() 的定义放在server 函数中意味着该值应该是“每个会话”。
  • @Eumenedies,我没有想到,这确实是一个简单而干净的解决方案。
  • @Eumenedies,我应该如何忽略您解决方案中的第一次点击?因为我第一次点击时不应该得到答案。
【解决方案3】:

您可以使用包library(tictoc)。使用reactiveVal 并将按钮本身用作计数器。

library(shiny); library(tictoc)
ui <- fluidPage(actionButton("timer", "click me"), textOutput("text"))
server <- function(input, output, session) {
  time = reactiveVal()
  observeEvent(input$timer, handlerExpr = {
    time(capture.output(toc()))
    tic()})
  output$text = renderText({ifelse(is.null(time()), "start!", paste0(time(), " : Time difference between click No", input$timer, " and click No", max(0, input$timer - 1)))})
}
shinyApp(ui, server)

【讨论】:

    猜你喜欢
    • 2014-09-02
    • 2020-10-16
    • 1970-01-01
    • 1970-01-01
    • 2014-02-28
    • 1970-01-01
    • 1970-01-01
    • 2011-06-19
    • 1970-01-01
    相关资源
    最近更新 更多