10.3 Reactivity

There is one final hurdle to understanding Shiny at an intermediate level. For the entirety of this course, and probably of your programming career the code you have written has been run sequentially. You start a script, load the library, load the data, execute the functions, and return the result. There’s never any chance for code to be run out of order because it is only designed to go in one direction. The style of programming we are used to is called imperative programming.

Unfortunately, Shiny not only runs out of order, but can be run multiple times. A user can start the app, trigger one function to run, and then click a button and change the data entirely. Our applications need to be flexible enough to handle this situation, but if we were to write it in the way we were used to then a user would be left looking out outdated results.

Enter declarative programming, or reactivity.

Reactivity is the idea that our code can react when changes are made to its inputs. This is perfect for R Shiny since our users are constantly getting in our way and changing inputs left and right (it’s okay we want them to do this). Imperative programming is telling your software to go and make you a sandwich. It will follow the prescribed instructions and make the same sandwich every time. We ask our reactive program, Shiny, to make sure there is a sandwich whenever we open the fridge, and maybe change the sandwich whenever we move our sandwich slider.

R Shiny has a lot of different levels of reactivity, but we’ll be using one cool idea which is the reactive expression.

Say I have an application that reads in a CSV of rainfall data and spits our a graph along with some statistics. I load my data and calculate the mean raininess over the last week or what have you. Next, I load in my data again and I run ggplot to plot a histogram of number of toads rained in a certain zip code.

With what we have learned in Shiny so far, I can only do these processes separately, once in each output$x <- section. Not only does this mean I need to write my uploading multiple times, I also need to parse the data more than once. It may be trivial for my rainfall data that spans two rows, but if your application needs to parse a lot of data then all of sudden your user is stuck looking at blank results and the angry emails will just pour into your inbox (with or without toads).

To solve this, in a Shiny way, we use a reactive expression. This is somewhat like a function that runs every time an input changes. The best part is that the results are cached, meaning they aren’t re-run unless they absolutely must be. This means I can load the data once and plot and process it without loading anything again.

server <- function(input, output, session) {
  dataset <- reactive({
    read.csv(input$data$datapath, header = TRUE)
  })

  output$plot <- renderPlot({
    ggplot(dataset(), aes(x = Toads, y = cm_rain_week))
  })

  output$stats <- renderTable({
    csv <- dataset()
    data.frame(mean = mean(csv$Toads))
  })
}

Reactivity can be used to control the flow of data and actions through your application. You can stop a plot from updating until a button is pressed, or ensure your user doesn’t see errors by waiting until every input is selected until progressing.

I don’t think you could teach a whole class on reactivity in Shiny but maybe a little more than one or two lectures.