【问题标题】:R Shiny - saving values of function in data table after action button pressR Shiny - 按下操作按钮后在数据表中保存函数值
【发布时间】:2020-02-20 09:15:44
【问题描述】:

我正在尝试创建一种方法来在 45 分钟内同时跟踪几只动物的呼吸器官(即嘴)的打开和关闭。目标是能够计算每只动物的总开放时间和开放频率。基本上,这个想法是让多个秒表并行运行,同时跟踪每只动物的两个值列表:打开时间和关闭时间。

理想情况下,实验应该是这样的:我开始实验,因此开始秒表。每次动物 1 打开它的呼吸器官时,我按下打开,一旦它关闭它的呼吸器官,我按下关闭。每个人的时间,相对于实验开始时开始的秒表,记录在动物 1 的数据框中。这个过程在 45 分钟内重复 10-15 次。与此同时,另一只动物正在打开和关闭其呼吸器官,并使用一组不同的按钮为动物 2 创建了一个单独的数据框。我希望这可以同时用于多达 10 只动物。

我已经能够使用watch 函数制作秒表(下面的示例代码),以及包含输出文本的操作按钮,这些文本对应于实验开始时间和按下时间之间的系统时间差异打开或关闭按钮。但是,我不确定如何将这些值存储在每个动物的数据框中。

我查看了 stackoverflow 并没有发现任何有用的东西,包括这个线程:r Shiny action button and data table output 和这个: Add values to a reactive table in shiny

如果您需要更多信息,请告诉我!提前致谢。

library(lubridate)
library(shiny)
library(DT)

# stopwatch function ----

stop_watch = function() {
  start_time = stop_time = open_time = close_time = NULL
  start = function() start_time <<- Sys.time()
  stop = function() {
    stop_time <<- Sys.time()
    as.numeric(difftime(stop_time, start_time))
  }
  open = function() {
    open_time <<- Sys.time()
    as.numeric(difftime(open_time, start_time))
  }
  close = function() {
    close_time <<- Sys.time()
    as.numeric(difftime(close_time, start_time))
  }
  list(start=start, open=open, close=close, stop=stop)
}
watch = stop_watch()

# ui ----

ui <- fluidPage(
  titlePanel("Lymnaea stopwatch"),

  sidebarLayout(
    sidebarPanel(

      selectInput(
        "select",
        label = "Number of animals",
        choices = c(1,2,3,4,5,6,7,8,9,10),
        selected = c("1")
      )
  # action button conditionals ----      
    ),
    mainPanel(
      h4("Start/Stop Experiment:"),
      actionButton('start1',"Start"),
      actionButton('stop1', "Stop"),
      textOutput('initial1'),
      textOutput('start1'),
      textOutput('stop1'),
      textOutput('stoptime1'),

     conditionalPanel(
       h4("Animal 1"),
      condition = "input.select == '1'||input.select == '2'||input.select == '3'||input.select == '4'||input.select == '5'||input.select == '6'||input.select == '7'||input.select == '8'||input.select == '9'||input.select == '10'",
       actionButton('open1', "Open"),
       actionButton('close1', "Close"),
       textOutput('open1'),
       textOutput('opentime1'),
       textOutput('close1'),
       textOutput('closetime1'),

     )

  )
)
)

# server ----

server <- function(input, output, session) {

values <- reactiveValues()

values$df <- data.frame(colnames(c("Open", "Close")))

newEntry <- observe({
  if(input$open1 > 0) {
    newLine <- isolate(c(({watch$start()})))
    isolate(values$df <- rbind(values$df, newLine))
  }
})

output$table <- renderTable({values$df})

  # n = 1 animal  ----
  observeEvent(input$start1, {
    watch$start()
    output$initial1 <- renderText(
      "Timer started."
      )
  })

  observeEvent(input$open1, {
    watch$open()
    output$open1 <- renderText(
      "Time of opening:"
    )
    output$opentime1 <- renderText({
      watch$open()
    })
 })

  observeEvent(input$close1, {
    watch$close()
    output$close1 <- renderText({
      "Time of closing:"
    })
    output$closetime1 <- renderText({
      watch$close()
    })
  })

}

shinyApp(ui, server)

