0

I have a simply shiny app and i have two plotly charts there each with its Play button. I need to have one button that would animate both charts. How can I do it?

My code is below:

Plot 1:

  output$plot1<-renderPlotly({

    res<-df%>%
      plot_ly(
        x=~year,
        y=~value,
        showlegend = TRUE
      )%>%add_lines()

    res<-res%>%add_trace(
      x=~year,
      frame=~year,
      y=~value,
      color=~state,
      type = 'scatter',
      mode = 'markers',
      showlegend = FALSE
    )
   return(res)

  })

Plot 2:

  output$plot2<-renderPlotly({


 
   res2<- df2%>%
      plot_ly(
        x=~var,
        y=~var2,
        frame=~year,
        type = 'bar')

     return(res2)

  })
m45ha
  • 399
  • 1
  • 9

3 Answers3

2
library(shiny)
library(plotly)
library(htmlwidgets)

ui <- fluidPage(
  br(),
  actionButton("anim", "Animate both plots"),
  fluidRow(
    column(
      6,
      plotlyOutput("plot1")
    ),
    column(
      6,
      plotlyOutput("plot2")
    )
  )
  
)

server <- function(input, output, session){
  
  output[["plot1"]] <- renderPlotly({
    df <- data.frame(
      x = c(1,2,1), 
      y = c(1,2,1), 
      f = c(1,2,3)
    )
    df %>%
      plot_ly(
        x = ~x,
        y = ~y,
        frame = ~f,
        type = 'scatter',
        mode = 'markers',
        marker = list(size = 20),
        showlegend = FALSE
      ) %>% 
      animation_button(visible = FALSE) %>%
      onRender("
        function(el,x){
          $('#anim').on('click', function(){Plotly.animate(el);});
        }")
  })
  
  output[["plot2"]] <- renderPlotly({
    df <- data.frame(
      x = c(2,1,2), 
      y = c(2,1,2), 
      f = c(1,2,3)
    )
    df %>%
      plot_ly(
        x = ~x,
        y = ~y,
        frame = ~f,
        type = 'scatter',
        mode = 'markers',
        marker = list(size = 20),
        showlegend = FALSE
      ) %>% 
      animation_button(visible = FALSE) %>%
      onRender("
        function(el,x){
          $('#anim').on('click', function(){Plotly.animate(el);});
        }")
  })
  
}

shinyApp(ui, server)

enter image description here

Stéphane Laurent
  • 75,186
  • 15
  • 119
  • 225
0

You did not provide a minimal reproducible example, hence, I have to improvise.

But with a bit of JavaScript you could:

  1. Trigger the play button of the second plotly graph whenever the play button of the first plotly graph is pressed.
  2. Hide the play button and slider altogether of the second graph.

The reprex below does not use shiny, but it is rather straight forward to translate that to shiny too:

library(plotly)
library(crosstalk) ## just for bscols
library(htmltools)

## this JavaScript attaches a click handler to the SVG button 
## of the left play button (which fires the second play button)
## and hides the controls for the second graph
js <- HTML("
  document.addEventListener('DOMContentLoaded', function() {
    const left = document.querySelector('#left .updatemenu-button');
    const right = document.querySelector('#right .updatemenu-button');
    left.addEventListener('click', 
                          () => right.dispatchEvent(new Event('click'))); 
    right.style.display = 'none';
    document.querySelector('#right .slider-container').style.display = 'none';
  })
") |>
   tags$script(type = "text/javascript") |>
   tags$head()

df <- data.frame(
   x = c(1, 2, 1), 
   y = c(1, 2, 1), 
   f = c(1, 2, 3)
)

fig1 <- fig2 <- df %>%
   plot_ly(
      x = ~x,
      y = ~y,
      frame = ~f,
      type = "scatter",
      mode = "markers",
      showlegend = FALSE
   )

## I use bscols here just to quickly layout 2 plots and add some JS
## In your shiny app you won't need that most probably
bscols(div(fig1, id = "left"),
       div(fig2, id = "right"), 
       js)
thothal
  • 16,690
  • 3
  • 36
  • 71
  • never used crosstalk :( how would you translate it to shiny? – m45ha May 12 '23 at 10:51
  • you just need to include the JavaScript in your `ui` for instance by adding `tags$head(tags$script(js, type = "text/javascript"))` to your ui. Make sure that the `plotlyOutput` sits in a div with the `id` as highlighted above and the `JS` will work out of the box. (in `shiny` the additional `div` may not be needed and you could adapt the `css` seletcors to benefit from the id associated to the `plotlyOutput` but this is out of scope for this answer) – thothal May 12 '23 at 12:58
-1

Since you did not give a minimal reproducible example, try this app below:

library(shiny)

ui <- fluidPage(
  titlePanel("Hello Shiny!"),
  sidebarLayout(
    sidebarPanel(
      actionButton("click", "Click to refresh")
    ),
    
    # Show a plot of the slider value
    mainPanel(
      plotOutput("plot1"),
      plotOutput("plot2")
    )
  )
)

server <- function(input, output, session) {
  output$plot1 <- renderPlot({
    input$click
    dist <- rnorm(100)
    hist(dist)
  })
  
  output$plot2 <- renderPlot({
    input$click
    dist <- rnorm(100)
    plot(dist)
  })
}

shinyApp(ui, server)

All you need to do is simple: add two plot rendering to one input as "reactive dependency"(in this case, input$click), so that each time input$click updates, the two plots will be re-rendered.

Su Na
  • 334
  • 1
  • 7