maRmat
maRmat

Reputation: 363

Pause looping in plots - Shiny

I have to build a simple web app using Shiny where I need to make a plot at each iteration of a sequential computation. Using this post I could manage to do it.

Now what I want is to be able to stop the looping process with a click. The action button should work like a pause/play button but I could not make it work as expected.

When going through the code I can't understand why the observe would run when pause_value() is true. I added some print to see what is actually done and when. Here is the code:

library(shiny)

server <- function(input, output, session) {
  rv <- reactiveValues(i = 0)
  maxIter <- 10

  output$myplot <- renderPlot( {
    if(rv$i > 0) {
      x <- seq_len(rv$i * 100)
      y <- (x + 1)^2 - 1 # this will do for now
      plot(x, y, main = sprintf("Round %i", rv$i), type = "l")
    } else {
      plot(1:1, main = "Placeholder")
    }
  })

  pause_value <- reactive({
    if (input$run %% 2 == 0) {
      TRUE
    } else {
      FALSE
    }
  }
  )

  observeEvent(
    eventExpr = pause_value(),
    handlerExpr = {
      if (pause_value()) {
        updateActionButton(
          session,
          inputId = "run",
          label = "RUN"
        )
      } else {
        updateActionButton(
          session,
          inputId = "run",
          label = "STOP"
        )
      }
    }
  )

  observeEvent(
    eventExpr = {
      input$run
      pause_value()
    },
    ignoreNULL = FALSE,
    ignoreInit = TRUE,
    handlerExpr = {
      print(pause_value())
      if (!pause_value()) {
        rv$i <- 0
        observe({
          print("-----")
          isolate({
            rv$i <- rv$i + 1
          })
          if (isolate(rv$i) < maxIter){
            invalidateLater(2000, session)
          }
        })
      } else {
        print("=====")
      }
    })
}

ui <- fluidPage(
  actionButton("run", "RUN"),
  plotOutput("myplot")
)

shinyApp(ui = ui, server = server)

I have been trying to make my app works for 2 days now. And even on this simple example I can't figure out the problem.

I hope someone can help.

My session info :

R version 3.5.0 (2018-04-23)
Platform: x86_64-apple-darwin15.6.0 (64-bit)
Running under: macOS  10.14.1

Matrix products: default
BLAS: /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBLAS.dylib
LAPACK: /Library/Frameworks/R.framework/Versions/3.5/Resources/lib/libRlapack.dylib

locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
[1] shiny_1.2.0

loaded via a namespace (and not attached):
 [1] compiler_3.5.0  magrittr_1.5    R6_2.3.0        promises_1.0.1  later_0.7.5    
 [6] htmltools_0.3.6 tools_3.5.0     Rcpp_0.12.19    jsonlite_1.5    digest_0.6.18  
[11] xtable_1.8-3    httpuv_1.4.5    mime_0.6        packrat_0.4.9-2 rlang_0.3.0.1  

Cheers

Upvotes: 0

Views: 259

Answers (1)

Yanir Mor
Yanir Mor

Reputation: 711

Consider the following approach, using a timer() that controls the value of a rv$go variable (which in turn controls whether the rv$i will increment or not:

library(shiny)

server <- function(input, output, session) {
  rv <- reactiveValues(i = 0, go = F)
  maxIter <- 10
  timer <- reactiveTimer(2000)

  output$myplot <- renderPlot({
    if(rv$i > 0) {
      x <- seq_len(rv$i * 100)
      y <- (x + 1)^2 - 1 # this will do for now
      plot(x, y, main = sprintf("Round %i", rv$i), type = "l")
    } else {
      plot(1:1, main = "Placeholder")
    }
  })

  observeEvent(input$run, {
    rv$go <- !rv$go

    updateActionButton(
      session,
      inputId = "run",
      label = "STOP"
    )
  })

  observeEvent(timer(), {
    req(rv$i < maxIter)
    req(rv$go)
    rv$i <- rv$i + 1
  })
}

ui <- fluidPage(
  actionButton("run", "RUN"),
  plotOutput("myplot")
)

shinyApp(ui = ui, server = server)

Upvotes: 1

Related Questions