3

I am trying to automate the interaction of a Shiny app so it displays a series of results while incrementing through a predetermined range of inputs, without having to repetitiously count and change input values. This automation will provide a systematic view of a set of inputs, such as displays of refreshed price charts for selected stocks, or plots of current performance indicators for real-time processes that are being monitored.

This is similar to question [Update graph/plot with fixed interval of time] (Update graph/plot with fixed interval of time) which runs a loop with a timer. Extending that approach, my objective is to: a) Automatically set the invalidateLater pause high (1 hour) to effectively stop the cycle after a fixed (5) set of displays, pending new user input to restart it.

b) [When I can do that, I will add a counter-based control to cycle through a set of input$obs before it stops. For simplicity, that step, which has the same error and presumably same solution, is omitted here.]

Using the above referenced toy example, the following script does repeatedly cycle through its 5 displays, but it yields this error rather than changing the pause interval.

Listening on port 8100 Error in hist.default(dist, main = paste("Last Histogram count =", as.numeric(updater()), : 'x' must be numeric

as.numeric(autoControl()) Error: could not find function "autoControl"

I can not find the reactive conductor, reactiveValues or other methods that this task requires. Thank you for your help.

library(shiny)

updates <- 0
updater <- function(){ updates + 1 }

runApp(list(
  ui = pageWithSidebar(    

  headerPanel("Hello Shiny!"),

  sidebarPanel(
    sliderInput("obs", 
      "Number of observations:", 
      min = 1,
      max = 1000, 
      value = 50)
    ,

    selectInput(inputId = "secPause",
        label = "Seconds between displays:",
        choices = c(1, 2, 3, 60*60),
        selected = 2)
  ),

  mainPanel(
    plotOutput("distPlot")
  )
),

  server =function(input, output, session) {
        updateTracker <- reactive( { 
            invalidateLater(as.numeric(input$secPause) * 1000, session)
            updates <<- as.numeric(updater())
        })

        autoControl <- reactive( {
            if(updateTracker() <= 5)
            secPause <<- input$secPause
                    else
                    secPause <<- 60*60
            return(secPause)
        })

    output$distPlot <- renderPlot( {
        if(updateTracker() <= 5) {
        # generate an rnorm distribution and plot it
        dist <- rnorm(input$obs)
        hist(dist, main = paste("Histogram count =" , updateTracker()))
        }
        else {
            updates <<- 0
            hist(dist, main = paste("Last Histogram count =", 
              as.numeric(updater()), "with secPause =", 
              as.numeric(autoControl())))
                }
    })
    }
))
Community
  • 1
  • 1

1 Answers1

1

You are getting the error because the hist distribution is defined inside the if clause, but you are using it (after 5 intervals) inside the else clause, where it is not defined. That's why it works for the first 5 intervals.

   if(updateTracker() <= 5) {
        # generate an rnorm distribution and plot it
        dist <- rnorm(input$obs)
        hist(dist, main = paste("Histogram count =" , updateTracker()))
        }
        else {
            updates <<- 0
            hist(dist, main = paste("Last Histogram count =", 
              as.numeric(updater()), "with secPause =", 
              as.numeric(autoControl())))
                }

After I moved the dist to before the if condition, I got your cycling to work. (I also split your code into UI.R and server.R to make it more manageable.) Not pasting here since it is essentially the same code, but you can find the working version of code in this gist.

Ram Narasimhan
  • 22,341
  • 5
  • 49
  • 55
  • Ram’s revision helped me get past the error display and make some more, minor changes. The revised coed is here: https://gist.github.com/tomjohn/6480507 The last part of the objective remains undone -- for “new user input to restart it.” The automated cycle of 5 displays should restart when either UI input (obs or secPause) is changed. However, only 1 histogram is shown each time obs is changed, and the short pause of the reactive source input$secPause stays inactive. Any suggestions please? – user1968332 Sep 07 '13 at 23:46
  • The code in gist now performs the objectives set out above. https://gist.github.com/tomjohn/6480507 Though invalidateLater() remains set at the specified longPause interval and is not reactive to inputs during that pause, the inputs are fully reactive once the time interval passes. By shortening the longPause to, say, 10 seconds from 1 hour, the automated cycle can be set to start after a desired wait time. The question of how to “wake” it from the longPause remains unanswered, but is obviated since one can set the longPause to a fixed interval for interaction suited to user preference. – user1968332 Sep 16 '13 at 22:07