由函数内部创建的旧 observeEvents 触发的不需要的弹出风暴
Unwanted popup storm triggered by old observeEvents created inside a function
如何在数据更改时阻止函数内创建的观察者多次存在?
更新:
- 进一步简化 github 上的应用程序以便于测试。
- 一直在尝试使用 destroy
----
我制作了一个应用程序,在我的程序中需要多个(10 个左右)版本的情节,因此我编写了 2 个函数:
myplotly
创建地块
mypopup
创建的弹出窗口包含属于 myplotly
图中每个粒子的脉冲形状图,以及 modaldialog
弹出窗口中的选项按钮,以及所属的观察者
当用户点击第一个图中的一个点时,这些对话框会打开。
此函数的简化版本如下所示:
mypopup <- function(THEDATAFRAME, THEPLOT, THEGROUP, THEPULSEFRAME) {
..... bla bla lots more code in real app.....
..... one example of an observer with only 1 of the arguments needed for this one
observeEvent(input[[paste("Close", THEPLOT, sep ='.')]], {
removeModal()
}, ignoreInit = T)
}
函数*1在创建或加载相应的数据框时调用,并在数据发生变化时再次调用。
我面临的问题是,在数据被更改并且用户点击弹出窗口的某个点后,所有观察者都会触发两次。如果数据再次更改,弹出窗口会触发 3 次,依此类推。
此外,基于旧数据的弹出窗口不理解图中现在有超过 1 个集群,因此如果您单击集群 2 或 3,错误/ NA 图等。
报表:
- 使用 obs$destroy 可能会解决问题,但并不容易(参见脚注 *2)
- 为什么我们首先得到双重观察者?修复症状是一回事,理解为什么它们没有被简单地覆盖对我来说仍然是个谜。
我已经创建了一个精简的工作代码示例以及一些文件 运行 它可以在以下 github link 中找到:
https://github.com/madmark81/Observer-Madness
脚注
1 我之所以将它写成函数,是因为我每次都在我的主应用程序中多次应用这种绘图和弹出窗口的组合,具体取决于独特的组合基本数据帧和脉冲数据帧以及包含组 ID 和组名称的列。
2
Maximilian 提出了将观察者分配给变量的想法。但是这个实现似乎必须在 mypopup 函数之外完成,而且我无法让它在使用超过 1 个输入参数的观察者上工作,这通常由 mypopup 函数的 4 个输入参数排序,但不能使用 lapply 调用来完成,如下例仅恰好有 1 个输入参数:
lapply(plot.list, function(x){
o <- observeEvent(event_data("plotly_click", source = paste("plotlyplot", x, sep = '.')), {
print('clicked')
if(values[[paste("particle_viewer", x, sep = "_")]]) {
## when click in plot: Highlight the clicked particle with java, but also store the clicked point
values[[paste("HLval", x, sep = "_")]] <- event_data("plotly_click", source = paste("plotlyplot", x, sep = '.')) ## this code stores the last clicked point so that the point stays active when object is re-rendered
}
})
})
每次数据更改时都会调用销毁。
observeEvent( values$TrainDFLogged, {
lapply(c("o"), function(x) {
if (exists(x))
{get(x)$destroy
print('destroyed2')
}
})
mypopup(values$TrainDFLogged, "SecondFile", "default", values$TrainPulses)
})
更新 2
然而,当在 mypopup 函数代码之外创建观察者时,似乎不需要销毁并分配给 'o',点击只会按我刚刚发现的时间观察。所以也许我们应该简单地找到一种方法来在 lapply
或 mapply
样式的解决方案中创建所有观察者,但在 mypopup
代码之外?
原因是在动态方法中创建了相同 observeEvent
的副本(lapply
超过 x 长度)
问题是 Shiny
在重建时覆盖 ui
元素(或者至少只显示它的最新版本,但是当你构建编号 observeEvents
来听一组带编号的按钮或类似按钮,如果您简单地从 1:10 中的 lapply
.
构建它们,它会创建每个观察者的副本
防止这个问题的解决方案是,记录你到目前为止做了多少observers
(最大nr循环),然后当与循环相关的代码更新时,需要更大的nr observers
的,只为高于先前最大值的 nrs 制作新的。
换句话说,遍历 'previous maximum'+1(第一次为 0)直到新的最大值,确保只有
如何在数据更改时阻止函数内创建的观察者多次存在?
更新:
- 进一步简化 github 上的应用程序以便于测试。
- 一直在尝试使用 destroy
----
我制作了一个应用程序,在我的程序中需要多个(10 个左右)版本的情节,因此我编写了 2 个函数:
myplotly
创建地块mypopup
创建的弹出窗口包含属于myplotly
图中每个粒子的脉冲形状图,以及modaldialog
弹出窗口中的选项按钮,以及所属的观察者
当用户点击第一个图中的一个点时,这些对话框会打开。
此函数的简化版本如下所示:
mypopup <- function(THEDATAFRAME, THEPLOT, THEGROUP, THEPULSEFRAME) {
..... bla bla lots more code in real app.....
..... one example of an observer with only 1 of the arguments needed for this one
observeEvent(input[[paste("Close", THEPLOT, sep ='.')]], {
removeModal()
}, ignoreInit = T)
}
函数*1在创建或加载相应的数据框时调用,并在数据发生变化时再次调用。
我面临的问题是,在数据被更改并且用户点击弹出窗口的某个点后,所有观察者都会触发两次。如果数据再次更改,弹出窗口会触发 3 次,依此类推。 此外,基于旧数据的弹出窗口不理解图中现在有超过 1 个集群,因此如果您单击集群 2 或 3,错误/ NA 图等。
报表:
- 使用 obs$destroy 可能会解决问题,但并不容易(参见脚注 *2)
- 为什么我们首先得到双重观察者?修复症状是一回事,理解为什么它们没有被简单地覆盖对我来说仍然是个谜。
我已经创建了一个精简的工作代码示例以及一些文件 运行 它可以在以下 github link 中找到: https://github.com/madmark81/Observer-Madness
脚注
1 我之所以将它写成函数,是因为我每次都在我的主应用程序中多次应用这种绘图和弹出窗口的组合,具体取决于独特的组合基本数据帧和脉冲数据帧以及包含组 ID 和组名称的列。
2 Maximilian 提出了将观察者分配给变量的想法。但是这个实现似乎必须在 mypopup 函数之外完成,而且我无法让它在使用超过 1 个输入参数的观察者上工作,这通常由 mypopup 函数的 4 个输入参数排序,但不能使用 lapply 调用来完成,如下例仅恰好有 1 个输入参数:
lapply(plot.list, function(x){
o <- observeEvent(event_data("plotly_click", source = paste("plotlyplot", x, sep = '.')), {
print('clicked')
if(values[[paste("particle_viewer", x, sep = "_")]]) {
## when click in plot: Highlight the clicked particle with java, but also store the clicked point
values[[paste("HLval", x, sep = "_")]] <- event_data("plotly_click", source = paste("plotlyplot", x, sep = '.')) ## this code stores the last clicked point so that the point stays active when object is re-rendered
}
})
})
每次数据更改时都会调用销毁。
observeEvent( values$TrainDFLogged, {
lapply(c("o"), function(x) {
if (exists(x))
{get(x)$destroy
print('destroyed2')
}
})
mypopup(values$TrainDFLogged, "SecondFile", "default", values$TrainPulses)
})
更新 2
然而,当在 mypopup 函数代码之外创建观察者时,似乎不需要销毁并分配给 'o',点击只会按我刚刚发现的时间观察。所以也许我们应该简单地找到一种方法来在 lapply
或 mapply
样式的解决方案中创建所有观察者,但在 mypopup
代码之外?
原因是在动态方法中创建了相同 observeEvent
的副本(lapply
超过 x 长度)
问题是 Shiny
在重建时覆盖 ui
元素(或者至少只显示它的最新版本,但是当你构建编号 observeEvents
来听一组带编号的按钮或类似按钮,如果您简单地从 1:10 中的 lapply
.
防止这个问题的解决方案是,记录你到目前为止做了多少observers
(最大nr循环),然后当与循环相关的代码更新时,需要更大的nr observers
的,只为高于先前最大值的 nrs 制作新的。
换句话说,遍历 'previous maximum'+1(第一次为 0)直到新的最大值,确保只有