2 The Structure of a Shiny App

A Shiny app consists of two parts, a user interface (ui) and an R session that runs code and returns results (server).

These two parts can be in their own files called ui.R and server.R, or they can be combined into a single file called app.R. The examples in this article will show a preference for a single app.R file for its simplicity.

After reviewing the structure of an app.R file, we will explore how to receive user input (Inputs), extract values from that input and return values and plots (Outputs), deal with data objects whose values can change (Reactivity), return helpful error messages to app users (Error Messages), and customize the layout of our Shiny apps (Layouts).

The basic Shiny app follows this structure:

library(shiny)

ui <- 
  fluidPage(

  )

server <- 
  function(input, output) {
    
  }

shinyApp(ui = ui, server = server)

And if we add some comments about what goes where:

# 1. Load libraries and read in data
library(shiny)
# load other packages
# read in data files

# 2. Create inputs and outputs, customize the appearance
ui <- 
  fluidPage(
    # *Input() functions
    # *Output() functions
    # *Layout() functions, *Panel() functions, HTML tags
  )

# 3. Run commands that return values to outputs
server <- 
  function(input, output) {
    # render*() functions with R expressions inside
    # reactive() expressions
  }

# 4. Tell Shiny this is an app
shinyApp(ui = ui, server = server)

We can look at the code for the example1 app to see these parts:

library(shiny)

ui <- 
  fluidPage(
    selectInput(
      inputId = "xvar",
      label = "Pick a variable for the x-axis:",
      choices = c("wt", "hp"),
      selected = "wt"
    ),
    
    plotOutput(outputId = "myPlot")
  )

server <- 
  function(input, output) {
    output$myPlot <- 
      renderPlot({
        plot(mtcars[, input$xvar], mtcars$mpg)
      })
  }

shinyApp(ui = ui, server = server, options = list(display.mode = "showcase"))

The only library needed for this app in addition to R’s default packages is shiny, and no data files are read in since this app uses mtcars.

Next, our ui consists of a fluidPage() (a webpage that auto-scales its content) with one input and one output. selectInput() calls its value as xvar, displays the text “Pick a variable for the x-axis:”, provides two choices, and has one these values selected by default. Our output is specified by plotOutput() as myPlot, which we will create and return in server.

In server, we create the plot that we return to plotOutput() in ui. The plot is made with renderPlot(). Note that we get xvar from selectInput() with input$xvar in mtcars[, input$xvar]. It was placed in a list called input for us, and we access the list with input$inputId. In a similar fashion, the plot we create is named output$myPlot, which plotOutput() accesses as simply myPlot. (It is precisely because of this non-linear processing of our script, from ui to server and back again, that I prefer using a single app.R file instead of splitting it across ui.R and server.R.)

We then declare that this app is indeed an app with shinyApp(). The last bit of code inside shinyApp(), options = list(display.mode = "showcase"), makes it so that the source file appears alongside the UI.

We can think of ui and server as the front and back of a fast food restaurant. The ui is like the public-facing counter, and the server is the kitchen. You place your custom order (input) at the counter (ui), the order gets sent to the kitchen (server) to be made (rendered) from raw ingredients (data), and then you receive your food (output) at the counter (ui).

2.1 Exercises

Copy and paste the code for the example1 app into a new R script. Save it. Click the “Run App” button that appears in the top-right corner of the Source pane. You have run your first Shiny app!