A Beginners Guide to R Shiny

Posted on
R Shiny

Getting Started

The purpose of this blog post is to provide an introduction to creating interactive web apps using Shiny that will update based on user input and interactions. A Shiny web app is made up of two primary files, a user interface (UI) script and a server script. Deploying a Shiny app can be done using four simple steps:

  • Loading the shiny package via library(shiny).
  • Create the user interface script.
  • Create the server script that receives input and returns output.
  • Run the app using shinyApp(ui, server)

The following is an example of a very simple Shiny app that allows the user to type a name and get a greeting in response. Test it out by entering your own name.

Hello App

The four components can be seen in the code below. First the shiny package is loaded.

library(shiny)

Next, the user interface is created using the following syntax:

ui <- fluidPage(
  textInput("name", "Enter a name:"),
  textOutput("greeting")
)

Then the server is specified using the following syntax:

server <- function(input, output, session) {
  output$greeting <- renderText({
    paste("Hello", input$name)
  })
}

And finally, the app is run.

shinyApp(ui, server)

Building a Shiny app

There are four essential elements that are specified in the UI and server scripts.

  1. Add inputs (UI)
  2. Add outputs (UI/server)
  3. Update layouts (UI)
  4. Update outputs (server)

There are tons of different inputs that can be used in your app. These are what the user interacts with to input directions to the app. Some examples of common inputs are below.

  • textInput(): used in Hello app; allows user to type text
  • sliderInput(): creates a numeric slider bar
  • selectInput(): creates a drop-down list
  • dateRangeInput(): allows user to select two dates from a calender

Unfortunately there’s not enough time to cover all of the different inputs, but we will go over some common ones later in this post. All inputs are formatted similarly. First an input ID is specified, then a label, and finally any input-specific options. The input ID should be a unique way to refer to it in your code, while the label is what is shown to the user.

In the selectInput example below, you can see the input ID, the label, and the input-specific options, in this case choices.

selectInput(
  "inputID",
  "label",
  choices = c("A", "B", "C")
)

This will create a drop-down list that allows the user to select A, B, or C like the one pictured below.

Opening SPSS

Inputs are always created in the user interface, though they are referred to in the server.

Outputs

There are two types of outputs: render functions and output functions. Render functions are used in the server to create images, text, plots, etc.

  • renderText()
  • renderImage()
  • renderPlot()
  • etc.

Output functions are used in the user interface to specify where to display each table, plot, text block, etc.

  • tableOutput()
  • plotOutput()
  • etc.

Let’s see these functions at work in a simple app.

The following app samples a random 1% of values from the babynames dataset in R and displays them in a table. You can search for a specific name in the database by typing it into the Search box.

Random 1% of Baby Names Table

The table is created in the server using the renderDT function from the DT package. Note the use of this package creates a searchable, sortable table rather than a static one.

server <- function(input, output) {
  output$babynames_table <- DT::renderDT({
    babynames %>%
      sample_frac(.1)
  })
}

The UI uses DTOutput to call the table that was created in the server-side so that the user can see it.

ui <- fluidPage(
  DT::DTOutput("babynames_table")
)

Layouts

The default layout is to stack elements, such as in the hello app. However, with multiple elements this can quickly become impractical, not to mention ugly. Thus, it is important to specify layouts in the UI.

When developing an app, it is useful to start by sketching how your app will look on paper. This way, you can keep track of all the elements to add and get a feel for how they’re nested. A simple layout is the sidebar layout, which will be used in the next app. Another common layout is the tab layout. There are many other layouts but we won’t cover those here.

The baby name explorer app uses a sidebar layout to have user inputs on one side, and a plot output on the other.

Baby Name Explorer

The following is the UI and server syntax used to create this app.

ui <- fluidPage(
  titlePanel("Baby Name Explorer"),
  sidebarLayout(
    sidebarPanel(textInput("name", "Enter Name", "David")),
    mainPanel(plotOutput("trend"))
  )
)

server <- function(input, output, session) {
  output$trend <- renderPlot({
    data_name <- subset(
      babynames, name == input$name)
    ggplot(data_name) +
      geom_line(aes(x=year, y = prop, color = sex))
  })
}

The next layout we’ll discuss is the tab layout. To create a tab layout use:

tabsetPanel(
  tabPanel("label", ...),
  tabPanel("label", ...)
)

We see in the next app how this is executed. This app incorporates both a sidebar layout and a tab layout. The user can specify the year and gender in the side panel and toggle between a plot or a table of the 10 most popular baby names given those inputs.

Themes

Themes are another important feature in the UI. They allow you to specify the aesthetics of your app. The shinythemes package allows you to change colors/themes. You can run the themeSelector() function anywhere in the UI to conveniently preview themes in your app. Once you decide on a theme you like, use the shinytheme function to specify the theme you want to use. It is also possible to create custom themes using HTML code, but we won’t go into that here.

Hello App with theme

Reactivity 101

Reactivity is an important part of your app. It allows you to stop, delay or trigger actions based on user input. We will cover four useful functions in this tutorial.

  • reactive
  • observe
  • observeEvent
  • eventReactive

Using the reactive function creates a variable that can be changed by user inputs. It is lazy and cached, meaning it’s evaluated only when something calls it and/or when the value of one of its underlying sources changes. The reactive function has no side effects. However, the observe function does not return a value, but rather performs some side effect (often this involves sending or retrieving data). It triggers when any reactive variable changes. observeEvent can be used to trigger when one specific reactive variable changes. Finally, eventReactive is used to create a reactive variable with a specific trigger.

In to cm conversion app

This app converts the user input from inches to centimeters. Note that reactive expressions are used to delay the calculation until the “Show height in cm” button is clicked. Compare this to the hello app which started saying hello as soon as the user began typing.

ui <- fluidPage(
  titlePanel("In to Cm Conversion"),
  sidebarLayout(
    sidebarPanel(
      numericInput("height", "Height(in)", 60),
      actionButton("show_cm", "Show height in cm")
    ),
    mainPanel(textOutput("height_cm"))
  )
)

server <- function(input, output, session) {
  rval_height_cm <- eventReactive(input$show_cm, {
    input$height*2.54
  })
  output$height_cm <- renderText({
    height_cm <- rval_height_cm()
    paste("Your height in cm is", height_cm, "cm")
  })
}

Widgets

The last thing we’ll mention are widgets. The shinyWidgets package provides many cool and useful widgets to incorporate into your own app. You can run shinyWidgetsGallery() to see them all in one dashboard, along with the code for each widget. You can also check out gallery.htmlwidgets.org to explore more.

Shiny Widget Gallery

Hopefully this gave you a starting point for creating apps with Shiny! Feel free to reach out with any questions.