Make a web app with Shiny

Today we will learn how to make and deploy interactive web applications with Shiny. Shiny allows you to display your R analysis on the web to anyone. For example:

The tutorial at Rstudio is good but pretty involved. I have tried to distill some of the principles below; if you like it and want more then I highly recommend the tutorial.

Resources

The cheat sheet may be helpful.

Components of a Shiny App

A ShinyApp has two main components components:

  • ui This controls the user interface (i.e. the design of the webpage, the input and the output).
  • server This does the work of performing any analysis, creating graphs, and creating tables

These components can:

  • be saved in two separate files, ui.R and server.R
  • OR combined into a single file, app.R.

For this class we will use the single-file version.

Anatomy of a single file Shiny App

A skeleton shiny app will looks like this:

library(shiny) #always required
library(tidyverse) # additional libraries if needed by your script

# load data
dat <- read_csv("path/to/my/cool/data")

# Preprocessing
# Any one-time data preprocessing code should go here

ui <- fluidPage(
  # Code to create the user interface goes here
)

server <- function(input, output) { # arguments named 'input' and 'output' are required.
  # Code to create plots and or tables based on user input goes here
}

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

Now let’s look more closely at the ui and server components

ui

Here is a sample ui object. This script makes use of R’s built in data set on iris. For more information on this data set you can type ?iris in R.

# Define UI for application that draws a histogram
ui <- fluidPage( #create the overall page
  
  # Application title
  titlePanel("Iris Data"),
  
  # Some helpful information
  helpText("This application creates a boxplot to show difference between",
           "iris species.  Please use the radio box below to choose a trait",
           "for plotting"),
  
  # Sidebar with a radio box to input which trait will be plotted
  sidebarLayout(
    sidebarPanel(
      radioButtons("trait", #the input variable that the value will go into
                   "Choose a trait to display:",
                   c("Sepal.Length",
                     "Sepal.Width",
                     "Petal.Length",
                     "Petal.Width")
      )),
      
      # Show a plot of the generated distribution
      mainPanel(
        plotOutput("boxPlot")
      )
    )
  )

There are several components in the above code (and note that they are nested)

  • fluidPage This creates the layout for our webpage. The webpage has three components:
    • titlePanel Should be obvious
    • helpText Should be obvious
    • sidebarLayout Creates a sidebar layout within fluidpage.
      • sidebarPanel Specifies the sidebar panel.
        • radioButtons Specifies that we want radio buttons in this sidebar panel. We could have additional input functions here.
      • mainPanel Specifies that we want a main panel as well.
      • plotOutput What we want on the main panel. We could have more than one of these, or could have tables, etc.

To see all the types of input and output that can be included, see the Shiny reference. Of particular interest:

  • tabPanel If we want multiple tabs on the page.
  • checkboxInput
  • sliderInput
  • tableOutput
  • textOutput

server

Below is an example of the server component to accompany the ui above

# Define server logic required to draw a boxplot
server <- function(input, output) {
  
  # Expression that generates a boxplot. The expression is
  # wrapped in a call to renderPlot to indicate that:
  #
  #  1) It is "reactive" and therefore should re-execute automatically
  #     when inputs change
  #  2) Its output type is a plot
    
  output$boxPlot <- renderPlot({
    
    plotTrait <- as.name(input$trait) # convert string to name
    
    # set up the plot
    pl <- ggplot(data = iris,
                 aes(x=Species,
                            y= !! plotTrait, # !! to use the column names contained in plotTrait
                            fill=Species
                            )
    )
    
    # draw the boxplot for the specified trait
    pl + geom_boxplot()
  })
}

The key elements of the above code:

  • server <- function We are creating a function called server that will do analyses and create plots or tables for our app.
    • renderPlot This tells R that the enclosed code will generate a plot that is to be put on the webpage. Note that there are similar functions for outputting tables and text.
  • Information is passed between the ui and server components via the input and output variables.
    • In the ui component we specified that the radioButton() information should be placed in “trait”. server accesses that through input$trait.
    • Similarly in the server component we specify that the rendered plot goes into output$boxPlot. Then in ui we can access the plot as “boxPlot”.
  • Pay attention to the modifications in how variables are given in the aes() argument to ggplot. Because we want aes() to use the contents of input$trait to select a column, we first have to convert input$trait to a name with as.name() (placing the contents in plotTrait) and then use !! to tell aes() to get the name out of plotTrait instead of just taking it literally as a column name.
  • Important any one-time data loading or manipulation (i.e. reading in a file) should be done BEFORE, not within, any renderNNN statements. You can put it at the beginning of the script.

Create a team repo

Before getting started:

  • One person in each team should click the github assignment link, create a team, and create a repo.
  • Other members of the team should then click on the github link and join that team.
  • Everyone should clone the repo.

trying the demoApp

Clone the assignment repo. You will find two directories in the repo demoApp and teamApp

demoApp contains a working version of the app described above. In Rstudio, navigate into the demoApp directory, and then click on app.R.

Run the app by clicking on the runApp button at the top of the script pane.

Exercise 1 (2 pts)

Work with your partner to:

Change the demoApp script so that a violin plot is produced instead of a boxplot.

Exercise 2 (2 pts)

Work with your partner to:

Change the demoApp script so that all of the traits are plotted as a violing plot but only for a single species. (The x-axis should be trait; the user selects species).

Push your changes.

Create a team app

Your team should work together to create and deploy a ShinyApp that plots some aspect of the data from the BLAST or RICE labs. The app should allow user input that modifies the plot in a useful way.

I have listed some ideas below, but feel free to choose something else

RICE data ideas

You might want to limit the user input to 5 or 10 traits in the examples below, just to save yourself some typing and to keep the radio button list not too long (or use selectize)

  • Interactive plot showing histograms or violin plots or boxplots of user-selected phenotypic data split by ancestral population assignment or region. You could also allow the user to choose whether it was a histogram or a violin plot, etc.
  • Scatter plot of any two traits (user chosen), colored by the values of a third (user chosen).
  • If you want to get fancy in either of the above then you could use the selectize tool to allow the user to select from all of the possible phenotypes.

Other data ideas

  • Feel free to use any data set that you are interested in; if you work in an lab maybe a data set from your lab work.
  • You could use the tomato data set that was used in the ggplot tutorial and:
    • explore the relationship between altitude and plant height
    • plot trait averages per species letting the user choose the trait
    • etc.

Download tomato data here

Scoring (out of 20 points)

4 points for the modifications to the demoApp (Exercises 1 and 2 above).

12 points for a functional, interactive web app deployed on shinyapps.io and pushed to GitHub.

+ 2 points for using two or more input widget types (slider and radio buttons, for example). + 2 points for good annotation on the web page (a new user would understand what the app is about).
- 2 or more points for each student that does not make at least 2 substantive commits to the team repository.

Getting started with the Team App

  • Discuss your goals and what you want your final product to look like with your team members.
  • There is a skeleton app.R inside the teamApp directory in your repo. Build your app there.
  • Start simple.
  • Remember that you can use git commit and push and pull to share your file changes among the team. I recommend that you do not have two people work on the same section of the same file at once; it makes it hard to do automatic merge when you pull.
  • Once you get it running, sign up for an account and deploy it on shiny.io. See deployment, below.
  • Place a link to your shiny web app in the README.md in your github repository.
  • List the students that contributed in your README.md in your github repository.

Going further

To get further inspiration, checkout out the Shiny Gallery.

You can also include Shiny apps directly in your Rmarkdown files to be rendered into html. In some ways the syntax is even easier because you only need a single file. You can also include interactive graphs in slide presentations this way.

Deployment

Once you have an awesome application how do you share it?

For this lab, we will use Rstudio’s free shiny server.

To use their server (required to complete the assignment, but wait to do these steps until you have your app working)

  • One person in your group needs to go to the shiny io website and register for an account. You can use your github or google ID.
  • After registering go to account > tokens. Click on “show”, Click on “Show Secret”, and then “copy to clipboard”
  • Paste it into the R command below and run it. It should look something like:
rsconnect::setAccountInfo(name='jnmaloof', token='45515FE2BB923C41A95D9768C9AD6F91', secret='somelonggibberishheredonotshare')
  • This only needs to be done once per computer.

Once you have signed up for an account and authenticated it a simple as:

library(rsconnect)
deployApp('path/to/your/app')

The above process is also described in the Shinyio user guide if would like more details.

You can see my version here.

Other ways to deploy (NOT NEEDED FOR BIS180L)

Now that we have our awesome application how do we share it?

Multiple options:

  1. If you are sharing it with someone that uses R and has the shiny library installed, then you can just send it to them, they can download it, and run it as above.
  2. If you have it on GitHub and the person you want to share it with has R they can use:

     library(shiny)
     runGitHub(repo = "HamiltonDemos",username = "jnmaloof", subdir = "BinomialDrift")
    
  3. You can use Rstudio’s free shiny server.

(see above)

  1. If you are advanced you can run your own server (I actually set up a server for my lab–it isn’t that hard).