如何提高shiny中dygraph的刷新率?

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

How to improve the refresh rate of a dygraph in shiny?

问题

以下是代码的中文翻译部分:

我想通过一个闪亮的应用程序和dygraphs查看时间序列(有很多点,这里有2E6个点)。
下面的脚本是一个工作得很好的最小示例,除了数值输入“start”发生变化会导致显示冻结5秒之外,一切正常。相反,使用范围选择器几乎没有延迟。所以我想这应该是可行的,但我没有找到解决方法。

是否有办法改进它?

library(shiny)
library(dygraphs)

ui <- fluidPage(
  # 侧边栏
  sidebarLayout(
    # 用于输入的侧边栏面板 ----
    sidebarPanel(
      numericInput("start", label = "开始(迭代)",
                   value = 1, step = 5E4),
      numericInput("duration", label = "持续时间(迭代)",
                   value = 5E4)
    ),
    # 主面板    
    mainPanel(
      dygraphOutput("plot")
    )
  )
)

server <- function(input, output) {
  z <- rnorm(2E6, 1, 10) # 数据
  time <- 1:length(z)
  df <- data.frame(time, z)
  output$plot <- renderDygraph({
    dygraph(df) %>% dyRangeSelector(dateWindow = c(input$start, input$start + input$duration))
  })
}

shinyApp(ui = ui, server = server)

希望这对您有帮助。

英文:

I would like to go through a time series (having lots of points, here 2E6) using a shiny app and dygraphs.
The script below is a minimal example that works nicely except that a change in the numeric input start results in a 5 seconds freeze of the display. In contrast, moving with the range selector results in almost no lag. So I guess it should be feasible but I had no luck sorting this out.

Is there a way to improve it ?

library(shiny)
library(dygraphs)

ui &lt;- fluidPage(
  # Sidebar
  sidebarLayout(
    # Sidebar panel for inputs ----
    sidebarPanel(
    numericInput(&quot;start&quot;, label = &quot;Start (iteration)&quot;, 
                   value = 1, step = 5E4),
    numericInput(&quot;duration&quot;, label = &quot;Duration (iterations)&quot;, 
                 value = 5E4)
    ),
  # Main    
  mainPanel(
      dygraphOutput(&quot;plot&quot;)
    )
  )
)

server &lt;- function(input, output) {
  z&lt;-rnorm(2E6,1,10) # data
  time&lt;-1:length(z)
  df&lt;-data.frame(time,z)
  output$plot &lt;- renderDygraph({
    dygraph(df) %&gt;% dyRangeSelector(dateWindow = c(input$start,input$start+input$duration) ) 
  })
  
}
shinyApp(ui = ui, server = server)

如何提高shiny中dygraph的刷新率?

答案1

得分: 2

以下是您要翻译的内容:

"这种行为的原因是,每当您更改 input$startinput$duration),整个图表都会重新渲染。当您仅仅更改选择器的手柄时,dygraph 会确保显示相关数据,而不重新渲染整个图表(实际上,这是 dygraph 的一个特性之一)。

您可以借助一点 JavaScript 的帮助来利用这种行为。思路如下:

  1. 在您的 renderDygraph 函数中,不要依赖于 input$startinput$duration)。这样可以避免在这些值更改时重新渲染整个图表。

  2. 包含一个 observer,它调用 dygraph 的 JavaScript 函数 updateOptions,从而更新 x 轴上的可见范围(基本上就是手动更改范围手柄的效果)。

  3. 为此,您需要:

    1. 在渲染时存储 dygraph 对象(我们使用 htmlwidgtes::onRender 来实现),以便稍后调用 updateOptions
    2. 添加一个自定义消息处理程序,以从 shiny 中调用 JavaScript(您也可以使用 shinyjs,它为您封装了这一功能)。

代码胜过千言万语,下面是一个可工作的示例:"

英文:

The reason for this behaviour is that whenever you change input$start (input$duration) the whole plot is re-rendered. When you simply change the selector handles, dygraph makes sure the relevant data is shown, without re-rendering the whole graph (that is in fact one of the features of dygraph).

You can piggy-back on this behaviour with the help of a bit of JavaScript. The idea is the following:

  1. In your renderDygraph function you do not take dependencies on input$start (input$duration). This avoids that the whole graph is re-rendered whenever one of those values changes.

  2. You include an observer, which calls the dygraph JavaScript function updateOptions, which in turn updates the visible range on the x-axis (so basically the same as changing the range handles by hand).

  3. In order to do so you need to:

    1. Store the dygraph object upon rendering (we use htmlwidgtes::onRender to so so), such that we can call updateOptions later.
    2. Add a custom message handler, to invoke JavaScript from shiny (you could also use shinyjs which encapsulates this for you).

Code speaks a thousand words, so here's a working example:

library(shiny)
library(dygraphs)
library(htmlwidgets)

ch &lt;- JS(&quot;
   var plots = [];
   Shiny.addCustomMessageHandler(&#39;adjust-x-axis&#39;, function(limits) {
     const dg = plots[&#39;plot&#39;];
     if (dg) {
       dg.updateOptions({dateWindow: [limits.xmin, limits.xmax]});
     }
   });&quot;)

ui &lt;- fluidPage(
   # Sidebar
   sidebarLayout(
      # Sidebar panel for inputs ----
      sidebarPanel(
         numericInput(&quot;start&quot;, label = &quot;Start (iteration)&quot;, 
                      value = 1, step = 5E4),
         numericInput(&quot;duration&quot;, label = &quot;Duration (iterations)&quot;, 
                      value = 5E4)
      ),
      # Main    
      mainPanel(
         tags$head(
           tags$script(
              ch,
              type = &quot;text/javascript&quot;
           ) 
         ),
         dygraphOutput(&quot;plot&quot;)
      )
   )
)



server &lt;- function(input, output, session) {
   z &lt;- rnorm(2E6, 1, 10) # data
   time &lt;- 1:length(z)
   df &lt;- data.frame(time, z)
   output$plot &lt;- renderDygraph({
      dygraph(df) %&gt;% 
         dyRangeSelector(dateWindow = c(1, 1 + 5E4)) %&gt;% 
         onRender(&quot;function(el, x) {
           plots[&#39;plot&#39;] = this.dygraph;
         }&quot;)
   })

   observe({
      start &lt;- req(input$start)
      duration &lt;- req(input$duration)
      session$sendCustomMessage(
         &quot;adjust-x-axis&quot;, 
         list(xmin = start, xmax = start + duration)
         )
   })
}

shinyApp(ui = ui, server = server)

huangapple
  • 本文由 发表于 2023年5月6日 19:55:37
  • 转载请务必保留本文链接:https://go.coder-hub.com/76188724.html
匿名

发表评论

匿名网友

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

确定