【问题讨论】:

  • 那是一个相当大的代码块......你能提供一个减少的问题吗?对于一些人(比如我)来说,这么多代码可能会让人望而生畏,因为理解所有涉及的组件需要更多时间。
  • 将您的示例限制为 2 只动物可能有意义吗?另外,你能澄清一下你在这个应用程序中想要的行为吗?也许举一个具体的例子,描述按事件顺序发生的事情?
  • 嗨,我已经编辑了代码和文本,以更好地描述我的实验和期望的结果。秒表甚至适用于 10 只动物,我只是不确定如何存储来自 watch$openwatch$close 的输出值。
  • ui 末尾缺少括号,无法编辑,因为它没有足够的字符
  • @bretauv 已修复,谢谢!

标签: r shiny


【解决方案1】:

我认为您可以通过多种方式进行不同的设置。

我的一个建议是避免将output 放在您的observers 中。

另一个是只调用一次秒表函数 - 为了数据完整性,以确保您的显示和收集的数据是相同的。

此外,让一个数据表存储您的所有打开和关闭事件可能会有所帮助,另外还有一个用于动物编号的列。使用这样的表格进行未来分析相对容易。

这是一个您可以尝试的简单示例,只是为了了解行为。也请在您的conditionalPanel 之后添加tableOutput('table') 到您的ui 以查看数据框。

# ui ----

ui <- fluidPage(
  titlePanel("Lymnaea stopwatch"),

  sidebarLayout(
    sidebarPanel(

      selectInput(
        "select",
        label = "Number of animals",
        choices = c(1,2,3,4,5,6,7,8,9,10),
        selected = c("1")
      )
      # action button conditionals ----      
    ),
    mainPanel(
      h4("Start/Stop Experiment:"),
      actionButton('start1',"Start"),
      actionButton('stop1', "Stop"),
      textOutput('initial1'),
      textOutput('start1'),
      textOutput('stop1'),
      textOutput('stoptime1'),

      conditionalPanel(
        h4("Animal 1"),
        condition = "input.select == '1'||input.select == '2'||input.select == '3'||input.select == '4'||input.select == '5'||input.select == '6'||input.select == '7'||input.select == '8'||input.select == '9'||input.select == '10'",
        actionButton('open1', "Open"),
        actionButton('close1', "Close"),
        textOutput('open1'),
        textOutput('opentime1'),
        textOutput('close1'),
        textOutput('closetime1'),
      ),
      tableOutput('table')
    )
  )
)

# server ----

server <- function(input, output, session) {

  values <- reactiveValues(df = data.frame(Animal = integer(),
                                           Event = character(),
                                           Time = as.POSIXct(character()),
                                           stringsAsFactors = FALSE),
                           timer = "Timer Off")

  output$initial1 <- renderText({
    values$timer
  })

  output$opentime1 <- renderText({
    paste("Opened at:", tail(values$df[values$df[["Animal"]] == 1 & values$df[["Event"]] == "Open", "Time"], 1))
  })

  output$closetime1 <- renderText({
    paste("Closed at:", tail(values$df[values$df[["Animal"]] == 1 & values$df[["Event"]] == "Close", "Time"], 1))
  })

  output$table <- renderTable({
    values$df
  })

  observeEvent(input$start1, {
    watch$start()
    values$timer <- "Timer Started"
  })

  observeEvent(input$open1, {
    values$df <- rbind(values$df, data.frame(Animal = 1, Event = "Open", Time = watch$open()))
  })

  observeEvent(input$close1, {
    values$df <- rbind(values$df, data.frame(Animal = 1, Event = "Close", Time = watch$close()))
  })

}

这可以扩大到 10 只动物,还有其他方法可以向用户提供数据反馈。

让我知道你的想法,如果这符合你的想法。

【讨论】:

  • 非常感谢!这正是我的想法。我刚刚尝试缩放到 2 只动物并且效果很好。如果它在实验环境中有效,我会告诉你的!
  • 很高兴听到!仅供参考 - 当您扩大规模时,您可能需要考虑一种动态方法来创建按钮和观察者,例如 this example。这将是一种更 DRY 的方法,更灵活,效率更高,因此您无需将所有 server outputobserveEvent 复制 10 次。只是一个想法。
猜你喜欢
  • 2018-01-26
  • 2021-02-10
  • 1970-01-01
  • 2019-10-18
  • 1970-01-01
  • 2019-04-07
  • 1970-01-01
  • 2021-06-22
  • 2020-01-03
相关资源
最近更新 更多