如何根据用户在R Shiny中的数据表中输入的内容更新eval()计算?

huangapple go评论131阅读模式
英文:

How do I update an eval() calculation based on user inputs into a data table in R Shiny?

问题

我有一个应用程序,用户可以从下拉列表中选择一个方程式。该应用程序从表格中提取输入到方程式中的所有变量,将这些变量插入方程式中,并提供结果。然而,我希望用户能够覆盖任何值,并查看计算结果的变化。计算是通过使用eval和变量列表来实现的,因此我怀疑我尝试的是在用户更新表格值时更改环境中变量的值,但我也愿意尝试其他方法!请参见下面提供的屏幕截图和示例。

我能够获得文本框,用户可以在其中输入变量的值。(小小的胜利!)我尝试使用代理表格来实现重新计算,但问题是我没有找到一个同时包含代理表格和动态输入字段的示例。

我找到的许多示例都以mod_df <- shiny::reactiveValues(x = df)(或类似的代码)开头。当我尝试复制代码时,出现以下错误:

You tried to do something that can only be done from inside a reactive consumer.

示例代码:

  1. library(shiny)
  2. library(DT)
  3. require(stringr)
  4. df1 = data.frame("ID" = c(1:3), "Equation" = c("<A> * <B> + <C>", "<A> + <B> + <C>", "<A> - <B> + <C>"))
  5. df2 = data.frame("Equation" = c(1, 1, 1, 2, 2, 2, 3, 3, 3),
  6. "Variable" = c("A", "B", "C", "A", "B", "C", "A", "B", "C"),
  7. "Value" = c(5,3,10,2,4,NA,7,5,NA))
  8. df3 = data.frame("Premise" = c("Red", "Yellow", "Green"),
  9. "Value" = c(5,4,3))
  10. ui <- fluidPage(
  11. selectizeInput("df1Select", "Select Equation", choices = df1$Equation, multiple = TRUE, options = list(maxItems = 1)),
  12. h3("This is the static table of the variables as defined"),
  13. dataTableOutput("StaticTable"),
  14. br(),
  15. htmlOutput("CalcResultStatic"),
  16. h3("Here, I want to be able to manipulate the fields and recalculate the results"),
  17. dataTableOutput("InteractiveTable"),
  18. br(),
  19. htmlOutput("CalcResultInteractive"))
  20. server <- function(input, output, session) {
  21. ### Filter Data
  22. StaticTableFiltered = reactive({
  23. EqSelect = if(is.null(input$df1Select)) unique(as.vector(df1$ID)) else df1$ID[df1$Equation == input$df1Select]
  24. filter(df2, Equation %in% EqSelect)})
  25. ### Render Static Table
  26. output$StaticTable = renderDataTable({
  27. if(is.null(input$df1Select)) return(NULL) else {StaticTableFiltered()}},
  28. options = list(dom = 't'), selection = "none")
  29. ### Render Static Result as Text
  30. CalculateResultStatic = reactive({
  31. if(is.null(input$df1Select)) return(NULL) else {
  32. ### Define algorithm
  33. CalcEq = paste(input$df1Select)
  34. ### Make list of input variables
  35. Variables = as.data.frame(str_extract_all(input$df1Select, "<(.*?)>"))
  36. colnames(Variables)[1] = "Vars"
  37. ### Remove < > from algorithm and assumptions
  38. CalcEq = gsub("<","",gsub(">","",CalcEq))
  39. Variables$Vars = gsub("<","",gsub(">","",Variables$Vars))
  40. ### Get values from Assumptions table
  41. Variables = merge(Variables, df2[df2$Equation == df1$ID[df1$Equation == input$df1Select],], by.x = "Vars", by.y = "Variable", all.x = TRUE, all.y = FALSE)
  42. ### Convert variables to list
  43. Variables.List = as.list(Variables$Value)
  44. names(Variables.List) = Variables$Vars
  45. ### Evaluate equation on list
  46. eval(str2lang(CalcEq), envir = Variables.List)}})
  47. output$CalcResultStatic = renderUI(HTML(paste("<b>",CalculateResultStatic(), sep = "")))
  48. ### Render Interactive Table
  49. output$InteractiveTable = renderDataTable({
  50. if(is.null(input$df1Select)) return(NULL) else {
  51. data = data.frame(StaticTableFiltered(),
  52. UserValue = sapply(1:nrow(StaticTableFiltered()), function(i) {sprintf('<input id="text" type="text" class="form-control" value=""/>', i)}))}},
  53. selection = "none", escape = FALSE,
  54. options =
  55. list(
  56. preDrawCallback = JS('function() { Shiny.unbindAll(this.api().table().node()); }'),
  57. drawCallback = JS('function() { Shiny.bindAll(this.api().table().node()); } '),
  58. dom = 't',
  59. processing = FALSE))
  60. ### Render Interactive Result as Text
  61. CalculateResultInteractive = reactive({
  62. if(is.null(input$df1Select)) return(NULL) else {
  63. ### Define algorithm
  64. CalcEq = paste(input$df1Select)
  65. ### Make list of input variables
  66. Variables = as.data.frame(str_extract_all(input$df1Select, "<(.*?)>"))
  67. colnames(Variables)[1] = "Vars"
  68. ### Remove < > from algorithm and assumptions
  69. CalcEq = gsub("<","",gsub(">","",CalcEq))
  70. Variables$Vars = gsub("<","",gsub(">","",Variables$Vars))
  71. ### Get values from Assumptions table
  72. Variables = merge(Variables, df2[df2$Equation == df1$ID[df1$Equation == input$df1Select],], by.x = "Vars", by.y = "Variable", all.x = TRUE, all.y = FALSE)
  73. ### Convert variables to list
  74. Variables.List = as.list(Variables$Value)
  75. names(Variables.List) = Variables$Vars
  76. ### Evaluate equation on list
  77. eval(str2lang(CalcEq), envir = Variables.List)}})
  78. output$CalcResultInteractive = renderUI(HTML(paste("<b>",CalculateResultInteractive(), sep = "")))
  79. }
  80. shinyApp(ui = ui, server = server)

