Created by John


Tutorial aims:

  1. Downloading Shiny
  2. Getting familiar with the Shiny app file structure
  3. Getting familiar with the Shiny app.R layout
  4. Creating a Shiny app
  5. Exporting a finished app
  6. Challenge yourself to write an app

At it’s core, Shiny is merely an R package like dplyr or ggplot2. The package is used to create web-applications, but uses the R language rather than javascript or HTML5, which are traditionally used for web applications. By using R, Shiny provides an efficient method of creating web applications designed around data presentation and analysis.

Below is an example of the basic Shiny app that we will be recreating in today’s tutorial:

Example app screenshot

Have a look at these examples if you want to see what a Shiny app looks like, or if you want inspiration for your own app.

What are Shiny Apps useful for?

1. Downloading Shiny and tutorial resources

To get Shiny in RStudio, the first thing you need is the shiny package, by running the code below in RStudio:

install.packages("shiny")
install.packages("rsconnect")  # For publishing apps online
install.packages("agridat")  # For the dataset in today's tutorial

You can download the resources for this tutorial by heading to the Github repository for this tutorial. You can click on Clone / Download and either download the zip file and extract the files, or fork the repository to your own Github account. See our Git and Github tutorial for more info.

2. The Shiny app file structure

Next, select File/ New File/ Shiny Web App…, give the application a descriptive name (no spaces) and change the application type to “Single File (app.R)”, save the app in an appropriate directory and click Create.

RStudio generates a template R script called app.R. Delete all the code in the template so you have a blank script.

Notice that the name you gave to your app was assigned to the directory, not the app script file. For your app to work, the file must remain named app.R!

It is possible to create a Shiny app with two files called ui.R and server.R, but the same can be accomplished by using one file. In the past, Shiny apps had to be created using two files, but the Shiny package has since been updated to allow the single file app structure, making things much tidier. You will see some tutorials on the internet using the old two file structure, but these can be easily translated to the one file structure. This tutorial will assume you have the one file app structure.

Now we can set up the rest of the folders for your app. Add a folder called Data and a folder called www in your app directory. Data will hold any data used by the app and www will hold any images and other web elements.

To review, a Shiny application should have this specific folder structure to work properly:

Test_App
├── app.R
├── Data
│   └── data.csv
└── www
    └── A.jpg

3. app.R layout

Now that the folder structure is set up, head back to RStudio to start building app.R. A basic app.R consists of these five parts:

# Packages ----
library(shiny)  # Required to run any Shiny app
library(ggplot2)  # For creating pretty plots
library(dplyr)  # For filtering and manipulating data
library(agridat)  # The package where the data comes from
# Loading data ----
Barley <- as.data.frame(beaven.barley)
# ui.R ----
ui <- fluidPage()
# server.R ----
server <- function(input, output) {}
# Run the app ----
shinyApp(ui = ui, server = server)

Delete any example code generated automatically when you created app.R and create a basic Shiny app by copying the snippets of code above into your app.R. Your script should now look like this:

 # Packages ----
 library(shiny)  # Required to run any Shiny app
 library(ggplot2)  # For creating pretty plots
 library(dplyr)  # For filtering and manipulating data
 library(agridat)  # The package where the data comes from

 # Loading data ----
 Barley <- as.data.frame(beaven.barley)

 # ui.R ----
 ui <- fluidPage()

 # server.R ----
 server <- function(input, output) {}

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

Layout of a Shiny App

Shiny apps are structured using panels, which are laid out in different arrangements. Panels can contain text, widgets, plots, tables, maps, images, etc.

Here is a good set of examples on how the panel layout can be changed. The most basic layout uses fluidRow() and column() to manually create grids of a given size. fluidRow() allows a lot of customisation, but is more fiddly. In this tutorial, we will be using sidebarLayout(), which creates a large panel and a smaller inset side panel.

4. Creating a Shiny App - Basic Syntax

To illustrate how to code a Shiny app, we will recreate a simple app that I wrote to explore some data on the productivity of Barley genotypes.

You can get the code for this app by opening app.R in the Example_app folder in the tutorial repository which you downloaded earlier.

