modify in place within shiny app

I have a shiny app which would like to use reactiveFileReader to dynamically update a data store. Ideally, the new data would be appended to old data, but when I make the assignment within the app, I get the following error:

Error: C stack usage 7970144 is too close to the limit

Here's a (failing) reprex; note that the reactive the_time() is getting invalidated in order to simulate some new incoming data in lieu of reactiveFileReader. A functioning app would append times to an ever growing table every second.

library(shiny)
# DOESN"T WORK

# The UI
ui <- fluidPage( tableOutput("timeTable")   )

server <- function(input, output, session) {
    
    time_accum <- reactive( data.frame(time = NULL) )
    
    ## the_time is a drop in replacement for reactiveFileReeader for this reprex
    the_time <- reactive({
        invalidateLater(1000, session)
        data.frame(time = as.character(Sys.time()))
    })
    
    ## the key step, which seems to be the fail point
    time_accum <- reactive( bind_rows(time_accum(), the_time()) )

    output$timeTable <- renderTable( time_accum() )
}

# Run the app
shinyApp(ui = ui, server = server)

Incidentally, below is a version that updates the time, but doesn't accumulate the old values, in case this version is somehow helpful. thanks in advance for any help

library(shiny)

ui <- fluidPage( tableOutput("timeTable")   )

server <- function(input, output, session) {
    
    time_accum <- reactive( data.frame(time = NULL) )
    
    ## the_time is a drop in replacement for reactiveFileReeader for this reprex
    the_time <- reactive({
        invalidateLater(1000, session)
        data.frame(time = as.character(Sys.time()))
    })
    
    ## the key step, which seems to be the fail point
    #time_accum <- reactive( bind_rows(time_accum(), the_time()) )

    output$timeTable <- renderTable( the_time() )
}
shinyApp(ui = ui, server = server)

Hi @cawthm. The script loop so deep and complicate. I clean up some and see if the script is what you wanted.

library(shiny)
library(tidyverse)
# DOESN"T WORK

# The UI
ui <- fluidPage( tableOutput("timeTable")   )

server <- function(input, output, session) {
  
  vals <- reactiveValues( time_accum = data.frame(time = NULL) )
  
  ## the_time is a drop in replacement for reactiveFileReeader for this reprex
  the_time <- reactive({
    invalidateLater(1000, session)
    data.frame(time = as.character(Sys.time()))
  })
  
  ## the key step, which seems to be the fail point
  observe(
    {
      time <- the_time()
      isolate(vals$time_accum <- bind_rows(vals$time_accum, time))
    }
  )
  
  # vals$time_accum <- reactive( bind_rows(vals$time_accum, the_time()) )
  
  output$timeTable <- renderTable( vals$time_accum )
}

# Run the app
shinyApp(ui = ui, server = server)
2 Likes

This works; thank you @raytong. I will mark it as the solution within the next 24 hours.

Still, I'd like to understand why it is necessary to use the reactiveValues construct. What can't we just create a create a reactive df and update that object, like so below? (this also fails, but I can see that it is performing the row_bind. it just doesn't get updated in the renderTable):

library(shiny)
library(tidyverse)

ui <- fluidPage( tableOutput("timeTable")   )

server <- function(input, output, session) {
    
    #vals <- reactiveValues( time_accum = data.frame(time = NULL) )
    
    time_accum <- reactive({ data.frame(time = as.character(Sys.time())) })
    
    ## the_time is a drop in replacement for reactiveFileReeader for this reprex
    the_time <- reactive({
        invalidateLater(1000, session)
        data.frame(time = as.character(Sys.time()))
    })
    
    observe({
            time <- the_time()
            
            isolate( time_accum <-  bind_rows(time_accum(), time) )
        })
    
     #vals$time_accum <- reactive( bind_rows(vals$time_accum, the_time()) )
    
    output$timeTable <- renderTable( time_accum() )
}

shinyApp(ui = ui, server = server)

Hi @cawthm. reactive is used to defined an expression that mean it can only give out a value according to the values inside the expression.

  the_time <- reactive({
    invalidateLater(1000, session)
    data.frame(time = as.character(Sys.time()))
  })

But it cannot assign a value to it. So, the script will not work.

time_accum <-  bind_rows(time_accum(), time)

If you want to store a value, you have to use reactiveVal or reactiveValues. Using reactiveValues is my habit because it can store values like normal list object. You can use reactiveVal in your case but the readability of the script will be lower.

library(shiny)
library(tidyverse)
# DOESN"T WORK

# The UI
ui <- fluidPage( tableOutput("timeTable")   )

server <- function(input, output, session) {
  
  time_accum <- reactiveVal(data.frame(time = NULL) )
  
  ## the_time is a drop in replacement for reactiveFileReeader for this reprex
  the_time <- reactive({
    invalidateLater(1000, session)
    data.frame(time = as.character(Sys.time()))
  })
  
  ## the key step, which seems to be the fail point
  observe(
    {
      time <- the_time()
      isolate(time_accum(bind_rows(time_accum(), time)))
    }
  )
  
  # vals$time_accum <- reactive( bind_rows(vals$time_accum, the_time()) )
  
  output$timeTable <- renderTable( time_accum() )
}

# Run the app
shinyApp(ui = ui, server = server)
1 Like

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.