Previous chapter
Shiny BasicsBasic UI
Next chapter

Introduction

All web pages are constructed out of HTML, and Shiny user interfaces are no different–although they are generally expressed using R, their ultimate job is to produce HTML. As a Shiny app author, you can use high-level layout functions in R that keep you far away from the details of HTML. You can also work with HTML tags directly to achieve any level of customization you want (see section Advanced UI). These approaches are by no means exclusive; you can mix high-level functions with low-level HTML as much as you like.

This section will focus on some of the high-level R functions that Shiny provides for input, output, and layout. If you’re new to Shiny, you should read this chapter regardless of your level of HTML knowledge, as inputs and outputs are essential parts of any Shiny app.

Inputs

As we saw previously, functions like sliderInput, selectInput, textInput, and numericInput are used to insert input controls into your UI.

The first parameter of an input function is always the input ID; this is a simple string that is composed of alphanumeric characters and/or underscore (no spaces, dashes, periods, or other special characters please!). Generally, there is a second parameter label that is used to create a human-readable label for the control. Any remaining parameters are specific to the particular input function, and can be used to customize the input control.

For example, a typical call to sliderInput might look something like this:

sliderInput("min", "Limit (minimum)", min = 0, max = 100, value = 50)

In the server function, the value of this slider would be accessed via input$min.

It’s absolutely vital that each input have a unique ID. Using the same ID value for more than one input or output in the same app will result in errors or incorrect results.

Shiny itself comes with a variety of input functions out of the box:

functionwidget
actionButtonAction Button
checkboxGroupInputA group of check boxes
checkboxInputA single check box
dateInputA calendar to aid date selection
dateRangeInputA pair of calendars for selecting a date range
fileInputA file upload control wizard
helpTextHelp text that can be added to an input form
numericInputA field to enter numbers
radioButtonsA set of radio buttons
selectInput/selectizeInputA box with choices to select from
sliderInputA slider bar
submitButtonA submit button
textInput/passwordInputA field to enter text

Each input function has its own unique look and functionality, and takes different arguments. But they all share the same two properties of 1) taking a unique input ID, and 2) exposing values to the server function via a slot in the input object.

Inputs (2)

Outputs

Output functions are used to tell Shiny where and how to place outputs that are defined in the app’s server.

Like inputs, outputs take a unique ID as their first argument. These IDs must be unique among all inputs and outputs!

Unlike inputs, outputs generally start out as empty rectangles, that need to be fed data from the server in order to actually appear. Outputs are typically created within reactive contexts or render___() functions and can only be used in conjunction with very specific ones. For example, plotOutput(id) should use the output created from renderPlot(), tableOuput() from renderTable() and so on. You can also make parts of the user interface reactive (or change based on user input) using uiOutput() as well as renderUI().

Below you can find a table of typical render___() and ___Output() functions:

DescriptionRender FunctionOutput Function
Create PlotrenderPlotplotOutput
Create TablerenderTabletableOutput
Create User InterfacerenderUIuiOutput
Create Text OutputrenderTexttextOutput, verbatimTextOutput

Note: Some packages like DT (for dynamic tables) and plotly (for interactive plots) have their own render and output functions.

Layouts and panels

Shiny includes several classes of UI functions that behave like neither inputs nor outputs. Rather, these functions help with the layout and formatting of your UI.

Page functions

The first function you’re likely to encounter in a Shiny UI is a page function. Page functions expect to be the outermost function call in your UI, and set up your web page to contain other content.

The most common page function is fluidPage.

fluidPage(..., title = NULL, theme = NULL)

fluidPage sets up your page to use the Bootstrap CSS framework. Bootstrap provides your web page with attractive settings for typography and spacing, and also preloads dozens of CSS rules that can be invoked to visually organize and enhance specific areas of your UI. We’ll take advantage of quite a few of these Bootstrap rules as we proceed through this chapter.

The “fluid” in fluidPage means the page’s content may resize its width (but not height) as the size of the browser window changes. (The other option is “fixed”, which means the page contents will never exceed 960 pixels in width.)

  • sidebar
  • tabset
  • bootstrap grid

Exercise 03

Note: Use the solution code from Exercise 02 in the previous section.

  • Add new input variable to control the alpha level of the points
  • This should be a sliderInput
  • Values should range from 0 to 1
  • Set a default value that looks good
  • Use this variable in the geom of the ggplot function as the alpha argument

Next Steps

  1. Try to first run the exercise above based on the specifications ON YOUR OWN.
  2. Only as a last resort check out the solution in the next section.

Solution 03

library(shiny)
library(ggplot2)
load("movies.Rdata")

# Define UI for application that plots features of movies -----------
ui <- fluidPage(
  
  # Sidebar layout with a input and output definitions --------------
  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"),
      
      # Set alpha level ---------------------------------------------
      sliderInput(inputId = "alpha", 
                  label = "Alpha:", 
                  min = 0, max = 1, 
                  value = 0.5)
    ),
    
    # Output: Show scatterplot --------------------------------------
    mainPanel(
      plotOutput(outputId = "scatterplot")
    )
  )
)

# Define server function required to create the scatterplot ---------
server <- function(input, output) {
  
  # Create scatterplot object the plotOutput function is expecting --
  output$scatterplot <- renderPlot({
    ggplot(data = movies, aes_string(x = input$x, y = input$y,
                                     color = input$z)) +
      geom_point(alpha = input$alpha)
  })
}

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

