User interface (UI)

In this section we’ll build the user interface of a simple app.

However, before we get into the weeds of building a user interface, let’s revisit the anatomy of a Shiny app.

Shiny app with Y-axis of audience_score and X-axis of critics_score from the movies.RData dataset. Those variables are in a box on the left. On the right is a scatterplot of the data. Points cover the whole plot, but have a general linear upward trend with a slope of 1. This will be our Shiny app that we'll be using and modifying in this lesson.

Example

Highlighting areas of the Shiny app. Shows the Y-axis box pointing to the y-axis on the plot and the X-axis box pointing to the x-axis on the plot. Code 'ggplot(data = movies, aes_string(x = input$x, y = input$y)) + geom_point()' points to the points on the scatterplot.

For example, if your app features a plot the code for building that plot lives in the server function. But the setup for the user defined inputs for the plot, as well as information on where physically on the app the plot should appear, are defined in the UI.

Here is the app we’ll work with in this section and the code that builds the UI of that app.

Since this is too much code to parse, we’ll explore individual components of the UI one by one.

Our same Shiny app. Shiny app with Y-axis of audience_score and X-axis of critics_score. Those variables are in a box on the left. On the right is a scatterplot of the data. Points cover the whole plot, but have a general linear upward trend with a slope of 1.

Code block highlighting the ui section of the Shiny app code.

fluidPage()

At the outermost layer of our UI definition we begin with the fluidPage() function.

Arrow pointing to the section in the code that says 'ui <- fluidPage{' that says Create fluide page layout.

The fluidPage() function creates a fluid page layout consisting of rows and columns. Rows make sure that elements in them appear on the same line. Columns within these rows define how much horizontal space each element should occupy.

Fluid pages scale their components in realtime to fill all available browser width, which means you, the app developer, don’t need to worry about defining relative widths for individual app components.

As always, for more information on arguments to this function, you can view the R function help by typing ?fluidPage in your R console or visiting the function reference page on the package website here.

Layout

Next, we define the layout of our app with sidebarLayout().

Arrow pointing to the section of the code that says 'sidebar_layout{' and says Create a layout with a sidebar and main area.

Shiny includes a number of options for laying out the components of an application. The default layout, the one we’re using in our example app, is a layout with a sidebar, that you can define with the sidebarLayout() function.

Showing the different sections of the Shiny app. The left portion with the variables is the 'sidebarPanel' and the right section with the plot is the 'mainPanel'.

This is a simple layout with a narrow sidebar for inputs and a wider main area for output.

Under the hood, Shiny implements layout features available in Bootstrap 2, which is a popular HTML/CSS framework. However the nice thing about working in Shiny is that no prior experience with Bootstrap is necessary.

To learn more about various layouts, I recommend reviewing the Application Layout Guide article at shiny.rstudio.com.

Input controls

Next we define our sidebar panel containing input controls.

Arrow pointing to the line of code in the Shiny app that says 'sidebarPanel{' and says Create a sidebar panel containing Input controls.

This panel contains two dropdown menus created with the selectInput() function.

Arrows pointing to the sections of code in the Shiny app that say 'selection{inputId = 'y', label = 'Y-axis:',' and 'selection{inputId = 'x', label = 'X-axis:',' and shows those sections in the app from the sidebar panel.

Let’s take a look at one of the selectInput widgets a little more closely.

Box around section of the code in the Shiny app on '#Selecting variable for y-axis'.

  1. The first argument is the inputId, which is the input value that the app will internally use to access the value selected by the user.

  2. The second argument is the label, which is the display label that the user sees.

  3. The third argument is the list of choices the user will choose from. In this app, these are variable names from the movies dataset.

  4. And lastly we specify a default selection from that list with selected.

Main Panel

The final component of our UI is mainPanel().

Arrow pointing to line of code in the Shiny app that says 'plotOutput(outputId = 'scatterplot')' and says Create a main panel containing output elements that get created in the server function.

Currently the main panel contains only one component, a plot output. We’ll talk about how this plot is built later in the tutorial.

Next, let’s practice building an app UI!

Practice: Extend the UI

We’ll start with a simplified version of the app you saw in the previous exercise. In this app a selectInput() widget is used to allow the user to select which variables should be plotted on the x and y axes of the scatterplot.

