【问题标题】:R Shiny: how to change stored data?R Shiny:如何更改存储的数据?
【发布时间】:2017-11-23 21:38:05
【问题描述】:

我为体育博彩编写了一个闪亮的应用程序,使我能够

  1. 运行模型并挑选获胜者,
  2. 如果我决定投注游戏并将其存储在数据库中,请添加其他变量,并且
  3. 使用这些信息跟踪我的投注表现并调整策略。

到目前为止,该应用程序运行良好,但有一个主要缺陷:当我进行计算并决定对游戏下注时,我可以使用提交按钮简单地将另一行添加到数据库中。问题是我有两个重要的数据分析栏,只能在游戏后添加。因此,我需要在比赛前提交的一行中添加或更改信息。

我在 Dean Attali 的 this 输入上构建了我的应用程序的数据存储部分,因此我还使用了本教程中的最小示例(顺便感谢 @Dean)。这是没有存储的基本应用程序,但我想重要的是回到已经存在的行并更改(或扩展)它们。有没有人已经做过类似的事情或知道如何解决这个问题?

更新:我在这里找到了解决问题的方法enter link description here(在底部 - 3 月 15 日)。我试图实现它,但表格中没有反应,因为我显然错过了一个重要的点。有谁知道如何让表格做出响应?

library(shiny)
library(DT)
devtools::install_github('rstudio/DT@feature/editor')

saveData <- function(data) {
  data <- as.data.frame(t(data))
  if (exists("responses")) {
    responses <<- rbind(responses, data)
  } else {
    responses <<- data
  }
}

loadData <- function() {
  if (exists("responses")) {
    responses
  }
}

# Define the fields we want to save from the form
fields <- c("name", "used_shiny", "r_num_years")

# Shiny app with 3 fields that the user can submit data for
shinyApp(
  ui = fluidPage(
    DT::dataTableOutput("responses", width = 300), tags$hr(),
    textInput("name", "Name", ""),
    checkboxInput("used_shiny", "I've built a Shiny app in R before", FALSE),
    sliderInput("r_num_years", "Number of years using R",
            0, 25, 2, ticks = FALSE),
    actionButton("submit", "Submit")
  ),
  server = function(input, output, session) {

# Whenever a field is filled, aggregate all form data
formData <- reactive({
  data <- sapply(fields, function(x) input[[x]])
  data
})

# When the Submit button is clicked, save the form data
observeEvent(input$submit, {
  saveData(formData())
})

# Show the previous responses
# (update with current response when Submit is clicked)
output$responses <- DT::renderDataTable({
  input$submit
  loadData() %>%
    datatable(rownames = FALSE)
    })

  proxy <- dataTableProxy("x1")

  observeEvent(input$x1_cell_edit, {
  info <- input$x1_cell_edit
  i <- info$row
  j <- info$col + 1
  v <- info$value
  loadData[i, j] <<- DT:::coerceValue(v, loadData[i, j])
  replaceData(proxy, loadData, resetPaging = FALSE, rownames = FALSE)
})     
  }
)

【问题讨论】:

  • responses 是一个可以从任何地方操作的全局变量。您可以编写像saveData 这样的函数来更改它并调用它吗?我不认为我完全理解这里的问题。您能否提供您正在寻找的具体示例?
  • 使用我上面发布的示例,您如何返回已提交的行并更改应用程序中的值?假设您使用 R 插入了错误的年数?最用户友好的方法是单击该行并更改某个字段。这可能吗?
  • 我知道 DataTables 有一些实时编辑扩展,但 DT 没有这些扩展。您可以查看jrowen.github.io/rhandsontable 或谷歌搜索实时表格编辑器
  • 感谢您的提示。我找到了使用DT 编辑表格的解决方案(参见上面的更新)。任何想法如何解决这个问题?
  • 您遇到了一些复制粘贴问题 - x1 是该链接中示例中的表名称

标签: r database shiny load storage


【解决方案1】:

