updateNumericInput 未从 reactiveValues 更新
updateNumericInput not updating from reactiveValues
我想我 运行 遇到了一些奇怪的范围界定问题,我已经为这个问题奋斗了一个星期,却不了解发生了什么。
我也无法真正举出一个有同样问题的小例子,但我希望这些症状能敲响警钟。真实代码也可用,但应用程序非常复杂。
让我解释一下代码中的播放器。
一个bsModal
中的一些输入,主要是numericInput
.
一个 observeEvent
,我们称之为“reader”,当读取包含缓存结果的文件时触发。它更新一个 reactiveValues
对象,该对象包含特殊 S4 对象中所有输入的等价物。
然后我们有一个 observe
,我们称它为“对象创建者”,它接受所有输入并在任何输入更改时更新 reactiveValues 对象。
一个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
构建。
启动应用程序后,可以通过以下方式查看问题:
- 点击“加载”
- Select 一个可用文件
- 点击“本地设置”
- 现在加载数据中的“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
值覆盖。
我对逐个游戏演练的解释如下所示:
- Reader 更新设置,使对象创建者和输入更新者无效。
- 新的评估周期开始。
- 输入更新器发送一条消息以从新设置更新输入,但是
输入对象中的值尚未更改。
- 对象创建者根据旧输入更新设置,使设置无效
并因此输入更新程序和对象创建程序本身。
- 输入更新器发送另一条消息来更新输入,这次基于
对象创建者刚刚设置的旧设置。
- 对象创建者再次更新设置,仍然基于旧的输入。失效
未触发,因为值未更改。
- 所有输出已准备就绪,评估结束,会话结束。
- 输入更新器发送的更新消息到达;只注意到后者,这
将输入更改为旧值。
- 对象创建者运行并将设置设置为旧值。再次,无效
未触发设置,因为值未更改。
- 评估再次结束,这次没有待处理的输入消息。
要解决此问题,请从“对象创建者”中删除 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()
我想我 运行 遇到了一些奇怪的范围界定问题,我已经为这个问题奋斗了一个星期,却不了解发生了什么。 我也无法真正举出一个有同样问题的小例子,但我希望这些症状能敲响警钟。真实代码也可用,但应用程序非常复杂。
让我解释一下代码中的播放器。
一个
bsModal
中的一些输入,主要是numericInput
.一个
observeEvent
,我们称之为“reader”,当读取包含缓存结果的文件时触发。它更新一个reactiveValues
对象,该对象包含特殊 S4 对象中所有输入的等价物。然后我们有一个
observe
,我们称它为“对象创建者”,它接受所有输入并在任何输入更改时更新 reactiveValues 对象。一个
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
构建。
启动应用程序后,可以通过以下方式查看问题:
- 点击“加载”
- Select 一个可用文件
- 点击“本地设置”
- 现在加载数据中的“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
值覆盖。
我对逐个游戏演练的解释如下所示:
- Reader 更新设置,使对象创建者和输入更新者无效。
- 新的评估周期开始。
- 输入更新器发送一条消息以从新设置更新输入,但是 输入对象中的值尚未更改。
- 对象创建者根据旧输入更新设置,使设置无效 并因此输入更新程序和对象创建程序本身。
- 输入更新器发送另一条消息来更新输入,这次基于 对象创建者刚刚设置的旧设置。
- 对象创建者再次更新设置,仍然基于旧的输入。失效 未触发,因为值未更改。
- 所有输出已准备就绪,评估结束,会话结束。
- 输入更新器发送的更新消息到达;只注意到后者,这 将输入更改为旧值。
- 对象创建者运行并将设置设置为旧值。再次,无效 未触发设置,因为值未更改。
- 评估再次结束,这次没有待处理的输入消息。
要解决此问题,请从“对象创建者”中删除 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()