21

I have a plot in Shiny UI. If I change any input parameter and through reactivity plot will change. But let's consider following situation:- The plot in Shiny UI plotting let say intra-day price move of a stock. And for that you query some live data source. Now If I create a refresh button and then if time passes by I keep on clicking on refresh button. The plot will be updated as new data arrives as time goes into that live data source. Now my question is I don't want to keep clicking on refresh button. But I want to run a loop with timer so that it will check over a fixed interval of time and as soon as new data comes the plot will auto update. Something sort of Google Finance Graphs which keeps updating over time.

So the problem can be simplified as follows :- Let's consider this example from Shiny itself :- ui.R

library(shiny)    

shinyUI(pageWithSidebar(    

  headerPanel("Hello Shiny!"),

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

  mainPanel(
    plotOutput("distPlot")
  )
))

and server.R

library(shiny)

shinyServer(function(input, output) {

  output$distPlot <- renderPlot({

    # generate an rnorm distribution and plot it
    dist <- rnorm(input$obs)
    hist(dist)
  })

})

Now I want to generate a different random sample from normal distribution without any input activity. So basically I want to call

dist <- rnorm(input$obs)
hist(dist)

again without changing sliderInput. Please help me find out how to do that.

zx8754
  • 52,746
  • 12
  • 114
  • 209
Indranil Gayen
  • 702
  • 1
  • 4
  • 17
  • You can use a `reactiveTimer`. See `?reactiveTimer` – jdharrison Aug 18 '13 at 18:56
  • I think you're looking for `invalidateLater` – GSee Aug 18 '13 at 20:10
  • 1
    Yeah both invalidateLater and reactiveTimer serves my purpose.. Only thing is that invalidateLater has to be implemented inside a reactive environment while reactiveTimer is to create reactive source [just repeating the fact for clarification]. I'm new in R Shiny that's why it took me little long time. – Indranil Gayen Aug 19 '13 at 17:20

2 Answers2

24

As an example you can run the following locally:

library(shiny)

runApp(list(
  ui = pageWithSidebar(    

  headerPanel("Hello Shiny!"),

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

  mainPanel(
    plotOutput("distPlot")
  )
),
  server =function(input, output, session) {
    autoInvalidate <- reactiveTimer(5000, session)
    output$distPlot <- renderPlot({
      autoInvalidate()
      # generate an rnorm distribution and plot it
      dist <- rnorm(input$obs)
      hist(dist)
    })

  }
))

A different normal sample will be generated every 5 seconds

Mathias711
  • 6,568
  • 4
  • 41
  • 58
jdharrison
  • 30,085
  • 4
  • 77
  • 89
1

This can also be solved using reactivePoll. The code is a lot simpler. it has also the advantage that you can use a check-function that does not necessarily invalidate the reactive expression because time has passed. You are able to write less resource-demanding code that way.

The sample, however, uses only Sys.tim() as check function. Since Sys.time() will be different every time it is called, the check function ALWAYS indicates that an update is necessary.

library(shiny)

runApp(list(
  ui = pageWithSidebar(

    headerPanel("Hello Shiny!"),

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

    mainPanel(
      plotOutput("distPlot")
    )
  ),
  server = function(input, output, session) {
    dist <- reactivePoll(5000, session, function () Sys.time(), function () {
      rnorm(input$obs)
    })

    output$distPlot <- renderPlot({
      hist( req(dist()) )
    })
  }
))
Jan
  • 4,974
  • 3
  • 26
  • 43