Shiny from scratch

R
intermediate
Shiny
Published

February 13, 2025

Session materials

Welcome

  • this is an 🌶🌶 intermediate-level practical session designed for those with prior R experience, but who are new to Shiny
  • it’s definitely meant to be a taster session, rather than a comprehensive introduction
  • we’ll concentrate on the Shiny-specific material here, and assume that you’re generally familiar with ordinary R

Session outline

  • What’s the point of Shiny?
  • Key resources
  • "hello world!"
  • Adding R code
  • Capturing user input
  • Thinking about reactivity

What’s the point of Shiny?

Key resources

  • you’ll need:

Boilerplate Shiny code

  • start a new R script in an empty project
  • save as app.R (conventional, but helpful)
  • start typing shiny, and select the shinyapp snippet to insert the boilerplate Shiny code
    boilerplate Shiny code

3 sections

  • ui, where you’ll build your user interface
  • server, where you’ll put the bulk of your R code
  • shinyApp, which collects the ui and server, and runs your Shiny server

"hello world!"

  • now add "hello world!" in the ui
    add “hello world!” in the ui
  • Ctrl + Shift + Enter to run your code - or use the run app button run app button
  • that should start your Shiny app - and you should see “hello world!” in the viewer pane “Hello world!”
  • Press stop Press stop - or hit Esc to stop your app. You’ll need to stop and restart to see changes.

Adding R code

  • now we’ll add some simple R code to our server. That’s going to do something simple with mtcars:
mtcars |>
  dplyr::group_by(cyl) |>
  dplyr::summarise(mpg = round(mean(mpg), 2))
# A tibble: 3 × 2
    cyl   mpg
  <dbl> <dbl>
1     4  26.7
2     6  19.7
3     8  15.1

renderTable, output$, and tableOutput

  • if we run our Shiny dashboard now, we won’t see any output from this new R code
  • we’ll need to add three new elements to make the code work
  1. wrap our mtcars code in the renderTable function in server
  2. assign that renderTable to a variable called output$my_table
  3. finally, replace your "hello world!" in the ui with tableOutput("my_table")

Your code should now read:

library(shiny)

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

server <- function(input, output, session) {
  output$my_table <- renderTable(mtcars |>
                dplyr::group_by(cyl) |>
                dplyr::summarise(mpg = round(mean(mpg), 2)))
}

shinyApp(ui, server)

Run it (Ctrl + Shift + Enter) and you should see a table of mtcars data in the viewer pane:
table of mtcars data in the viewer pane

What’s going on with renderX etc?

  • there are pairs of functions on the Shiny cheatsheet. Each output type has its own renderX function, which you use in the server to wrap other kinds of output. So renderPlot collects plot/ggplot output etc.

  • once your output has been rendered, you then save it into a list variable called output. Each bit of output needs its own variable name - like output$my_table

  • finally, and again from the Shiny cheatsheet, you extract your data inside the UI from the output$ variable by using an XOutput function that corresponds to your renderX

Capturing user input

  • we need to add three elements to capture user input:
  1. add an input widget - like radioButtons() above your tableOutput in the UI. You’ll need to comma-splice that - all your UI contents gets joined with commas
  2. then add an input ID to that input widget radioButtons("my_input", "Which gear to show?", sort(unique(mtcars$gear)))
  3. finally, you connect your user input into your code using input$my_input
ui <- fluidPage(
  radioButtons("my_input", "Which gear to show?", sort(unique(mtcars$gear))),
  tableOutput("my_table")
)

server <- function(input, output, session) {
  output$my_table <- renderTable(mtcars |>
                dplyr::filter(gear == input$my_input) |>
                dplyr::group_by(cyl) |>
                dplyr::summarise(mpg = round(mean(mpg), 2)))
}

Thinking about reactivity

  • all this extra work is needed to allow Shiny to run reactive code: code that responds to user input by producing different outputs
  • that’s a big difference from standard, declarative, R code
  • one helpful tool for understanding reactivity: reactlog

Reactlog

  • run install.packages("reactlog")
  • then add library(reactlog) to the start of your Shiny script to attach the package
  • then follow that with reactlog_enable() to start logging
  • now launch your dashboard, interact with it a couple of times, and then press Ctrl + F3
  • that should bring up a new webpage showing you the reactive graph of your Shiny app
    Reactive graph
  • conveniently, Mastering Shiny uses the same visual style to explain the reactive graph as reactlog