updateNumericInput 未从 reactiveValues 更新

updateNumericInput not updating from reactiveValues

我想我 运行 遇到了一些奇怪的范围界定问题,我已经为这个问题奋斗了一个星期,却不了解发生了什么。 我也无法真正举出一个有同样问题的小例子,但我希望这些症状能敲响警钟。真实代码也可用,但应用程序非常复杂。

让我解释一下代码中的播放器。

  1. 一个bsModal中的一些输入,主要是numericInput.

  2. 一个 observeEvent,我们称之为“reader”,当读取包含缓存结果的文件时触发。它更新一个 reactiveValues 对象,该对象包含特殊 S4 对象中所有输入的等价物。

  3. 然后我们有一个 observe,我们称它为“对象创建者”,它接受所有输入并在任何输入更改时更新 reactiveValues 对象。

  4. 一个observeEvent,我们称它为“输入更新器”,当reactiveValues反应无效时触发,应该更新所有输入。这样做是为了允许其他进程通过更改 reactiveValues 反应(例如“对象创建者”)来更改输入。我需要的第一个功能就是在“对象创建者”读取缓存结果时更新输入。

所以它应该是: “reader”读取一个文件 --> “输入更新器”看到一个新的 reactiveValues 响应并更新输入(--> “对象创建者”看到新的输入并重写reactiveValues 有反应,但它们应该是“reader”已经设置的。

我的问题出在“输入更新程序”中。我无法让它根据 reactiveValues.

更新输入

代码如下所示:

observeEvent(settings$processing_local, {

    cat("\n\n\n")
    print("Modifying inputs")
    print(paste0("before ppm input is: ", input$local_ppm))
  
    set <- ppm(settings$processing_local) # THIS DOES NOT WORK
    print(paste0("setting: ", set)) # SHOWS CORRECT VALUE
    # set <- 1000 # THIS WORKS!
  
   updateNumericInput(session,"local_ppm",value = set)
   
   print(paste0("after ppm input is: ", input$local_ppm))
   
   cat("\n\n\n")
  
}, priority = 2)

set 基于 reactiveValues settings$processing_local 时,更新不会发生。疯狂的是 print 的输出确实 显示了正确的值,如果我将一个值硬编码为 set 那么它也可以工作。 1, 2, 3 and 4.

的完整代码



编辑1:基于@cuttlefish44示例的相关流程版本 这更接近我的动作应用程序,但不幸的是没有我在完整应用程序中遇到的问题。

ui <- fluidPage(
    numericInput("inNumber", "Input number", 0),
    actionButton("but", "Update")
)

server <- function(input, output, session) {
    settings <- reactiveValues(aaa = NULL)
    
    
    # proxy for reading cached file
    observeEvent(input$but, {
      settings$aaa <- 30
      
    })
    

    
    observe({
      settings$aaa <- input$inNumber
      
    }, priority = 1)
    
    
    
    observeEvent(settings$aaa, {
        set <- settings$aaa
        print(c(set, input$inNumber))
        
        updateNumericInput(session, "inNumber", value = set)
        print(c(set, input$inNumber))
        
    }, priority = 2)
    
    
}

shinyApp(ui, server)



编辑 2:代替问题的工作示例,我已经对我的应用程序进行了 docker 化,因此应该可以看到该问题,尽管这样做很烦人。 Docker 化应用 here。 可以使用 docker build --tag mscurate . 和 运行 使用 docker run --publish 8000:3838 mscurate 构建。 启动应用程序后,可以通过以下方式查看问题:

  1. 点击“加载”
  2. Select 一个可用文件
  3. 点击“本地设置”
  4. 现在加载数据中的“ppm”值是 500。但输入从未更新,然后反应被改回默认​​值 100。

日志显示加载文件时的事件顺序:

-------Loading started-------
before the reactive is:
settings not present
after the reactive is:
500
-------Loading finished-------

-------Modifying inputs-------
before ppm input is: 100
setting: 500
after ppm input is: 100     <---- @cuttlefish44's answer explains why this is not updated
--------------

-------updating reactive objects-------
before ppm input is: 100    <---- this should have been updated to 500!
before the reactive object is: 500
after ppm input is: 100
after the reactive object is: 100
--------------

-------Modifying inputs-------
before ppm input is: 100
setting: 100
after ppm input is: 100
--------------

-------updating reactive objects-------
before ppm input is: 100
before the reactive object is: 100
after ppm input is: 100
after the reactive object is: 100
--------------

-------updating reactive objects-------
before ppm input is: 100
before the reactive object is: 100
after ppm input is: 100
after the reactive object is: 100
--------------

您的代码有效,但据我所知,input 在事件中是静态的。 请参阅下面的简单示例。

ui <- fluidPage(
    sliderInput("controller", "Controller", 0, 20, 10),
    numericInput("inNumber", "Input number", 0),
)

server <- function(input, output, session) {
    settings <- reactiveValues(aaa = NULL)
    
    observe({
        settings$aaa <- input$controller + 3

    }, priority = 1)
    
    observeEvent(settings$aaa, {
        set <- settings$aaa
        print(c(input$controller, set, input$inNumber))
        
        updateNumericInput(session, "inNumber", value = set)
        print(c(input$controller, set, input$inNumber))
        
    }, priority = 2)
}

shinyApp(ui, server)

我将控制器 10(默认)更改为 12。

# this is console output
[1] 10 13  0
[1] 10 13  0
[1] 12 15 13
[1] 12 15 13

并且 UI 屏幕截图显示 inNumber 已更新为 15。
但是控制台输出显示输入没有立即更新。
(也许更新后的值在 session 的某个地方,但我不知道在哪里)

我认为这里的问题是“对象创建者”有一个反应 依赖于 RVs,导致它在与 “reader”更新 RV 时的“输入更新程序”。然后在“输入更新器”的更新发生在下一个周期之前,设置被旧的 input 值覆盖。

我对逐个游戏演练的解释如下所示:

  1. Reader 更新设置,使对象创建者和输入更新者无效。
  2. 新的评估周期开始。
  3. 输入更新器发送一条消息以从新设置更新输入,但是 输入对象中的值尚未更改。
  4. 对象创建者根据旧输入更新设置,使设置无效 并因此输入更新程序和对象创建程序本身。
  5. 输入更新器发送另一条消息来更新输入,这次基于 对象创建者刚刚设置的旧设置。
  6. 对象创建者再次更新设置,仍然基于旧的输入。失效 未触发,因为值未更改。
  7. 所有输出已准备就绪,评估结束,会话结束。
  8. 输入更新器发送的更新消息到达;只注意到后者,这 将输入更改为旧值。
  9. 对象创建者运行并将设置设置为旧值。再次,无效 未触发设置,因为值未更改。
  10. 评估再次结束,这次没有待处理的输入消息。

要解决此问题,请从“对象创建者”中删除 RV 依赖项,例如和 isolate()。我无法让 req()isolate() 一起工作, 但在这种情况下,您可以完全放弃它。

这是一个问题的最小示例。删除这里的 req() 修复它:

library(shiny)

lgr <- list(debug = function(...) cat(sprintf(...), "\n"))

ui <- fluidPage(
  sliderInput("file_number", "Number to \"read from file\"", 0, 10, 5),
  actionButton("read", "Read"),
  numericInput("number", "Input number to sync", 0)
)

server <- function(input, output, session) {
  settings <- reactiveValues(number = NULL)
  
  observeEvent(input$read, {
    settings$number <- input$file_number
    lgr$debug("Loaded settings from \"file\".")
  }, label = "reader")
  
  observe({
    req(settings$number) # The dependency on settings
    settings$number <- input$number
    lgr$debug("Updated settings from input.")
  }, priority = 1, label = "object-creator")
  
  observeEvent(settings$number, {
    updateNumericInput(session, "number", value = settings$number)
    lgr$debug("Set input from settings: %d", settings$number)
  }, priority = 2, label = "input-updater")
}

shinyApp(ui, server)

点击“阅读”后产生的日志:

Loaded settings from "file". 
Set input from settings: 5 
Updated settings from input. 
Set input from settings: 0 
Updated settings from input. 
Updated settings from input.

您可以通过 reactlog:

更好地了解该过程
reactlog::reactlog_enable()
reactlogReset()
shinyApp(ui, server)
reactlogShow()