我在使用 DT live editor 的更新示例中修复了一些问题:

  • 添加了 getDataValuesetDataValue 函数来读取/操作数据框中的单个条目
  • responses 替换了x1 的实例(来自GitHub 上的示例代码的表名)
  • sapply 中添加了simplify = FALSE,因此它返回一个列表而不是一个向量。这样添加到表中的数据可以是不同类型的。 R中的向量只有一种类型,所以所有的表数据都被转换为字符串,甚至TRUE/FALSE
# devtools::install_github('rstudio/DT@feature/editor')
library(shiny)
library(DT)

saveData <- function(data) {
  if (exists("responses")) {
    responses <<- rbind(responses, data)
  } else {
    responses <<- data.frame(data, stringsAsFactors = FALSE)
  }
}

loadData <- function() {
  if (exists("responses")) {
    responses
  }
}

getDataValue <- function(i, j) {
  stopifnot(exists("responses"))
  responses[i, j]
}

setDataValue <- function(i, j, value) {
  stopifnot(exists("responses"))
  responses[i, j] <<- value
  responses
}

# Define the fields we want to save from the form
fields <- c("name", "used_shiny", "r_num_years")

# Shiny app with 3 fields that the user can submit data for
shinyApp(
  ui = fluidPage(
    DT::dataTableOutput("responses", width = 300), tags$hr(),
    textInput("name", "Name", ""),
    checkboxInput("used_shiny", "I've built a Shiny app in R before", FALSE),
    sliderInput("r_num_years", "Number of years using R",
                0, 25, 2, ticks = FALSE),
    actionButton("submit", "Submit")
  ),
  server = function(input, output, session) {

    # Whenever a field is filled, aggregate all form data
    formData <- reactive({
      data <- sapply(fields, function(x) input[[x]], simplify = FALSE)
      data
    })

    # Show the previous responses
    # (update with current response when Submit is clicked)
    output$responses <- DT::renderDataTable({
      req(input$submit)
      newData <- isolate(formData())
      saveData(newData)
      datatable(loadData(), rownames = FALSE)
    })

    proxy <- dataTableProxy("responses")

    observeEvent(input$responses_cell_edit, {
      info <- input$responses_cell_edit
      i <- info$row
      j <- info$col + 1
      v <- info$value

      newValue <- DT:::coerceValue(v, getDataValue(i, j))
      setDataValue(i, j, newValue)
      DT::replaceData(proxy, loadData(), resetPaging = FALSE, rownames = FALSE)
    })
  }
)

【讨论】:

  • 感谢@greg 的更新。 x1 是有意使用的,因为在示例中也是这样做的,以便创建一个代理变量,然后覆盖实际值(至少这是我的想法)。无论如何,我从你那里得到了更正的例子,行为很奇怪。当我提交几行时,无论我在文本字段或其他输入中写什么,它总是相同的信息。此外,只能操作第一行,然后自动将所有行更改为相同的值。你能在你的机器上重现这个吗?
  • 我用“工作”示例更新了帖子。 rbinding 列表转换为 data.frames 时发生了一些奇怪的事情。 - 不完全确定为什么,但我稍后会调查。更新后的示例rbinds 添加了数据而不转换为 data.frame。此外,数据保存和数据呈现都取决于单击的提交按钮。这导致了在保存数据之前渲染数据的问题,因此我将所有内容都移到了 renderDataTable 中。这很糟糕,所以我建议将 responses 设为响应值。
  • 感谢您的更新。 req(input$submit)-函数会产生问题,因为它会阻止在启动应用程序时显示以前的条目。另一方面,只有input$submit 会导致这样一种情况,即每次启动或更新应用程序时都会添加空行name 和值FALSE2。你有什么解决办法吗? renderDataTable-function 中也包含保存是否有问题?
  • 嗨,你有没有找到解决 req(input$submit) 问题的方法?如果是,我会很感兴趣
猜你喜欢
  • 2021-09-01
  • 2021-01-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多