Learning Objectives

Motivation

Format of a Shiny App.

Your First Shiny App

Input UI Elements

Text Inputs

  • Use textInput() to collect one line of text.

  • Use passwordInput() to collect one line of text which is not displayed on the screen as it is entered.

    • NOTE: This is not a secure way to collect passwords by itself.
  • UsetextAreaInput() to collect multiple lines of text.

  • Add this element to your tryouts app:

    library(shiny)    
    
    ui <- fluidPage(
      textInput("name", "What's your name?"),
      passwordInput("password", "What's your password?"),
      textAreaInput("story", "Tell me about yourself")
    )
    
    server <- function(input, output) {
    
    }
    
    shinyApp(ui = ui, server = server)
  • Running the app, you should get something like this:

  • Later on, we’ll demonstrate how to access these inputs in the server() function.

  • Exercise: Change the width and height arguments in textAreaInput(). What does it do?

  • Exercise: Change the value argument in textInput(). What does it do?

Numeric Inputs

  • Use numericInput() to create a text box that only accepts numeric values.

  • Use sliderInput() to create a number slider.

    • Giving the value argument one number will result in a one-sided slider.
    • Giving the value argument a vector of two numbers will result in a two-sided slider.
    library(shiny)
    
    ui <- fluidPage(
      numericInput("num", "Number one", value = 0, min = 0, max = 100),
      sliderInput("num2", "Number two", value = 50, min = 0, max = 100),
      sliderInput("rng", "Range", value = c(10, 20), min = 0, max = 100)
    )
    
    server <- function(input, output) {
    
    }
    
    shinyApp(ui = ui, server = server)
  • Running the app, you should get something like this:

  • Only use sliders for small ranges where the exact number is not important.

  • Exercise: What does the animate option do when you set it to TRUE?

  • You can see more on sliders at https://shiny.rstudio.com/articles/sliders.html.

Date Inputs

  • Use dateInput() to collect a single date.

  • Use dateRangeInput() to collect two dates.

    library(shiny)
    
    ui <- fluidPage(
      dateInput("dob", "When were you born?"),
      dateRangeInput("holiday", "When do you want to go on vacation next?")
    )
    
    server <- function(input, output) {
    
    }
    
    shinyApp(ui = ui, server = server)
  • Running the app, you should get something like this:

  • Exercise: In dateInput(), try to disable the selection of Sundays, Mondays, Fridays, and Saturdays.

Multiple Choice

  • Use selectInput() to provide the user with a drop-down menu.

  • Use radioButtons() to have a multiple choice button selection where only selection is possible.

  • Use checkboxGroupInput() to have a multiple choice button selection where multiple selections are possible.

    library(shiny)
    
    weekdays <- c("Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat")
    ui <- fluidPage(
      selectInput("state", "Where do you live?", choices = state.name),
      radioButtons("weekday", "What's your favorite day of the week?", choices = weekdays),
      checkboxGroupInput("weekday2", "What days do you work?", choices = weekdays)
    )
    
    server <- function(input, output) {
    
    }
    
    shinyApp(ui = ui, server = server)
  • Running the app, you should get something like this:

  • Exercise: What does multiple = TRUE do in in selectInput()?

Columns of a Data Frame

  • For a data frame named df, just use selectInput(), with the choices = names(df) option.

    library(shiny)
    
    ui <- fluidPage(
      selectInput("carcol", "Which Column?", choices = names(mtcars))
    )
    
    server <- function(input, output) {
    
    }
    
    shinyApp(ui = ui, server = server)
  • Running the app, you should get something like this:

  • Exercise: What does the selected argument do? Change it.

Binary Inputs

  • Use checkboxInput() to get a TRUE/FALSE or Yes/No answer.

    library(shiny)
    
    ui <- fluidPage(
      checkboxInput("startrek", "Like Star Trek?")
    )
    
    server <- function(input, output) {
    
    }
    
    shinyApp(ui = ui, server = server)
  • Running the app, you should get something like this:

  • Exercise: What are the possible values for the value argument? Change it.

    It can be either TRUE (so the box is checked) or FALSE (so the box is unchecked).

File Inputs

  • Use fileInput() to have a user input a file name.

  • Running the app, you should get something like this:

  • Exercise: What does the buttonLabel argument do? Change it.

Action Buttons

  • Use actionButton() to create a clickable button, or actionLink() to create a clickable link.

    library(shiny)
    
    ui <- fluidPage(
      actionButton("click", "Click me!"),
      actionLink("Link", "No, click me!")
    )
    
    server <- function(input, output) {
    
    }
    
    shinyApp(ui = ui, server = server)
  • Running the app, you should get something like this:

Output UI Elements

Text Output

  • Use textOutput() to display text.

  • Use verbatimTextOutput() to display code.

  • You create text in the server() function by either renderText() or renderPrint().

  • renderText() will display text returned by code. Functions can only return one thing.

  • renderPrint() will display text printed by code. Functions can print multiple things.

    library(shiny)
    
    ui <- fluidPage(
      textOutput("text"),
      verbatimTextOutput("code")
    )
    
    server <- function(input, output, session) {
      output$text <- renderText({
        "Hello World!"
      })
    
      output$code <- renderPrint({
        summary(c(1, 2, 3, 4))
      })
    }
    
    shinyApp(ui = ui, server = server)
  • Running the app, you should get something like this:

  • Exercise: Change the label from “text” to something else. Make sure the Shiny App still works.

Output Tables

  • Use tableOutput() to print an entire table created in the server by renderTable().

    • Should only be used for small tables.
    library(shiny)
    
    ui <- fluidPage(
      tableOutput("static")
    )
    
    server <- function(input, output, session) {
      output$static <- renderTable({
        head(mtcars)
        })
    }
    
    shinyApp(ui = ui, server = server)
  • Running the app, you should get something like this:

  • Use dataTableOutput() to output a dynamic table created in the server by renderDataTable().

    library(shiny)
    
    ui <- fluidPage(
      dataTableOutput("dynamic")
    )
    
    server <- function(input, output, session) {
      output$dynamic <- renderDataTable({
        mtcars
        })
    }
    
    shinyApp(ui = ui, server = server)
  • Running the app, you should get something like this:

  • You can change the appearance of dataTableOutput() by passing arguments as a list to the options argument in renderDataTable().

    renderDataTable({ mtcars }, options = list(pageLength = 5))

Output Plots

  • Use plotOutput() to output plots created by renderPlot() in the server() function.

    library(shiny)
    library(ggplot2)
    
    ui <- fluidPage(
      plotOutput("plot")
    )
    
    server <- function(input, output, session) {
      output$plot <- renderPlot({
        ggplot(mpg, aes(x = displ, y = hwy)) +
          geom_point() +
          theme_bw() +
          xlab("Displacement") +
          ylab("Highway MPG")
        })
    }
    
    shinyApp(ui = ui, server = server)
  • Running the app, you should get something like this:

  • Exercise: Change the height and width of the plot by changing the argument values in renderPlot().

  • Exercise: Change the height and width of the plot by changing the argument values in plotOutput().

ggplot2 and non-standard evaluation

Putting Inputs and Outputs Together

Alternative pipeline to .data

  • You can use selectInput() for variable selection, in which case you can use the .data object.

  • But if you use varSelectInput(), you need to use !!.

    library(shiny)
    library(ggplot2)
    
    ui <- fluidPage(
        varSelectInput("var1", "Variable 1", data = mtcars),
        varSelectInput("var2", "Variable 2", data = mtcars),
        plotOutput("plot")
    )
    
    server <- function(input, output) {
        output$plot <- renderPlot({
            ggplot(mtcars, aes(x = !!input$var1, y = !!input$var2)) +
                geom_point()
        })
    }
    
    shinyApp(ui = ui, server = server)
  • Compare UI:

    • Way 1: varSelectInput("var1", "Variable 1", data = mtcars)
    • Way 2: selectInput("var1", "Variable 1", choices = names(mtcars))
  • Compare Server:

    • Way 1: x = !!input$var1
    • Way 2: x = .data[[input$var1]]
  • Exercise: Create a Shiny app that will take as input

    1. A column from mtcars
    2. A numeric value

    and it will print out an interactive table containing just the rows from mtcars that have a value of the selected variable above the provided numeric value. For example, if the user selects mpg as the column and 30 as the numeric value, then the code that would effectively be run would be:

    mtcars |>
      filter(mpg > 30)