The selectInput() function has the following arguments:

  • an inputId that is used to refer to the input parameter when building the scatterplot,
  • a list of choices to pick from (which must match variable names in the data frame),
  • and a selected choice for when the app first launches.

Your turn

Modify the Shiny app code in app.R / shown below:

In the ui:

  1. Add a new selectInput widget to color the points by a choice of the following variables: "title_type", "genre", "mpaa_rating", "critics_rating", "audience_rating".
  2. Make the default selection "mpaa_rating".
  3. Use "z" as the inputId.
  4. label can be whatever you like.

In the server:

  1. Set the color argument in ggplot() aesthetic mappings to input$z.

Complete this exercise by opening up the RStudio Project titled 1-2a Extend the UI within your RStudio Cloud Workspace

Go to Posit Cloud Workspace

Continue editing the file you started in the Getting Started section

OR

  • Download the data if you haven’t already
```{r}
# Get the data

file <- "https://github.com/rstudio-education/shiny-course/raw/main/movies.RData"
destfile <- "movies.RData"

download.file(file, destfile)
```
  • Copy the code below into an R script
# Load packages ----------------------------------------------------------------

library(shiny)
library(ggplot2)

# Load data --------------------------------------------------------------------

load("movies.RData")

# Define UI --------------------------------------------------------------------

ui <- fluidPage(
  
  sidebarLayout(
    
    # Inputs: Select variables to plot
    sidebarPanel(
      
      # Select variable for y-axis
      selectInput(inputId = "y", 
                  label = "Y-axis:",
                  choices = c("imdb_rating", "imdb_num_votes", "critics_score", "audience_score", "runtime"), 
                  selected = "audience_score"),
      
      # Select variable for x-axis
      selectInput(inputId = "x", 
                  label = "X-axis:",
                  choices = c("imdb_rating", "imdb_num_votes", "critics_score", "audience_score", "runtime"), 
                  selected = "critics_score"),
      
      # Select variable for color
      selectInput(inputId = "___", 
                  label = "____",
                  choices = c(___),
                  selected = "___")
      
    ),
    
    # Output: Show scatterplot
    mainPanel(
      plotOutput(outputId = "scatterplot")
    )
  )
)

# Define server ----------------------------------------------------------------

server <- function(input, output, session) {
  
  output$scatterplot <- renderPlot({
    ggplot(data = movies, aes_string(x = input$x, y = input$y,
                                     color = ___)) +
      geom_point()
  })
  
  }

# Create a Shiny app object ----------------------------------------------------

shinyApp(ui = ui, server = server)
# Load packages ----------------------------------------------------------------

library(shiny)
library(ggplot2)

# Load data --------------------------------------------------------------------

load("movies.RData")

# Define UI --------------------------------------------------------------------

ui <- fluidPage(
  
  sidebarLayout(
    
    # Inputs: Select variables to plot
    sidebarPanel(
      
      # Select variable for y-axis
      selectInput(inputId = "y", 
                  label = "Y-axis:",
                  choices = c("imdb_rating", "imdb_num_votes", "critics_score", "audience_score", "runtime"), 
                  selected = "audience_score"),
      
      # Select variable for x-axis
      selectInput(inputId = "x", 
                  label = "X-axis:",
                  choices = c("imdb_rating", "imdb_num_votes", "critics_score", "audience_score", "runtime"), 
                  selected = "critics_score"),
      
      # Select variable for color
      selectInput(inputId = "z", 
                  label = "Color by:",
                  choices = c("title_type", "genre", "mpaa_rating", "critics_rating", "audience_rating"),
                  selected = "mpaa_rating")
      
    ),
    
    # Output: Show scatterplot
    mainPanel(
      plotOutput(outputId = "scatterplot")
    )
  )
)

# Define server ----------------------------------------------------------------

server <- function(input, output, session) {
  
  output$scatterplot <- renderPlot({
    ggplot(data = movies, aes_string(x = input$x, y = input$y,
                                     color = input$z)) +
      geom_point()
  })
  
  }

# Create a Shiny app object ----------------------------------------------------

shinyApp(ui = ui, server = server)

Practice: Extend the UI further

The potential variables the user can select for the x and y axes and color currently appear in the UI of the app the same way that they are spelled in the data frame header. However we might want to label them in a way that is more human readable. We can achieve this using named vectors for the choices argument, in the format of "Human readable label" = "variable_name".

Your turn

  1. Fill in the blanks in the code below with human readable labels for x and y inputs.

  2. Re-create the selectInput widget for color, z, with options "title_type", "genre", "mpaa_rating", "critics_rating", and "audience_rating", default selection "mpaa_rating" just like in the previous exercise, but this time use human readable labels as well.

Complete this exercise by opening up the RStudio Project titled 1-2b Extend the UI further within your Posit Cloud Workspace

Go to Posit Cloud Workspace

  • Continue editing the code you’ve created with the code below
# Load packages ----------------------------------------------------------------

library(shiny)
library(ggplot2)

# Load data --------------------------------------------------------------------

load("movies.RData")

# Define UI --------------------------------------------------------------------

ui <- fluidPage(
  
  sidebarLayout(
    
    # Inputs: Select variables to plot
    sidebarPanel(
      
      # Select variable for y-axis
      selectInput(inputId = "y", 
                  label = "Y-axis:",
                  choices = c(___ = "imdb_rating", 
                              ___ = "imdb_num_votes", 
                              ___ = "critics_score", 
                              ___ = "audience_score", 
                              ___ = "runtime"), 
                  selected = "audience_score"),
      
      # Select variable for x-axis
      selectInput(inputId = "x", 
                  label = "X-axis:",
                  choices = c(___ = "imdb_rating", 
                              ___ = "imdb_num_votes", 
                              ___ = "critics_score", 
                              ___ = "audience_score", 
                              ___ = "runtime"), 
                  selected = "critics_score"),
      
      # Select variable for color
      selectInput(inputId = "z", 
                  label = "Color:",
                  choices = ___, 
                  selected = ___)
      
    ),
    
    # Output: Show scatterplot
    mainPanel(
      plotOutput(outputId = "scatterplot")
    )
  )
)

# Define server ----------------------------------------------------------------

server <- function(input, output, session) {
  
  output$scatterplot <- renderPlot({
    ggplot(data = movies, aes_string(x = input$x, y = input$y,
                                     color = input$z)) +
      geom_point()
  })
  
  }

# Create a Shiny app object ----------------------------------------------------

shinyApp(ui = ui, server = server)
# Load packages ----------------------------------------------------------------

library(shiny)
library(ggplot2)

# Load data --------------------------------------------------------------------

load("movies.RData")

# Define UI --------------------------------------------------------------------

ui <- fluidPage(
  
  sidebarLayout(
    
    # Inputs: Select variables to plot
    sidebarPanel(
      
      # Select variable for y-axis
      selectInput(inputId = "y", 
                  label = "Y-axis:",
                  choices = c("IMDB rating"          = "imdb_rating", 
                              "IMDB number of votes" = "imdb_num_votes", 
                              "Critics score"        = "critics_score", 
                              "Audience score"       = "audience_score", 
                              "Runtime"              = "runtime"), 
                  selected = "audience_score"),
      
      # Select variable for x-axis
      selectInput(inputId = "x", 
                  label = "X-axis:",
                  choices = c(
                    "IMDB rating"          = "imdb_rating", 
                    "IMDB number of votes" = "imdb_num_votes", 
                    "Critics score"        = "critics_score", 
                    "Audience score"       = "audience_score", 
                    "Runtime"              = "runtime"), 
                  selected = "critics_score"),
      
      # Select variable for color
      # Select variable for color
      selectInput(inputId = "z", 
                  label = "Color by:",
                  choices = c(
                    "Title type" = "title_type", 
                    "Genre" = "genre", 
                    "MPAA rating" = "mpaa_rating", 
                    "Critics rating" = "critics_rating", 
                    "Audience rating" = "audience_rating"),
                  selected = "mpaa_rating")
      
    ),
    
    # Output: Show scatterplot
    mainPanel(
      plotOutput(outputId = "scatterplot")
    )
  )
)

# Define server ----------------------------------------------------------------

server <- function(input, output, session) {
  
  output$scatterplot <- renderPlot({
    ggplot(data = movies, aes_string(x = input$x, y = input$y,
                                     color = input$z)) +
      geom_point()
  })
  
  }

# Create a Shiny app object ----------------------------------------------------

shinyApp(ui = ui, server = server)