Windows of Reactivity

rstudio::conf(2022)
Building Production-Quality Shiny Applications

Eric Nantz

Default Perspective

Default Perspective

selectInput(
  "dept",
  "Select Department",
  choices = dept_choices,
  selected = dept_choices[1],
  multiple = FALSE
)
output$top_objects <- renderPlot({
  df <- art_data |>
    filter(department == input$dept)
  
  # more data processing ....
  
  ggplot(df, aes(x = name, y = n)) +
    geom_col() +
    xlab(NULL) +
    ylab("Frequency of Annotation") +
    ggtitle("Top 5 Objects Annotated")
})

Default Perspecive

reactive input: input$dept

output: output$top_objects

The beginning (and end) of a typical Shiny interaction

  • Can this approach scale to multiple inputs?

Default Perspective

Default Perspective

selectInput(
  "dept",
  "Select Department",
  choices = dept_choices,
  selected = dept_choices[1],
  multiple = FALSE
)

sliderInput(
  "n_top",
  "Top Annotations",
  min = 1,
  max = 10,
  value = 5,
  step = 1
)
output$top_objects <- renderPlot({
  df <- art_data |>
    filter(department == input$dept)
  
  df2 <- df |>
    # more data processing 
    # using input$n_top
  
  ggplot(df2, aes(x = name, y = n)) +
    geom_col() +
    xlab(NULL) +
    ylab("Frequency of Annotation")
})

Your Turn: Exercise 1

Open the application in ex-1/app.R and see if you can improve the reactivity flow in the next 5 minutes. View more details at the Exercise 1 page.

05:00

The Middle

reactive expressions

The Building Blocks of Reactivity

The sources used in downstream endpoints

  • Not only the classic input widgets within your UI

Intermediate bridges between sources and endpoints.

  • Both consume and produce

Consumers of one or more sources.

  • Goal is to produce a side-effect

Your Turn: Exercise 2

Open the application in ex-2/app.R which has 2 inputs that drive the visualization. See if you can optimize the reactive calculations in the next 5 minutes.

05:00

Demo Time!

Reactive

Observer

Reactive

  • Use for calculations
  • Lazy
  • Cached
  • Returns a value
  • Absolutely no side effects

Observer

  • Use for side effects
  • Very eager
  • Forgetful (no caching)
  • No return value
  • Only for side effects

Isn’t Lazy a ….

When constructing a Shiny app, lazy is not a bad thing for reactives!

  • Only preform calculations when absolutely necessary
  • Intentional design will reward you with efficient performance

Those Troublesome Observers

  • Observers may cause reactive chaos in your app
  • But with a little control, they can be just as valuable

Joe Cheng at Shiny Dev Con 2016

Event-driven Processing

observeEvent ensures processing only happens based on a single trigger

  • Button click
  • Updated reactive expression
  • Updated reactiveValues or reactiveVal

Inputs from the Server

  • Users typically drive processing through the Shiny UI
  • Sometimes you need to create a dynamic version that can be updated within the server-side logic
  • The MVPs: reactiveValues and reactiveVal

Inputs from the Server

server <- function(input, output, session) {
  rv <- reactiveValues(x = 0)
  rv2 <- reactiveVal(0)
  
  observeEvent(input$btn, {
    rv$x <- rv$x + 1
    rv2(rv2() + 1)
  })
}

Code-Along

Code-Along 1: Building the MET image viewer foundation

More from the Reactivity Bank

Additional Resources