Using shiny and plotly, how can I animate a vertical line on a time series that scrolls with the current frame of an embedded movie?

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

Using shiny and plotly, how can I animate a vertical line on a time series that scrolls with the current frame of an embedded movie?

问题

我理解了。以下是您要求的中文翻译:

我正在使用R、shiny和plotly制作一个仪表板。我想展示一个视频,并在其下方显示与视频中的每一刻相关的时间序列图。当用户播放视频时,我想在图中显示一个垂直线,该线对应于视频中的当前播放时间。换句话说,这是一种类似于滚动播放头的功能。

这里的代码和示例数据实现了我想要的,但效果不佳,存在两个问题。

1. 这条线只会每秒更新一次。理想情况下,我希望它能更平滑地移动,类似于每秒30帧,以匹配视频。

2. 据我了解plotly和shiny(即了解不太深刻),每次移动垂直线时,我都在重新绘制整个图表。在这里的示例数据中,这可能不是问题。但最终我将使用非常大的数据集并进行一些平滑处理,因此我只想绘制时间序列一次,并单独更新垂直线的位置。关于使用plotlyProxyInvoke的说明可以在[这里](https://plotly-r.com/linking-views-with-shiny.html#proxies)找到,但我无法在我的情况下实现这些想法。

我在R和ggplot方面相当熟练,但这是我第一次同时使用shiny和plotly,如果我漏掉了一些基本的东西,还请谅解。非常感谢任何建议!
英文:

I am making a dashboard using R, shiny and plotly. I would like to show a video, and beneath it a plot of a time series that relates to each moment in the video. When the user plays the video, I want to show a vertical line on the plot that corresponds to current playing time on the video. In other words, it's a sort of scrolling playhead.

The code and toy data here achieves what I want, but poorly. There are two problems.

  1. The line only updates about once a second. Ideally, I'd like it to move more smoothly, something like 30 frames per second to match the video.

  2. As I understand plotly and shiny (ie not very well), then each time I am moving the vertical line, I am re-drawing the whole plot. With the toy data here, that may not be problem. But eventually I will be using very large data sets and doing some smoothing, so I only want to draw the time series once, and update the vertical line position by itself. There are instructions about using plotlyProxyInvoke herebut I can't implement those ideas in my case.

I'm fairly competent in R and ggplot, but this is my first time with both shiny and plotly, so apologies if I'd missing something basic. Any suggestions very much appreciated!


library(shiny)
library(video)

data <- data.frame(t=1:45,y=sample(x=50,size = 45))

ui <- fluidPage(
    mainPanel(
      video(
        "https://vjs.zencdn.net/v/oceans.mp4",
        elementId = "video"),
      tags$p( "Duration:",
        textOutput("video_seek", container = tags$strong, inline = TRUE), "/",
        textOutput("video_duration", container = tags$strong, inline = TRUE) ),
       plotlyOutput(outputId = "sparkline")
  ) )

server <- function(input, output,session) {
  output$sparkline <- renderPlotly({
    p <- ggplotly( ggplot(data,aes(x=t,y=y))+geom_line() )
    add_segments(p,x=input$video_seek,xend=input$video_seek,y=0,yend=50,inherit = F)  })
  output$video_duration <- renderText({input$video_duration })
  output$video_seek <- renderText({ input$video_seek })
}

shinyApp(ui,server)

答案1

得分: 0

你可以使用 plotlyProxyplotlyProxyInvoke

想法是在 renderPlotly 函数中创建基本的图表,并使用 plotlyProxyInvoke 更新对应于小型图表的迹线。

library(shiny)
library(video)
library(plotly)

data <- data.frame(t = 1:45,
                   y = sample(50, size = 45))

server <- function(input, output,session) {
   output$sparkline <- renderPlotly({
      plot_ly(
         data,
         x = ~t,
         y = ~y,
         type = "scatter",
         mode = "lines"
      ) %>%
         add_segments(x = 0, xend = 0, y = 0, yend = 50) %>%
         layout(xaxis = list(range = c(0, ceiling(req(input$video_duration)))))
   })
   
   output$video_duration <- renderText(input$video_duration)
   output$video_seek <- renderText(input$video_seek)
   
   observeEvent(input$video_seek, {
      plotlyProxy("sparkline") %>%
         plotlyProxyInvoke("restyle",
                           list(x = list(rep(input$video_seek, 2))),
                           1)

   })
}
英文:

You can use plotlyProxy together with plotlyProxyInvoke.

Idea is that you make the basic plot in the renderPlotly function and use plotlyProxyInvoke to update the trace corresponding to the sparkline.

library(shiny)
library(video)
library(plotly)

data &lt;- data.frame(t = 1:45,
                   y = sample(50, size = 45))

server &lt;- function(input, output,session) {
   output$sparkline &lt;- renderPlotly({
      plot_ly(
         data,
         x = ~t,
         y = ~y,
         type = &quot;scatter&quot;,
         mode = &quot;lines&quot;
      ) %&gt;% 
         add_segments(x = 0, xend = 0, y = 0, yend = 50) %&gt;%
         layout(xaxis = list(range = c(0, ceiling(req(input$video_duration)))))
   })
   
   output$video_duration &lt;- renderText(input$video_duration)
   output$video_seek &lt;- renderText(input$video_seek)
   
   observeEvent(input$video_seek, {
      plotlyProxy(&quot;sparkline&quot;) %&gt;%
         plotlyProxyInvoke(&quot;restyle&quot;,
                           list(x = list(rep(input$video_seek, 2))),
                           1)

   })
}

huangapple
  • 本文由 发表于 2023年4月10日 21:52:06
  • 转载请务必保留本文链接:https://go.coder-hub.com/75977715.html
匿名

发表评论

匿名网友

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

确定