0

当数据发生变化时,如何阻止在函数中创建的观察者多次存在?

更新: - 进一步简化了 github 上的应用程序,以便于测试。- 一直在尝试使用destroy ----

我制作了一个应用程序,在整个程序中需要多个(10ish)版本的绘图,因此我编写了 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 链接上找到: 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
      }
    })
  })

每次更改数据时都会调用destroy。

  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代码之外?

4

1 回答 1

0

observeEvent原因是在动态方法中创建了相同的副本(lapply超过 x 长度)

问题是在重建元素时Shiny覆盖ui元素(或者至少只显示它的最新版本,但是当你构建编号observeEvents以收听一组编号按钮等时,如果你只是构建,它会创建每个观察者的副本他们从即 1:10 开始lapply

防止这个问题的解决方案是,记录到目前为止你做了多少observers(最大 nr 循环),然后当与循环相关的代码更新,并且需要更大的 nr 时observers,只为更高的 nr 制作新的比以前的最大值。

换句话说,循环“上一个最大值”+1(第一次为 0)直到新的最大值,确保只有

于 2019-02-23T17:13:22.347 回答