Introduction to DT

From: https://rstudio.github.io/DT/

The R package DT provides an R interface to the JavaScript library DataTables. R data objects (matrices or data frames) can be displayed as tables on HTML pages, and DataTables provides filtering, pagination, sorting, and many other features in the tables.

library(DT)
datatable(iris)

You can use the Search box to filter data by specific strings (e.g. by typing versicolor in the table above). Additionally, DT supports server-side rendering for larger tables (see here) and supports additional extensions to include export buttons (Clipboard, CSV, Excel). Tables can also be edited by the users by setting the argument editable, see here.

Note: If table editing shall be the primary feature of the table you can also take a look at rhandsontable.

Exercise 04

  • Add a checkbox input to decide whether the data plotted should be shown in a data table
  • This should be a checkboxInput()
  • Create a new output item using DT::renderDataTable, an if statement to check if the box is checked, and DT::datatable
  • Show first seven columns of movies data, show 10 rows at a time, and hide row names, e.g.
    • data = movies[, 1:7]
    • options = list(pageLength = 10)
    • rownames = FALSE
  • Add a dataTableOutput to the main pane
  • Run the app in a new Window, check and uncheck the box to test functionality

Next Steps

  1. Try to first run the exercise above based on the specifications ON YOUR OWN.
  2. Only as a last resort check out the solution in the next section.

Solution 04

library(shiny)
library(ggplot2)
library(DT)
load("movies.Rdata")

# Define UI for application that plots features of movies -----------
ui <- fluidPage(
  
  # Sidebar layout with a input and output definitions --------------
  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"),
      
      # Set alpha level ---------------------------------------------
      sliderInput(inputId = "alpha", 
                  label = "Alpha:", 
                  min = 0, max = 1, 
                  value = 0.5),
      
      # Show data table ---------------------------------------------
      checkboxInput(inputId = "show_data",
                    label = "Show data table",
                    value = TRUE)
    ),
    
    # Output --------------------------------------------------------
    mainPanel(

      # Show scatterplot --------------------------------------------
      plotOutput(outputId = "scatterplot"),

      # Show data table ---------------------------------------------
      DT::dataTableOutput(outputId = "moviestable")
    )
  )
)

# Define server function required to create the scatterplot ---------
server <- function(input, output) {
  
  # Create scatterplot object the plotOutput function is expecting --
  output$scatterplot <- renderPlot({
    ggplot(data = movies, aes_string(x = input$x, y = input$y,
                                     color = input$z)) +
      geom_point(alpha = input$alpha)
  })
  
  # Print data table if checked -------------------------------------
  output$moviestable <- DT::renderDataTable(
    if(input$show_data){
      DT::datatable(data = movies[, 1:7], 
                    options = list(pageLength = 10), 
                    rownames = FALSE)
    }
  )
}

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

Exercise 05

  • Add a title to your app with titlePanel, which goes before the sidebarLayout.
  • Prettify the variable names shown as input choices.
  • You can use choices = c("IMDB rating" = "imdb_rating", ...)
  • Prettify the axis and legend labels of your plot. You might use
  • str_replace_all from the stringr package
  • toTitleCase from the tools package

Next Steps

  1. Try to first run the exercise above based on the specifications ON YOUR OWN.
  2. Only as a last resort check out the solution in the next section.

Solution 05

library(shiny)
library(ggplot2)
library(DT)
library(stringr)
library(tools)
load("movies.Rdata")

# Define UI for application that plots features of movies -----------
ui <- fluidPage(
  
  # Application title -----------------------------------------------
  titlePanel("Movie browser"),
  
  # Sidebar layout with a input and output definitions --------------
  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 -----------------------------------
      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"),
      
      # Set alpha level ---------------------------------------------
      sliderInput(inputId = "alpha", 
                  label = "Alpha:", 
                  min = 0, max = 1, 
                  value = 0.5),
      
      # Show data table ---------------------------------------------
      checkboxInput(inputId = "show_data",
                    label = "Show data table",
                    value = TRUE)
    ),
    
    # Output --------------------------------------------------------
    mainPanel(

      # Show scatterplot --------------------------------------------
      plotOutput(outputId = "scatterplot"),

      # Show data table ---------------------------------------------
      DT::dataTableOutput(outputId = "moviestable")
    )
  )
)

# Define server function required to create the scatterplot ---------
server <- function(input, output) {
  
  # Create scatterplot object the plotOutput function is expecting --
  output$scatterplot <- renderPlot({
    ggplot(data = movies, aes_string(x = input$x, y = input$y,
                                     color = input$z)) +
      geom_point(alpha = input$alpha) +
      labs(x = toTitleCase(str_replace_all(input$x, "_", " ")),
           y = toTitleCase(str_replace_all(input$y, "_", " ")),
           color = toTitleCase(str_replace_all(input$z, "_", " ")))
  })
  
  # Print data table if checked -------------------------------------
  output$moviestable <- DT::renderDataTable(
    if(input$show_data){
      DT::datatable(data = movies[, 1:7], 
                    options = list(pageLength = 10), 
                    rownames = FALSE)
    }
  )
}

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