Looking at the app and comparing to the panel layout examples in the above link, we can see that the app has a sidebarLayout with a sidebarPanel, mainPanel and titlePanel. It uses a selectInput to choose the genotype of barley shown in the histogram and the table, another selectInput for the colour of the histogram, a sliderInput to choose the number of bins in the histogram and a textInput to display some text in the app. The histogram is located in the mainPanel along with a summary table of the data being shown, while the inputs are in the sidebarPanel.

Go back to your app.R and fill in the code you already have with the new bits of code below, which will serve as the basic skeleton for our app. Remember that you should only have one ui and one server object. Don’t just copy and paste the below:

# Packages ----
library(shiny)  # Required to run any Shiny app
library(ggplot2)  # For creating pretty plots
library(dplyr)  # For filtering and manipulating data
library(agridat)  # The package where the data comes from

# Loading data ----
Barley <- as.data.frame(beaven.barley)

# ui.R ----
ui <- fluidPage(
  titlePanel(""),  # Add a title panel
  sidebarLayout(  # Make the layout a sidebarLayout
    sidebarPanel(),  # Inside the sidebarLayout, add a sidebarPanel
    mainPanel()  # Inside the sidebarLayout, add a mainPanel
  )
)

# server.R ----
server <- function(input, output) {}

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

titlePanel() indicates that we would like a separate panel at the top of the page in which we can put the title.

sidebarLayout() indicates that we want our Shiny app to have the sidebar layout, one of many layouts we saw above. Within sidebarLayout we have:

sidebarPanel() indicates that we want a sidebar panel included in our app. Sidebar panels often contain input widgets like sliders, text input boxes, radio buttons etc.

mainPanel() indicates that we want a larger main panel. Main panels often contain the output of the app, whether it is a table, map, plot or something else.

Input widgets

Now that we have our basic structure we can start to fill it with inputs and outputs.

The example app has four input widgets, a selectInput for genotype, a selectInput for histogram colour, a sliderInput for number of bins and a textInput to add some arbitrary text. Each of these widgets provides information on how to display the histogram and its accompanying table. In the example app, all the widgets are found in the sidebarPanel so the code for these widgets should be put in the sidebarPanel command like this:

ui <- fluidPage(
  titlePanel("Barley Yield"),
  sidebarLayout(
    sidebarPanel(
      selectInput(inputId = "gen",  # Give the input a name "genotype"
      label = "1. Select genotype",  # Give the input a label to be displayed in the app
      choices = c("A" = "a","B" = "b","C" = "c","D" = "d","E" = "e","F" = "f","G" = "g","H" = "h"), selected = "a"),  # Create the choices that can be selected. e.g. Display "A" and link to value "a"
    selectInput(inputId = "colour", 
      label = "2. Select histogram colour", 
      choices = c("blue","green","red","purple","grey"), selected = "grey"),
    sliderInput(inputId = "bin", 
      label = "3. Select number of histogram bins", 
      min=1, max=25, value= c(10)),
    textInput(inputId = "text", 
      label = "4. Enter some text to be displayed", "")
    ),
  mainPanel()
  )
)

