10  Reactive Programming

Author
Affiliation

Dr Randy Johnson

Hood College

Published

February 5, 2025

Introduction to Shiny

  • A framework for creating web apps using R

  • No HTML/CSS/JS required (but you can use them if you want!)

  • ui: The front-end (what the user sees)

  • server: The back-end (the R logic)

ui <- fluidPage(
  # front end interface
)

server <- function(input, output, session) {
  # back end logic
}

shinyApp(ui, server)

Hello, Shiny!

Try running the following code in R:

library(shiny)

ui <- fluidPage(
  "Hello, world!"
)

server <- function(input, output, session) {
}

shinyApp(ui, server)

Basic UI: Inputs & Outputs

  • In this section, we’ll focus on the UI components of a Shiny app

UI Inputs

  • Each input typically has
    • inputID: internal name, must be unique and follow R variable naming conventions
    • label: visible text
  • Different types of inputs:

    • Free Text: textInput(), textAreaInput()

    • Numbers: numericInput(), sliderInput().

    • Choices: selectInput(), radioButtons(), checkboxGroupInput().

UI Outputs

  • Outputs are placeholders in the UI

  • Every Output() in the UI must have a corresponding render() in the server.

    • textOutput()renderText()

    • tableOutput()renderTable()

    • plotOutput()renderPlot()

Layouts

  • fluidPage() manages the responsive layout

    • Use sidebarLayout() for a common sidebar + main content structure

Basic UI Example

The following is an example of a simple UI that includes a slider input and a plot output:

# Old Faithful Geyser Data UI (see https://shiny.posit.co/r/gallery/start-simple/faithful/)
# Define UI for application that draws a histogram
ui <- fluidPage(

    # Application title
    titlePanel("Old Faithful Geyser Data"),

    # Sidebar with a slider input for number of bins 
    sidebarLayout(
        sidebarPanel(
            sliderInput("bins",
                        "Number of bins:",
                        min = 1,
                        max = 50,
                        value = 30)
        ),

        # Show a plot of the generated distribution
        mainPanel(
           plotOutput("distPlot")
        )
    )
)

Basic Reactivity

  • In this section we will introduce reactivity
  • Reactivity is what makes Shiny apps dynamic and interactive

The Server Function

  • Three arguments:

    • input: A list-like object, Read-only

    • output: A list-like object, Write-only

    • session: An environment for managing user sessions (R handles this in the background)

Declarative vs. Imperative

  • Imperative (Normal R): “Take X, do Y, save as Z

  • Declarative (Shiny): “This is the recipe for Z. Update it whenever the ingredients change.”

The Reactive Graph

  • A reactive graph is a network of dependencies

  • For example, when output$y depends on input$x:

    • output$y <- renderText({ paste("You selected", input$x) })

    • When input$x changes, output$y will be updated

  • A reactive graph can be a helpful tool to visualize and debug dependencies

Reactive Expressions (reactive())

  • To avoid duplicated code or minimize expensive calculations

  • Use reactive({...}) to create a cached calculation

  • We call a reactive expression like a function to retrieve the object: my_data()

Example of duplicate code from section 3.4.2 of Wickham (2021):

server <- function(input, output, session) {
  output$hist <- renderPlot({
    x1 <- rnorm(input$n1, input$mean1, input$sd1)
    x2 <- rnorm(input$n2, input$mean2, input$sd2)

    freqpoly(x1, x2, binwidth = input$binwidth, xlim = input$range)
  }, res = 96)

  output$ttest <- renderText({
    x1 <- rnorm(input$n1, input$mean1, input$sd1)
    x2 <- rnorm(input$n2, input$mean2, input$sd2)

    t_test(x1, x2)
  })
}

Reactive Expressions (reactive())

Simplified with reactive():

server <- function(input, output, session) {
  x1 <- reactive(rnorm(input$n1, input$mean1, input$sd1))
  x2 <- reactive(rnorm(input$n2, input$mean2, input$sd2))

  output$hist <- renderPlot({
    freqpoly(x1(), x2(), binwidth = input$binwidth, xlim = input$range)
  }, res = 96)

  output$ttest <- renderText({
    t_test(x1(), x2())
  })
}

Basic Server Example

This server code complements the UI example from above:

# Old Faithful Geyser Data Server (see https://shiny.posit.co/r/gallery/start-simple/faithful/)
# Define server logic required to draw a histogram
server <- function(input, output) {

    output$distPlot <- renderPlot({
        # generate bins based on input$bins from ui.R
        x    <- faithful[, 2]
        bins <- seq(min(x), max(x), length.out = input$bins + 1)

        # draw the histogram with the specified number of bins
        hist(x, breaks = bins, col = 'darkgray', border = 'white',
             xlab = 'Waiting time to next eruption (in mins)',
             main = 'Histogram of waiting times')
    })
}

Copy and paste the UI and server examples into R along with this code to run the complete app:

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

References

Wickham, Hadley. 2021. Mastering Shiny: Build Interactive Apps, Reports, and Dashboards Powered by R. First edition. Beijing Boston Farnham Sebastopol Tokyo: O’Reilly.