In this tutorial, I’m going to walk you through the basics of setting up a shiny app, starting with the example built into RStudio I’m not going to explain yet how shiny apps are structured, the goal is to just get something up and running, and give you some familiarity with the layout of a fairly simple app.

Create the Demo App

New project…

Under the File menu, choose New Project.... You will see a popup window like the one below. Choose New Directory.

Project type

Choose Shiny Web Application as the project type.

Directory name

I like to put all of my apps in the same directory`, but it doesn’t matter where you save it.

Default demo app

Your RStudio interface should look like this now. You don’t have to do anything else at this step.

If RStudio has changed their demo app and your source code doesn’t look like this, replace it with the code below:

#
# This is a Shiny web application. You can run the application by clicking
# the 'Run App' button above.
#
# Find out more about building applications with Shiny here:
#
#    http://shiny.rstudio.com/
#

library(shiny)

# Define UI for application that draws a histogram
ui <- fluidPage(
   
   # Application title
   titlePanel("Old Faithful Geyser Data"),
   
   # Sidebar with a slider input for number of bins 
   sidebarLayout(
      sidebarPanel(
         sliderInput("bins",
                     "Number of bins:",
                     min = 1,
                     max = 50,
                     value = 30)
      ),
      
      # Show a plot of the generated distribution
      mainPanel(
         plotOutput("distPlot")
      )
   )
)

# Define server logic required to draw a histogram
server <- function(input, output) {
   
   output$distPlot <- renderPlot({
      # generate bins based on input$bins from ui.R
      x    <- faithful[, 2] 
      bins <- seq(min(x), max(x), length.out = input$bins + 1)
      
      # draw the histogram with the specified number of bins
      hist(x, breaks = bins, col = 'darkgray', border = 'white')
   })
}

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

Run the app

Click on Run App in the top right corner of the source pane. The app will open up in a new window. Play with the slider and watch the histogram change.

You can also open up the app in a web browser by clicking on Open in Browser.

Modify the Demo App

Now we’re going to make a series of changes to the demo app until it’s all your own.

You can close the app by closing the window or browser tab it’s running in, or leave it running while you edit the code. If you have multiple screens, it’s useful to have the app open on one screen and the code on another.

Change the title

Find the application title. It is the first argument to the function titlePanel. Change the title to "My First App". Make sure the title is inside quotes and the whole quoted string is inside the parentheses. Save the file (cmd-S or File > Save).

Reload the app

Click Run App (or Reload App if you haven’t closed the app window) in the source pane. If you haven’t saved your changes, it will prompt you to do so. Check that the app title has changed.

Change the input

Find the function sliderInput (line 21). The first argument is the name you can use in the code to find the value of this input, so don’t change it just yet. The second argument is the text that displays before the slider. Change this to something else and re-run the app.

         sliderInput("bins",
                     "Number of bins:",
                     min = 0,
                     max = 50,
                     value = 30)

See if you can figure out what the next three arguments to sliderInput do. Change them to different integers, then re-run the app to see what’s changed.

Add some text

The arguments to the function sidebarPanel are just a list of things you want to display in the sidebar. To add some explanatory text in a paragraph before the sliderInput, just use the paragraph function p("My text")

      sidebarPanel(
         p("I am explaining this perfectly"),
         sliderInput("bins",
                     "Choose the best bin number:",
                     min = 10,
                     max = 40,
                     value = 25)
      )

The sidebar shows up on the left if your window is wide enough, but moves to the top of the screen if it’s too narrow.

Move the text

I don’t like it there, so we can move this text out of the sidebar and to the top of the page, just under the title. Try this and re-run the app.

   # Application title
   titlePanel("My First App"),

   p("I am explaining this perfectly"),

   # Sidebar with a slider input for number of bins
   sidebarLayout(...)

See where you can move the text in the layout of the page and where causes errors.

Change the plot colour

I’m also not keen on the grey plot. We can change it inside the hist function.

      # draw the histogram with the specified number of bins
      hist(x, breaks = bins, col = 'steelblue3', border = 'grey30')

There are a lot of ways to represent colour in R. The easiest three are:

  1. hexadecimal colours like #0066CC,
  2. the rgb or hsl functions,
  3. colour names (see page 4 of Melanie Frazier’s R color cheetsheet

I like steelblue3, as it’s pretty close to the shiny interface default colour, but feel free to choose whatever you like.

Change the plot style

I prefer ggplot graphs, so let’s make the plot with geom_histogram instead of hist (which is a great function for really quick plots). Since we need several functions from the ggplot2 package, we’ll need to load that package at the top of the script, just under where the shiny package is loaded:

library(shiny)
library(ggplot2)

You can replace all of the code in the renderPlot function with the code below.

  output$distPlot <- renderPlot({
    # create plot
    ggplot(faithful, aes(waiting)) +
      geom_histogram(bins = input$bins,
                     fill = "steelblue3",
                     colour = "grey30") +
      xlab("What are we even plotting here?") +
      theme_minimal()
  })

You can set the fill and colour to whatever colours you like, and change theme_minimal() to one of the other built-in ggplot themes.

What are we even plotting here? Type ?faithful into the console pane to see what the waiting column represents (faithful is a built-in demo dataset). Change the label on the x-axis to something more sensible.

Adding New Things

Add a new input widget

The faithful dataset includes two columns:eruptions and waiting. We’ve been plotting the waiting variable, but what if you wanted to plot the eruptions variable instead?

Try plotting the eruption time (eruptions) instead of the waiting time. You just have to change one word in the ggplot function and update the x-axis label.

We can add another input widget to let the user switch between plotting eruption time and wait time. The RStudio Shiny tutorial has a great overview of the different input options. We need to toggle between two options, so we can use either radio buttons or a select box. Radio buttons are probably best if you have only a few options and the user will want to see them all at the same time to decide.

Add the following code as the first argument to sidebarPanel(), which just takes a list of different widgets. radioButtons is the widget we’re using. The first argument is display_var, which we will use later in the code to find the value of this widget. The second argument is the label to display to the user. The next argument is choices, which is a list of choices in the format c("label1" = "value1", "label2 = "value2", ...). The label is what gets shown to the user and the value is what gets used by the code (these can be the same, but you often want the user label to be more descriptive). The last argument is selected, which is the value of the default choice. Save this and re-run the app.

         radioButtons("display_var",
                      "Which variable to display",
                      choices = c("Waiting time to next eruption" = "waiting",
                                  "Eruption time" = "eruptions"),
                      selected = "waiting"
         ),

You should have a radio button interface now. You can click on the options to switch the button, but it won’t do anything to your plot yet. We need to edit the plot-generating code to make that happen.

Change what you’re plotting

First, we need to change the x-axis label depending on what we’re graphing. We use an if/else statement to set the variable xlabel to one thing if input$display_var is equivalent to "eruptions", and to something else if it’s equivalent to "waiting". Put this code at the very beginning of the code block for the renderPlot function (after the line output$distPlot <- renderPlot({).

      # set x-axis label depending on the value of display_var
      if (input$display_var == "eruptions") {
        xlabel <- "Eruption Time (in minutes)"
      } else if (input$display_var == "waiting") {
        xlabel <- "Waiting Time to Next Eruption (in minutes)"
      }

The double-equal-signs == means "equivalent to and is how you check if two things are the same; if you only use one equal sign, you set the variable on the left to the value on the right.

Then we have to edit the ggplot function to use the new label and to plot the correct column. The variable input$display_var gives you the user-input value of the widget called display_var.

      # create plot
      ggplot(faithful, aes(.data[[input$display_var]])) +
        geom_histogram(bins = input$bins,
                       fill = "steelblue3",
                       colour = "grey30") +
        xlab(xlabel) +
        theme_minimal()

Notice that the function aes(waiting) from before has changed to aes(.data[[input$display_var]]). Because input$display_var is a string, we have to select it from the .data placeholder (which refers to the faithful data table) using double brackets.

Re-run your app and see if you can change the data and x-axis label with your new widget. If not, check that your code against the code below:

#
# This is a Shiny web application. You can run the application by clicking
# the 'Run App' button above.
#
# Find out more about building applications with Shiny here:
#
#    http://shiny.rstudio.com/
#

library(shiny)
library(ggplot2)

# Define UI for application that draws a histogram
ui <- fluidPage(

   # Application title
   titlePanel("My First App"),

   p("I am explaining this perfectly"),

   # Sidebar with a slider input for number of bins
   sidebarLayout(
      sidebarPanel(
         radioButtons("display_var",
                      "Which variable to display",
                      choices = c("Waiting time to next eruption" = "waiting",
                                  "Eruption time" = "eruptions"),
                      selected = "waiting"
         ),
         sliderInput("bins",
                     "Number of bins:",
                     min = 10,
                     max = 40,
                     value = 25)
      ),

      # Show a plot of the generated distribution
      mainPanel(
         plotOutput("distPlot")
      )
   )
)

# Define server logic required to draw a histogram
server <- function(input, output) {

    output$distPlot <- renderPlot({
      # set x-axis label depending on the value of display_var
      if (input$display_var == "eruptions") {
        xlabel <- "Waiting Time to Next Eruption (in minutes)"
      } else if (input$display_var == "waiting") {
        xlabel <- "Waiting Time to Next Eruption (in minutes)"
      }

      # create plot
      ggplot(faithful, aes(.data[[input$display_var]])) +
        geom_histogram(bins = input$bins,
                       fill = "steelblue3",
                       colour = "grey30") +
        xlab(xlabel) +
        theme_minimal()
    })
}

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

Glossary

term definition
argument A variable that provides input to a function.
integer A data type representing whole numbers.
package A group of R functions.
panes RStudio is arranged with four window “panes”.
rstudio An integrated development environment (IDE) that helps you process R code.
shiny An R package that builds interactive web apps
string A piece of text inside of quotes.
widget A interactive web element, like a dropdown menu or a slider.