Note that choices = c("A" = "a" ... could be replaced with choices = unique(Barley$gen) to simply use the groups directly from the dataset.

Spend a couple of minutes looking at this code so you understand what it means, then fill in your own app.R with the code.

Let’s break down selectInput() to understand what is going on:

You can look into the arguments presented by the other input widgets by using the help function ?. For example, by running the code ?textInput in the R console.

More Input Widgets

There are plenty of pre-made widgets in Shiny. Here is a selection, each with the minimum number of arguments needed when running the app, though many more can be added:

actionButton(inputId = "action", label = "Go!")
radioButtons(inputId = "radio", label = "Radio Buttons", choices = c("A", "B"))
selectInput(inputId = "select", label = "select", choices = c("A", "B"))
sliderInput(inputId = "slider", label = "slider", value = 5, min = 1, max = 100)

Notice how all of the inputs require an inputId and a label argument.

Running a Shiny App

Take this opportunity to preview your app by clicking Run App:

RStudio GUI run app screenshot

or use the keyboard shortcut Cmd + Opt + R (Mac), Ctrl + Alt + R (Windows).

When a Shiny app is running from RStudio, the console cannot be used. To stop the app, click the Stop button in the top right of the console window or press the Esc key.

RStudio GUI run app cancel screenshot

Output

A Shiny app without any outputs is useless. Outputs can be in the form of plots, tables, maps or text.

As per our example app, we’re going to be using ggplot() to create a histogram. For more information on creating plots in ggplot2, see our tutorials on basic data visualisation and customising ggplot graphs.

Outputs are created by placing code in the curly brackets ({}) in the server object:

server <- function(input, output) {
  output$plot <- renderPlot(ggplot(Barley, aes(x = yield)) +  # Create object called `output$plot` with a ggplot inside it
  geom_histogram(bins = 7,  # Add a histogram to the plot
    fill = "grey",  # Make the fill colour grey
    data = Barley,  # Use data from `Barley`
    colour = "black")  # Outline the bins in black
  )                                                       
}

Look at the code above for a couple of minutes to understand what is going on, then add it to your own app.R in the appropriate place.

Basically, we are creating an object called output$plot and using renderPlot() to wrap a ggplot() command.

Reactive output

The histogram is great, but not particularly interactive. We need to link our input widgets to our output object.

We want to select individual genotypes to display in our histogram, which the user can select using the selectInput that we called genotype earlier. Use some base R wizardry, [] $ and ==, to select the data we want. Update server with the new reactive output arguments so it looks like the code below:

server <- function(input, output) {
  output$plot <- renderPlot(ggplot(Barley, aes(x = yield)) +
  geom_histogram(bins = 7,
      fill = "grey",
      data = Barley[Barley$gen == input$gen,],
      colour = "black")
  )                                                       
}

data = Barley[Barley$Genotype == input$gen,] tells geom_histogram() to only use data where the value in column gen is equal to (==) the value given by input$gen. Note the , after input$gen which indicates that we are selecting columns and that all the rows should be selected.

Next, we want to be able to change the colour of the histogram based on the value of the selectInput called colour. To do this, simply change fill = “grey” to fill = input$colour.

Next, we want to select the number of bins in the histogram using the sliderInput called bin. Simply change bins = 7 to bins = input$bin.

Finally, to create a table output showing some summary statistics of the selected genotype, create a new output object called output$table and use renderTable() to create a table generated using dplyr summarise(). See our tutorial on data manipulation for more information on dplyr. Update server with the output$table information so it looks like the code below:

server <- function(input, output) {
output$myhist <- renderPlot(ggplot(Barley, aes(x = yield)) + 
	geom_histogram(bins = input$bin, fill = input$col, group=input$gen, 
		data=Barley[Barley$gen == input$gen,],
  		colour = "black"))

output$mytext <- renderText(input$text)

output$mytable <- renderTable(Barley %>%
filter(gen == input$gen) %>%
summarise("Mean" = mean(yield), 
  	"Median" = median(yield),
  	"STDEV" = sd(yield), 
  	"Min" = min(yield),
  	"Max" = max(yield)))
}

Displaying output

To make the outputs appear on your app in the mainPanel, they need to be added to the ui object inside mainPanel() like so:

ui <- 
  fluidPage(
    titlePanel("Barley Yield"),
    sidebarLayout(
      position = "right",
      sidebarPanel(h3("Inputs for histogram"), 
                   selectInput("gen", "1. Select genotype", choices = c("A" = "a","B" = "b","C" = "c","D" = "d","E" = "e","F" = "f","G" = "g","H" = "h"), selected = "a"),
                   br(),
                   selectInput("col", "2. Select histogram colour", choices = c("blue","green","red","purple","grey"), selected = "grey"),
                   br(),
                   sliderInput("bin", "3. Select number of histogram bins", min=1, max=25, value= c(10)),
                   br(),
                   textInput("text", "4. Enter some text to be displayed", "")),
                   mainPanel(
                             plotOutput("myhist"),
                             tableOutput("mytable"),
                             textOutput("mytext")
                             )
      )
    )

Take this chance to preview your app again by clicking Run in RStudio.

Additional elements

HTML

To make your app look more pretty, you can add HTML tags like in a normal HTML webpage. Below is a table of basic HTML tags, their Shiny equivalent and a description of what they do:

HTML Shiny Function
<div> tags$div() Defines a block with consistent formatting
<br> tags$br() Inserts a break
<hr> tags$hr() Inserts a horizontal line
<p> tags$p() Creates a paragraph of text
<a> tags$a(href = "LINK", "displayed text") Creates a clickable link

A list of all HTML tags can be found using:

shiny::tags

Some tags may conflict with other functions and so you should always state the source the function comes from by using tags$, e.g.:

tags$div()

Tags can be stacked to apply many arguments to the same object/text, just as in HTML:

tags$div(style="color:red",
  tags$p("Visit us at:"),
  tags$a(href = "https://ourcodingclub.github.io", "Coding Club")
  )

This creates a block of text that is coloured red (style="color:red"), within that block there is a paragraph of text (tags$p("Visit us at?:")) and a link (tags$a(href = "http://ourcodingglub.github.io", "Coding Club")).

Add the code above to your Shiny app in mainPanel() and see what happens!

For more information on the arguments that can be included in popular Shiny HTML tags, RStudio have a nice wiki at [[https://shiny.rstudio.com/articles/tag-glossary.html]].

5. Exporting a finished app

As a Github repository

It is easy to send a Shiny app to somebody else who also has RStudio. The easiest way is to send app.R alongside any data and other resources in a zip file to be unzipped by the recipient and run through R.

If you want to quickly share the app over the internet we recommend using Github to host the file.

Go to Github, sign in with your account details, create a repository and upload everything from your app folder, including any Data and www folders.

Remember to add a file called README.md using Create new file in your new app repository, where you can write a quick explanation of the content of your app. .md files can use markdown syntax to create headers, sections, links etc.. See our tutorial on markdown and reproducible research for more markdown tips:

Github Create new file screenshot

To send the app to another person, give them your Github username and the name of the app repo and ask them to run runGithub() in R, like this:

runGitHub(repo = "repo_name", username = "user_name")

Alternatively, if your recipient doesn’t know how Github works, upload your app folder as a .zip file to Github or any other file-hosting service and they can use runUrl() if you give them the url of the zipfile:

runUrl("https://github.com/rstudio/shiny_example/archive/master.zip")

To learn more about Github, check out our tutorial on Git and Github.

As a shinyapps.io app

You can also host Shiny apps on www.shinyapps.io, a webhosting platform run by RStudio that is especially built for Shiny apps. Go to their website and sign up using whatever method you choose, then go to www.shinyapps.io/admin/#/tokens, click Show secret and copy the rsconnect account info:

shinyapps.io token screenshot

Then open up an R session and run the copied material to link shinyapps.io with R Studio.

To upload your app, open your app.R and click the publish button. Select a name for your app (no spaces) and click Publish.

RStudio RS Connect screenshot

The app can then be used by anyone with the URL for that app, which can be found by going to shinyapps.io and opening the app info from the dashboard:

shinyapps.io URL screenshot

To embed an app that is hosted by shinyapps.io, in your own website you can put it in an iframe, replacing the URL with your own app URL and altering the style arguments to your own desire:

<iframe src="https://johngodlee.shinyapps.io/barley_yield_exploration/" style="border:none;width:1000px;height:500px;"></iframe>

6. Challenge yourself to create a Shiny app

Now that you have the skills to create a Shiny app, try to create an app of your own and publish it to your shinyapps.io profile. Your app could use your own data if you have some, or one of the many datasets that come bundled with R. If you need more inspiration, have a look through the Shiny app gallery.


Stats from Scratch stream

Doing this tutorial as part of our Data Science for Ecologists and Environmental Scientists online course?

This tutorial is part of the Stats from Scratch stream from our online course. Go to the stream page to find out about the other tutorials part of this stream!

If you have already signed up for our course and you are ready to take the quiz, go to our quiz centre. Note that you need to sign up first before you can take the quiz. If you haven't heard about the course before and want to learn more about it, check out the course page.

Stay up to date and learn about our newest resources by following us on Twitter!
We would love to hear your feedback, please fill out our survey!
Contact us with any questions on ourcodingclub@gmail.com

Related tutorials: