"Forcing" a reactive to rerun

2,094 views
Skip to first unread message

Anders Carlsson

unread,
Jun 8, 2016, 2:31:15 PM6/8/16
to Shiny - Web Framework for R
Hi all,

In the app I'm working on, I have a 'reactive' (r) that pulls data from a data base which is used in multiple places in the app. I also have an 'observeEvent' (o) that updates the database upon clicking an action button. I want to have a functionality that, once updating the database by clicking the action button, the first reactive statement is immediately updated so that a plot that is plotting the data from the database is refreshed.

Since the data is in a database the reactive isn't refreshed automatically. So, is there a way to have the reactive refresh right after my observe event has executed?

Simplified:

Button click -> (o) sends data to database -> (r) -> pulls data from database -> plot is refreshed.

Thanks!


Joe Cheng

unread,
Jun 8, 2016, 2:34:59 PM6/8/16
to Anders Carlsson, Shiny - Web Framework for R
Is there anything else reactive going on in that reactive expression? If not, you can use eventReactive to make it react to the button click itself. If so, then you can add a reference to input$button (or whatever) to the beginning of the reactive.

You may need to set a priority on (o) (it's one of the available parameters, see ?observeEvent) to guarantee that the "sends data to database" always happens before anybody else does anything to respond to the button click.

--
You received this message because you are subscribed to the Google Groups "Shiny - Web Framework for R" group.
To unsubscribe from this group and stop receiving emails from it, send an email to shiny-discus...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/shiny-discuss/909c1860-0c88-4c57-8e7d-8ef53c361632%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Anders Carlsson

unread,
Jun 8, 2016, 2:55:00 PM6/8/16
to Shiny - Web Framework for R, nian...@gmail.com
Thanks for responding.

Yes, the reactive is also reactive to an other input.

I now reference the action button in the reactive and set a priority for the observerEvent, but the plot pulling data from the reactive is only updated if I click the action button a second time. I also tried to reference the action button in the renderPlot, but that didn't change the behavior.

I also see that even if I reference the action button in the reactive, the data frame that is generated from the database call within it isn't updated (until the second time I click the same button). 

Thanks again.

Anders Carlsson

unread,
Jun 8, 2016, 3:19:55 PM6/8/16
to Shiny - Web Framework for R, nian...@gmail.com
Please take a look at this simplified part of the app. 

In essence, the plot shows a number of events. Some of them are stored in a database table, others are not. In the plot, it is possible to see, by color, which events that are not in the database. Using brushedPoints in the plot, the user can select events and submit them to the database using the button. I want everything to update once the button has been clicked, so that the events for example change color in the plot to reflect that they are now in the database. Right now, with code similar to the below, this only happens if I click the buttons twice.

# plot all events, both in and not in database. Selected events should be added in database upon button click, and plot updated to reflect that  
  output$plot <- renderPlot({
data = cell_info()$cell_data
    ggplot(data, aes(... , col = in_database)
})
  
cell_info <- reactive({ 
input$submit_new_cells #actionButton
# input to select case
case = input$case 
# database call
# ...
cell_data <- fetch(results, n=-1) 
return(cell_data)
})

# select new events in plot to submit to database
new_hits = reactive({
    new <- brushedPoints(cell_info()$cell_data, input$plot1_brush)
    return(new)
  })

 # write new events to database
observeEvent(input$submit_new_cells, {
    dbWriteTable( ... subset(new_hits(), in_database == FALSE ), ...)
  })

Anders Carlsson

unread,
Jun 8, 2016, 4:40:18 PM6/8/16
to Shiny - Web Framework for R, nian...@gmail.com
OK, seems like since the reactive is used two times in the "cascade", it isn't updated again the second time it's used, after which the database has been altered. I therefore have to do a new database call in the renderPlot to get the latest version of the database there, instead of referring to the reactive that has outdated content at the time of plotting. Works fine, although a little bit ugly.

Thanks.

Joe Cheng

unread,
Jun 8, 2016, 7:25:06 PM6/8/16
to Anders Carlsson, Shiny - Web Framework for R
So the problem here looks like it's because new_hits() and cell_info() are called *during* the observeEvent. That's causing those to evaluate and thus become "up-to-date"--they will cache their results until they think they're no longer up-to-date. The state that we truly care about is in the database, and that's not inherently reactive, so new_hits/cell_info think they're still up-to-date when accessed by renderPlot.

One workaround for this is to have a reactive value serve as a stand-in for the database's state.

# plot all events, both in and not in database. Selected events should be added in database upon button click, and plot updated to reflect that  
  output$plot <- renderPlot({
data = cell_info()$cell_data
    ggplot(data, aes(... , col = in_database)
})

rv <- reactiveValues(dbVersion = 0)
  
cell_info <- reactive({ 
# Removed input$submit_new_calls
rv$dbVersion
# input to select case
case = input$case 
# database call
# ...
cell_data <- fetch(results, n=-1) 
return(cell_data)
})

# select new events in plot to submit to database
new_hits = reactive({
    new <- brushedPoints(cell_info()$cell_data, input$plot1_brush)
    return(new)
  })

 # write new events to database
observeEvent(input$submit_new_cells, {
    dbWriteTable( ... subset(new_hits(), in_database == FALSE ), ...)
    rv$dbVersion <- isolate(rv$dbVersion + 1)
  })

This admittedly feels a little hacky, sorry; but hopefully it's not terribly surprising that you might need to get a little hacky to build bridges between the reactive and non-reactive worlds.

Reply all
Reply to author
Forward
0 new messages