此外,如果您尝试运行示例代码,您会发现有些方程式需要查找值。我还想创建一个列来实现查找,但我想先从只有文本字段开始,看看那里得到的帮助是否能指导我正确地完成下一步。

非常感谢您的帮助!

英文:

I have an app where a user selects an equation from a drop down list. The app pulls all the variables that get input into the equation from a table, plugs the variables into the equation, and provides the result. However, I want a user to be able to override any of the values and see how the calculation is affected. The calculation is facilitated using eval and a list of variables, so I suspect what I'm trying to do is change the value of the variable in the environment when a user updates a table value, but I'm open to other ideas! See screenshot and reprex provided below.

如何根据用户在R Shiny中的数据表中输入的内容更新eval()计算?

I am able to get the text box where a user can input their own values for the variables. (Small victory!) I tried using a proxy table to facilitate the recalculation, but the problem is I haven't found an example where there is a proxy table and a dynamic input field in the table.

Many of the examples I found start with mod_df &lt;- shiny::reactiveValues(x = df) (or something similar). When I try to replicate the code, I get the following error:

You tried to do something that can only be done from inside a reactive consumer.

Reprex:

  1. library(shiny)
  2. library(DT)
  3. require(stringr)
  4. df1 = data.frame(&quot;ID&quot; = c(1:3), &quot;Equation&quot; = c(&quot;&lt;A&gt; * &lt;B&gt; + &lt;C&gt;&quot;, &quot;&lt;A&gt; + &lt;B&gt; + &lt;C&gt;&quot;, &quot;&lt;A&gt; - &lt;B&gt; + &lt;C&gt;&quot;))
  5. df2 = data.frame(&quot;Equation&quot; = c(1, 1, 1, 2, 2, 2, 3, 3, 3),
  6. &quot;Variable&quot; = c(&quot;A&quot;, &quot;B&quot;, &quot;C&quot;, &quot;A&quot;, &quot;B&quot;, &quot;C&quot;, &quot;A&quot;, &quot;B&quot;, &quot;C&quot;),
  7. &quot;Value&quot; = c(5,3,10,2,4,NA,7,5,NA))
  8. df3 = data.frame(&quot;Premise&quot; = c(&quot;Red&quot;, &quot;Yellow&quot;, &quot;Green&quot;),
  9. &quot;Value&quot; = c(5,4,3))
  10. ui &lt;- fluidPage(
  11. selectizeInput(&quot;df1Select&quot;, &quot;Select Equation&quot;, choices = df1$Equation, multiple = TRUE, options = list(maxItems = 1)),
  12. h3(&quot;This is the static table of the variables as defined&quot;),
  13. dataTableOutput(&quot;StaticTable&quot;),
  14. br(),
  15. htmlOutput(&quot;CalcResultStatic&quot;),
  16. h3(&quot;Here, I want to be able to manipulate the fields and recalculate the results&quot;),
  17. dataTableOutput(&quot;InteractiveTable&quot;),
  18. br(),
  19. htmlOutput(&quot;CalcResultInteractive&quot;))
  20. server &lt;- function(input, output, session) {
  21. ### Filter Data
  22. StaticTableFiltered = reactive({
  23. EqSelect = if(is.null(input$df1Select)) unique(as.vector(df1$ID)) else df1$ID[df1$Equation == input$df1Select]
  24. filter(df2, Equation %in% EqSelect)})
  25. ### Render Static Table
  26. output$StaticTable = renderDataTable({
  27. if(is.null(input$df1Select)) return(NULL) else {StaticTableFiltered()}},
  28. options = list(dom = &#39;t&#39;), selection = &quot;none&quot;)
  29. ### Render Static Result as Text
  30. CalculateResultStatic = reactive({
  31. if(is.null(input$df1Select)) return(NULL) else {
  32. ### Define algorithm
  33. CalcEq = paste(input$df1Select)
  34. ### Make list of input variables
  35. Variables = as.data.frame(str_extract_all(input$df1Select, &quot;&lt;(.*?)&gt;&quot;))
  36. colnames(Variables)[1] = &quot;Vars&quot;
  37. ### Remove &lt; &gt; from algorithm and assumptions
  38. CalcEq = gsub(&quot;&lt;&quot;,&quot;&quot;,gsub(&quot;&gt;&quot;,&quot;&quot;,CalcEq))
  39. Variables$Vars = gsub(&quot;&lt;&quot;,&quot;&quot;,gsub(&quot;&gt;&quot;,&quot;&quot;,Variables$Vars))
  40. ### Get values from Assumptions table
  41. Variables = merge(Variables, df2[df2$Equation == df1$ID[df1$Equation == input$df1Select],], by.x = &quot;Vars&quot;, by.y = &quot;Variable&quot;, all.x = TRUE, all.y = FALSE)
  42. ### Convert variables to list
  43. Variables.List = as.list(Variables$Value)
  44. names(Variables.List) = Variables$Vars
  45. ### Evaluate equation on list
  46. eval(str2lang(CalcEq), envir = Variables.List)}})
  47. output$CalcResultStatic = renderUI(HTML(paste(&quot;&lt;b&gt;&quot;,CalculateResultStatic(), sep = &quot;&quot;)))
  48. ### Render Interactive Table
  49. output$InteractiveTable = renderDataTable({
  50. if(is.null(input$df1Select)) return(NULL) else {
  51. data = data.frame(StaticTableFiltered(),
  52. UserValue = sapply(1:nrow(StaticTableFiltered()), function(i) {sprintf(&#39;&lt;input id=&quot;text&quot; type=&quot;text&quot; class=&quot;form-control&quot; value=&quot;&quot;/&gt;&#39;, i)}))}},
  53. selection = &quot;none&quot;, escape = FALSE,
  54. options =
  55. list(
  56. preDrawCallback = JS(&#39;function() { Shiny.unbindAll(this.api().table().node()); }&#39;),
  57. drawCallback = JS(&#39;function() { Shiny.bindAll(this.api().table().node()); } &#39;),
  58. dom = &#39;t&#39;,
  59. processing = FALSE))
  60. ### Render Interactive Result as Text
  61. CalculateResultInteractive = reactive({
  62. if(is.null(input$df1Select)) return(NULL) else {
  63. ### Define algorithm
  64. CalcEq = paste(input$df1Select)
  65. ### Make list of input variables
  66. Variables = as.data.frame(str_extract_all(input$df1Select, &quot;&lt;(.*?)&gt;&quot;))
  67. colnames(Variables)[1] = &quot;Vars&quot;
  68. ### Remove &lt; &gt; from algorithm and assumptions
  69. CalcEq = gsub(&quot;&lt;&quot;,&quot;&quot;,gsub(&quot;&gt;&quot;,&quot;&quot;,CalcEq))
  70. Variables$Vars = gsub(&quot;&lt;&quot;,&quot;&quot;,gsub(&quot;&gt;&quot;,&quot;&quot;,Variables$Vars))
  71. ### Get values from Assumptions table
  72. Variables = merge(Variables, df2[df2$Equation == df1$ID[df1$Equation == input$df1Select],], by.x = &quot;Vars&quot;, by.y = &quot;Variable&quot;, all.x = TRUE, all.y = FALSE)
  73. ### Convert variables to list
  74. Variables.List = as.list(Variables$Value)
  75. names(Variables.List) = Variables$Vars
  76. ### Evaluate equation on list
  77. eval(str2lang(CalcEq), envir = Variables.List)}})
  78. output$CalcResultInteractive = renderUI(HTML(paste(&quot;&lt;b&gt;&quot;,CalculateResultInteractive(), sep = &quot;&quot;)))
  79. }
  80. shinyApp(ui = ui, server = server)

In addition, if you play with the reprex, you'll see some equations require a value to be looked up. I also wanted to create a column to facilitate the lookup, but I thought let's start with just the text field and see if the help I get there guides me in the right direction to do the next piece myself.

Thanks in advance for any help!

答案1

得分: 1

我建议将方程式存储为数据框列中的实际 R 函数。标签应该是一个单独的列。

使用 selectInputchoices 参数选择方程式,其中 choices 是一个命名列表。名称是标签,值是实际函数。它们来自我刚提到的数据框。当选择新方程式时,观察者会使用初始值更新 numericInput

在 Shiny 中,用户可编辑的数据表格(不仅仅是 DT)很麻烦。我建议为所需的每个变量使用 numericInput。在下面的示例中,我在 UI 中硬编码了三个 numericInput,但如果需要的话,你可以动态创建/销毁或显示/隐藏。这在一定程度上取决于你是否需要任意多个或任意命名的变量,或者是否有一小组可重复使用的变量。

下面的服务器函数在变量名称方面基本上是动态的。

  1. library(tidyverse)
  2. library(shiny)
  3. eqn_df <- tibble(
  4. id = 1:3,
  5. label = c("<A> * <B> + <C>", "<A> + <B> + <C>", "<A> - <B> + <C>"),
  6. func = list(
  7. \(A,B,C) A*B+C,
  8. \(A,B,C) A+B+C,
  9. \(A,B,C) A-B+C
  10. )
  11. )
  12. values_df <- tibble(
  13. id = c(1, 1, 1, 2, 2, 2, 3, 3, 3),
  14. var = c("A", "B", "C", "A", "B", "C", "A", "B", "C"),
  15. value = c(5,3,10,2,4,NA,7,5,NA)
  16. )
  17. ui <- fluidPage(
  18. selectInput("eqn", "Select Equation", choices = set_names(eqn_df$id, eqn_df$label)),
  19. numericInput("var_A", "Choose A", 0),
  20. numericInput("var_B", "Choose B", 0),
  21. numericInput("var_C", "Choose C", 0),
  22. textOutput("result")
  23. )
  24. server <- function(input, output, session) {
  25. observe({
  26. values_df |>
  27. filter(id == input$eqn) |>
  28. transmute(inputId = paste0("var_", var),
  29. value) |>
  30. pwalk(updateNumericInput)
  31. }) |> bindEvent(input$eqn)
  32. output$result <- renderText({
  33. req(input$var_A, input$var_B, input$var_C)
  34. func <- eqn_df |>
  35. filter(id == input$eqn) |>
  36. pull(func) |>
  37. nth(1)
  38. helper <- tibble(id = str_subset(names(input), "var_"),
  39. var = str_sub(id, 5))
  40. args <- map_int(helper$id, ~input[[.x]]) |>
  41. set_names(helper$var) |>
  42. as.list()
  43. do.call(func, args)
  44. })
  45. }
  46. shinyApp(ui, server)
英文:

I suggest storing the equations as actual R functions in a data frame column. The label should be a separate column.

Equations are chosen using a selectInput with choices given by a named list. The names are the labels and the values are the actual functions. They come from the data frame I just mentioned. When a new equation is chosen, an observer updates the numericInputs with the initial values.

User editable data tables (not just DT) are painful in Shiny. I suggest using numericInputs for each of your needed variables. In the example below I have hard-coded three numericInput in the UI, but you could dynamically create/destroy or show/hide if needed. It partly depends on whether you need arbitrarily many or arbitrarily named variables, or if you have a small set of re-used variables.

The server function below is basically dynamic in terms of variable names.

  1. library(tidyverse)
  2. library(shiny)
  3. eqn_df &lt;- tibble(
  4. id = 1:3,
  5. label = c(&quot;&lt;A&gt; * &lt;B&gt; + &lt;C&gt;&quot;, &quot;&lt;A&gt; + &lt;B&gt; + &lt;C&gt;&quot;, &quot;&lt;A&gt; - &lt;B&gt; + &lt;C&gt;&quot;),
  6. func = list(
  7. \(A,B,C) A*B+C,
  8. \(A,B,C) A+B+C,
  9. \(A,B,C) A-B+C
  10. )
  11. )
  12. values_df &lt;- tibble(
  13. id = c(1, 1, 1, 2, 2, 2, 3, 3, 3),
  14. var = c(&quot;A&quot;, &quot;B&quot;, &quot;C&quot;, &quot;A&quot;, &quot;B&quot;, &quot;C&quot;, &quot;A&quot;, &quot;B&quot;, &quot;C&quot;),
  15. value = c(5,3,10,2,4,NA,7,5,NA)
  16. )
  17. ui &lt;- fluidPage(
  18. selectInput(&quot;eqn&quot;, &quot;Select Equation&quot;, choices = set_names(eqn_df$id, eqn_df$label)),
  19. numericInput(&quot;var_A&quot;, &quot;Choose A&quot;, 0),
  20. numericInput(&quot;var_B&quot;, &quot;Choose B&quot;, 0),
  21. numericInput(&quot;var_C&quot;, &quot;Choose C&quot;, 0),
  22. textOutput(&quot;result&quot;)
  23. )
  24. server &lt;- function(input, output, session) {
  25. observe({
  26. values_df |&gt;
  27. filter(id == input$eqn) |&gt;
  28. transmute(inputId = paste0(&quot;var_&quot;, var),
  29. value) |&gt;
  30. pwalk(updateNumericInput)
  31. }) |&gt; bindEvent(input$eqn)
  32. output$result &lt;- renderText({
  33. req(input$var_A, input$var_B, input$var_C)
  34. func &lt;- eqn_df |&gt;
  35. filter(id == input$eqn) |&gt;
  36. pull(func) |&gt;
  37. nth(1)
  38. helper &lt;- tibble(id = str_subset(names(input), &quot;var_&quot;),
  39. var = str_sub(id, 5))
  40. args &lt;- map_int(helper$id, ~input[[.x]]) |&gt;
  41. set_names(helper$var) |&gt;
  42. as.list()
  43. do.call(func, args)
  44. })
  45. }
  46. shinyApp(ui, server)

答案2

得分: 0

你是否需要将“UserValue”列作为输入?

如果不需要,这是一个快速而简单的方法,可以帮助你开始实现你想要的功能。在不重写太多应用程序的情况下,我将InteractiveTable设置为可编辑。

在下面的示例中,技术上所有单元格都是可编辑的,但你可以将其更改为仅指定“User_Value”列。

双击该列中的单元格后,你可以添加一个新值,该值可以通过input$InteractiveTable_cell_edit检索。然后,你可以使用新值更新表格并进行计算。

这部分代码如下所示:

  1. # Update the DT with the new user entered value
  2. if(!is.null(input$InteractiveTable_cell_edit)) {
  3. new_data = input$InteractiveTable_cell_edit
  4. df2[new_data$row, new_data$col] = as.integer(new_data$value)
  5. }

示例代码如下:

  1. library(shiny)
  2. library(DT)
  3. library(stringr)
  4. library(dplyr)
  5. df1 = data.frame("ID" = c(1:3), "Equation" = c("<A> * <B> + <C>", "<A> + <B> + <C>", "<A> - <B> + <C>"))
  6. df2 = data.frame("Equation" = c(1, 1, 1, 2, 2, 2, 3, 3, 3),
  7. "Variable" = c("A", "B", "C", "A", "B", "C", "A", "B", "C"),
  8. "Value" = c(5,3,10,2,4,NA,7,5,NA))
  9. df3 = data.frame("Premise" = c("Red", "Yellow", "Green"),
  10. "Value" = c(5,4,3))
  11. ui <- fluidPage(
  12. selectizeInput("df1Select", "Select Equation", choices = df1$Equation, multiple = TRUE, options = list(maxItems = 1)),
  13. h3("This is the static table of the variables as defined"),
  14. dataTableOutput("StaticTable"),
  15. br(),
  16. htmlOutput("CalcResultStatic"),
  17. h3("Here, I want to be able to manipulate the fields and recalculate the results"),
  18. dataTableOutput("InteractiveTable"),
  19. br(),
  20. htmlOutput("CalcResultInteractive"))
  21. server <- function(input, output, session) {
  22. ### Filter Data
  23. StaticTableFiltered = reactive({
  24. EqSelect = if(is.null(input$df1Select)) unique(as.vector(df1$ID)) else df1$ID[df1$Equation == input$df1Select]
  25. filter(df2, Equation %in% EqSelect)})
  26. ### Render Static Table
  27. output$StaticTable = renderDataTable({
  28. if(is.null(input$df1Select)) return(NULL) else {StaticTableFiltered()}},
  29. options = list(dom = 't'), selection = "none")
  30. ### Render Static Result as Text
  31. CalculateResultStatic = reactive({
  32. if(is.null(input$df1Select)) return(NULL) else {
  33. ### Define algorithm
  34. CalcEq = paste(input$df1Select)
  35. ### Make list of input variables
  36. Variables = as.data.frame(str_extract_all(input$df1Select, "<(.*?)>"))
  37. colnames(Variables)[1] = "Vars"
  38. ### Remove < > from algorithm and assumptions
  39. CalcEq = gsub("<","",gsub(">","",CalcEq))
  40. Variables$Vars = gsub("<","",gsub(">","",Variables$Vars))
  41. ### Get values from Assumptions table
  42. Variables = merge(Variables, df2[df2$Equation == df1$ID[df1$Equation == input$df1Select],], by.x = "Vars", by.y = "Variable", all.x = TRUE, all.y = FALSE)
  43. ### Convert variables to list
  44. Variables.List = as.list(Variables$Value)
  45. names(Variables.List) = Variables$Vars
  46. ### Evaluate equation on list
  47. eval(str2lang(CalcEq), envir = Variables.List)}})
  48. output$CalcResultStatic = renderUI(HTML(paste("<b>",CalculateResultStatic(), sep = "")))
  49. ### Render Interactive Table
  50. output$InteractiveTable = renderDataTable({
  51. if(is.null(input$df1Select)) return(NULL) else {
  52. data = StaticTableFiltered() %>%
  53. rename(User_Value = Value)
  54. }
  55. },
  56. selection = "none", escape = FALSE, editable = TRUE, # make dt editable
  57. options =
  58. list(
  59. preDrawCallback = JS('function() { Shiny.unbindAll(this.api().table().node()); }'),
  60. drawCallback = JS('function() { Shiny.bindAll(this.api().table().node()); } '),
  61. dom = 't',
  62. processing = FALSE))
  63. ### Render Interactive Result as Text
  64. CalculateResultInteractive = reactive({
  65. if(is.null(input$df1Select)) return(NULL) else {
  66. ### Define algorithm
  67. CalcEq = paste(input$df1Select)
  68. ### Make list of input variables
  69. Variables = as.data.frame(str_extract_all(input$df1Select, "<(.*?)>"))
  70. colnames(Variables)[1] = "Vars"
  71. ### Remove < > from algorithm and assumptions
  72. CalcEq = gsub("<","",gsub(">","",CalcEq))
  73. Variables$Vars = gsub("<","",gsub(">","",Variables$Vars))
  74. # Update the DT with the new user entered value
  75. if(!is.null(input$InteractiveTable_cell_edit)) {
  76. new_data = input$InteractiveTable_cell_edit
  77. df2[new_data$row, new_data$col] = as.integer(new_data$value)
  78. }
  79. ### Get values from Assumptions table
  80. Variables = merge(Variables, df2[df2$Equation == df1$ID[df1$Equation == input$df1Select],], by.x = "Vars", by.y = "Variable", all.x = TRUE, all.y = FALSE)
  81. ### Convert variables to list
  82. Variables.List = as.list(Variables$Value)
  83. names(Variables.List) = Variables$Vars
  84. ### Evaluate equation on list
  85. eval(str2lang(CalcEq), envir = Variables.List)}})
  86. output$CalcResultInteractive = renderUI(HTML(paste("<b>",CalculateResultInteractive(), sep = "")))
  87. }
  88. shinyApp(ui = ui, server = server)
英文:

Do you require the "UserValue" column to be an input?

If not, here's quick and dirty way to give you a jump start to what you want. Without re-writing too much of the app - I've set the InteractiveTable to be editable.

In the example below, technically all cells are editable but you can change that to only specify the "User_Value" column.

Upon double clicking the cell in that column, you can add a new value which can be retrieved by input$InteractiveTable_cell_edit. Then you can update the table with the new value and perform you calcs.

That portion is performed here:

  1. # Update the DT with the new user entered value
  2. if(!is.null(input$InteractiveTable_cell_edit)) {
  3. new_data = input$InteractiveTable_cell_edit
  4. df2[new_data$row, new_data$col] = as.integer(new_data$value)
  5. }

Ex:

  1. library(shiny)
  2. library(DT)
  3. library(stringr)
  4. library(dplyr)
  5. df1 = data.frame(&quot;ID&quot; = c(1:3), &quot;Equation&quot; = c(&quot;&lt;A&gt; * &lt;B&gt; + &lt;C&gt;&quot;, &quot;&lt;A&gt; + &lt;B&gt; + &lt;C&gt;&quot;, &quot;&lt;A&gt; - &lt;B&gt; + &lt;C&gt;&quot;))
  6. df2 = data.frame(&quot;Equation&quot; = c(1, 1, 1, 2, 2, 2, 3, 3, 3),
  7. &quot;Variable&quot; = c(&quot;A&quot;, &quot;B&quot;, &quot;C&quot;, &quot;A&quot;, &quot;B&quot;, &quot;C&quot;, &quot;A&quot;, &quot;B&quot;, &quot;C&quot;),
  8. &quot;Value&quot; = c(5,3,10,2,4,NA,7,5,NA))
  9. df3 = data.frame(&quot;Premise&quot; = c(&quot;Red&quot;, &quot;Yellow&quot;, &quot;Green&quot;),
  10. &quot;Value&quot; = c(5,4,3))
  11. ui &lt;- fluidPage(
  12. selectizeInput(&quot;df1Select&quot;, &quot;Select Equation&quot;, choices = df1$Equation, multiple = TRUE, options = list(maxItems = 1)),
  13. h3(&quot;This is the static table of the variables as defined&quot;),
  14. dataTableOutput(&quot;StaticTable&quot;),
  15. br(),
  16. htmlOutput(&quot;CalcResultStatic&quot;),
  17. h3(&quot;Here, I want to be able to manipulate the fields and recalculate the results&quot;),
  18. dataTableOutput(&quot;InteractiveTable&quot;),
  19. br(),
  20. htmlOutput(&quot;CalcResultInteractive&quot;))
  21. server &lt;- function(input, output, session) {
  22. ### Filter Data
  23. StaticTableFiltered = reactive({
  24. EqSelect = if(is.null(input$df1Select)) unique(as.vector(df1$ID)) else df1$ID[df1$Equation == input$df1Select]
  25. filter(df2, Equation %in% EqSelect)})
  26. ### Render Static Table
  27. output$StaticTable = renderDataTable({
  28. if(is.null(input$df1Select)) return(NULL) else {StaticTableFiltered()}},
  29. options = list(dom = &#39;t&#39;), selection = &quot;none&quot;)
  30. ### Render Static Result as Text
  31. CalculateResultStatic = reactive({
  32. if(is.null(input$df1Select)) return(NULL) else {
  33. ### Define algorithm
  34. CalcEq = paste(input$df1Select)
  35. ### Make list of input variables
  36. Variables = as.data.frame(str_extract_all(input$df1Select, &quot;&lt;(.*?)&gt;&quot;))
  37. colnames(Variables)[1] = &quot;Vars&quot;
  38. ### Remove &lt; &gt; from algorithm and assumptions
  39. CalcEq = gsub(&quot;&lt;&quot;,&quot;&quot;,gsub(&quot;&gt;&quot;,&quot;&quot;,CalcEq))
  40. Variables$Vars = gsub(&quot;&lt;&quot;,&quot;&quot;,gsub(&quot;&gt;&quot;,&quot;&quot;,Variables$Vars))
  41. ### Get values from Assumptions table
  42. Variables = merge(Variables, df2[df2$Equation == df1$ID[df1$Equation == input$df1Select],], by.x = &quot;Vars&quot;, by.y = &quot;Variable&quot;, all.x = TRUE, all.y = FALSE)
  43. ### Convert variables to list
  44. Variables.List = as.list(Variables$Value)
  45. names(Variables.List) = Variables$Vars
  46. ### Evaluate equation on list
  47. eval(str2lang(CalcEq), envir = Variables.List)}})
  48. output$CalcResultStatic = renderUI(HTML(paste(&quot;&lt;b&gt;&quot;,CalculateResultStatic(), sep = &quot;&quot;)))
  49. ### Render Interactive Table
  50. output$InteractiveTable = renderDataTable({
  51. if(is.null(input$df1Select)) return(NULL) else {
  52. data = StaticTableFiltered() %&gt;%
  53. rename(User_Value = Value)
  54. }
  55. },
  56. selection = &quot;none&quot;, escape = FALSE, editable = TRUE, # make dt editable
  57. options =
  58. list(
  59. preDrawCallback = JS(&#39;function() { Shiny.unbindAll(this.api().table().node()); }&#39;),
  60. drawCallback = JS(&#39;function() { Shiny.bindAll(this.api().table().node()); } &#39;),
  61. dom = &#39;t&#39;,
  62. processing = FALSE))
  63. ### Render Interactive Result as Text
  64. CalculateResultInteractive = reactive({
  65. if(is.null(input$df1Select)) return(NULL) else {
  66. ### Define algorithm
  67. CalcEq = paste(input$df1Select)
  68. ### Make list of input variables
  69. Variables = as.data.frame(str_extract_all(input$df1Select, &quot;&lt;(.*?)&gt;&quot;))
  70. colnames(Variables)[1] = &quot;Vars&quot;
  71. ### Remove &lt; &gt; from algorithm and assumptions
  72. CalcEq = gsub(&quot;&lt;&quot;,&quot;&quot;,gsub(&quot;&gt;&quot;,&quot;&quot;,CalcEq))
  73. Variables$Vars = gsub(&quot;&lt;&quot;,&quot;&quot;,gsub(&quot;&gt;&quot;,&quot;&quot;,Variables$Vars))
  74. # Update the DT with the new user entered value
  75. if(!is.null(input$InteractiveTable_cell_edit)) {
  76. new_data = input$InteractiveTable_cell_edit
  77. df2[new_data$row, new_data$col] = as.integer(new_data$value)
  78. }
  79. ### Get values from Assumptions table
  80. Variables = merge(Variables, df2[df2$Equation == df1$ID[df1$Equation == input$df1Select],], by.x = &quot;Vars&quot;, by.y = &quot;Variable&quot;, all.x = TRUE, all.y = FALSE)
  81. ### Convert variables to list
  82. Variables.List = as.list(Variables$Value)
  83. names(Variables.List) = Variables$Vars
  84. ### Evaluate equation on list
  85. eval(str2lang(CalcEq), envir = Variables.List)}})
  86. output$CalcResultInteractive = renderUI(HTML(paste(&quot;&lt;b&gt;&quot;,CalculateResultInteractive(), sep = &quot;&quot;)))
  87. }
  88. shinyApp(ui = ui, server = server)

huangapple
  • 本文由 发表于 2023年8月9日 01:52:05
  • 转载请务必保留本文链接:https://go.coder-hub.com/76862056.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定