Alex Petralia
Alex Petralia

Reputation: 1770

R Shiny: Updating .csv input on a schedule

I have a .csv that auto-updates every minute with new data. I'd like to have R Shiny reupdate every hour with this new dataset.

From everything I've seen, this will involve invalidateLater or autoInvalidate; however, I'm not sure how to get these working (or more importantly, where to put them).

ui.R is pretty straightforward so I won't include it. server.R is below:

library(ggplot2)
library(reshape2)
library(scales)

# data <- reactive({ # data refresh once a day # 86400000ms is 1 day  
#   invalidateLater(10000, session) # 10s to test
# })

shinyServer(function(input, output, session) {

  autoInvalidate <- reactiveTimer(10000, session)

  observe({
    x <- read.csv("wait_times.csv", header=T, stringsAsFactors=FALSE)
    x <- rename(x, c("Fall.River" = "Fall River", "Martha.s.Vineyard" = "Martha's Vineyard", "New.Bedford" = "New Bedford", "North.Adams" = "North Adams", "South.Yarmouth" = "South Yarmouth"))
    cities <- colnames(x)[-1]

    x[x == 999] <- NA

    x_long <- melt(x, id.var="timestamp") ### does not work after Attleboro ###
    x_long <- rename(x_long, c("variable" = "city", "value" = "wait_time"))
    x_long$timestamp <- strptime(x_long$timestamp, "%d/%m/%Y %H:%M %p")

    weeks <- as.double(difftime(x_long$timestamp[1], x_long$timestamp[length(x_long$timestamp)], units = "weeks")) + 1

    print("REFRESHING CSV!")
    autoInvalidate()
  })

  # pass server-side code into initial UI page
  output$cities <- renderUI({
    checkboxGroupInput("cities", 
                       label = h3("Which cities to view?"),
                       as.list(cities),
                       selected = "Boston")
  })

  output$weeks <- renderUI({
    sliderInput("weeks", 
                label = h3("How many prior weeks to average?"),
                min = 1,
                max = weeks,
                step = 1,
                value = 1)
  })

  output$main <- renderPlot({

    x_output <- x_long[x_long$city == input$cities, ]
    p <- ggplot(x_output, aes(x=timestamp, y=wait_time, group=city)) + geom_line(aes(color=city), size=1.5) + scale_x_datetime(breaks = date_breaks("10 min")) + theme(axis.text.x = element_text(angle = 90, hjust=1), legend.position = "bottom") + labs(x=NULL, y="Waiting time (minutes)")
    print(p)

  })

})

When I pull out certain values from the .csv (like "weeks" and "cities"), R Shiny says they don't exist:

Error in as.list(cities) : object 'cities' not found
Error in sliderInput("weeks", label = h3("How many prior weeks to average?"),  : 
  object 'weeks' not found
Error in func() : object 'x_long' not found

What I think is happening is that since these are being declared inside the observe function, they are encapsulated by it. Perhaps I should be invalidating/declaring these earlier? I've tried putting them before declaring shinyServer() but that hasnt' seemed to work either.

I've researched these sources but haven't been able to replicate:

Upvotes: 0

Views: 2073

Answers (1)

sechstein
sechstein

Reputation: 306

observe doesn't return a value (it returns an observer reference class). You want to use reactive instead.

If you wanted only the variable cities for exemple, you could do it like this:

refrehed_cities <- reactive({
    autoInvalidate()

    x <- read.csv("wait_times.csv", header=T, stringsAsFactors=FALSE)
    x <- rename(x, c("Fall.River" = "Fall River", "Martha.s.Vineyard" = "Martha's Vineyard", "New.Bedford" = "New Bedford", "North.Adams" = "North Adams", "South.Yarmouth" = "South Yarmouth"))
    cities <- colnames(x)[-1]
    return cities
)}

and then use it in checkboxGroupInput:

output$cities <- renderUI({
     checkboxGroupInput("cities", 
                       label = h3("Which cities to view?"),
                       as.list(refreshed_cities()),
                       selected = "Boston")
    })
})

An other way to do it would be to use the function reactiveValues, which enables you to store reactive values.

Upvotes: 3

Related Questions