Make a web app with Shiny
11 May 2023Today 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:
- I used Shiny to write an app to visualize a Markov Chain simulation of genetic drift.
- A student from the 2014 BIS180L worked in my lab to start a visualizer for QTL data and gene expression.
- The Shiny website has plenty of additional examples.
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 consists of two R scripts:
- ui.R This script controls the user interface (i.e. the design of the webpage, the input and the output).
- server.R This script does the work of performing any analysis, creating graphs, and creating tables
These two scripts must be saved together in a single directory. Each app much be saved in a different directory. (It is now possible to combine these into a single script but we will keep them separate for this class)
ui.R
Here is a sample ui.R script. 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.
library(shiny)
# Define UI for application that draws a histogram
shinyUI(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 script (and note that they are nested)
shinyUI
This is the overall function that creates that user interfacefluidPage
This creates the layout for our webpage. The webpage has three components:titlePanel
Should be obvioussidebarLayout
Creates a sidebar layout within fluidpagesidebarPanel
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 wellplotOutput
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 pagecheckboxInput
sliderInput
tableOutput
textOutput
server.R
Below is an example of a server script to accompany the ui script above
library(shiny)
library(tidyverse)
# Define server logic required to draw a boxplot
shinyServer(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 script:
shinyServer
this creates the server application.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.R and server.R scripts via the
input
andoutput
variables.- In the ui.R script we specified that the
radioButton()
information should be placed in “trait”. server.R accesses that throughinput$trait
- Similarly in the server.R script we specify that the rendered plot goes into output$boxPlot. Then in ui.R we can access the plot as “boxPlot”
- In the ui.R script we specified that the
- Pay attention to the modifications in how variable are given in the
aes()
argument toggplot
. Because we wantaes()
to use the contents ofinput$trait
to select a column, we first have to convertinput$trait
to a name withas.name()
(placing the contents inplotTrait
) and then use!!
to tellaes()
to get the name out ofplotTrait
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 just below thelibrary
statements, before theshinyServer
trying it
To try the app on your computer:
- Create a new directory for this app
demoApp
(you can use a different name) - Save the above scripts in ui.R and server.R, respectively, inside the ‘demoApp` directory that you just created for this app.
- Then either press the “RunApp” button in Rstudio, or, from the R console:
library(shiny)
runApp('PATH_TO_APP_DIRECTORY')
If your working directory is the App directory, you can leave out the path to the App directory. ie runApp()
will run the App
Practice 1 (not graded)
Change the scripts above so that a violin plot is produced instead of a boxplot.
Practice 2 (not graded)
Change the scripts above so that all of the traits are plotted as a boxplot but only for a single species. (The x-axis should be trait; the user selects species).
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](http://www.shinyapps.io/) 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
Assignment
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 relationship between altitude and plant height
- plot trait averages per species letting the user choose the trait
- etc.
Scoring (out of 20 points)
16 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 assignment
- One person in each team should click github 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.
- Discuss your goals and what you want your final product to look like with your team members.
- Start by having one person create an app using the RStudio template
- click on the green “+” RStudio and select “Shiny Web App”.
- select “multiple file”, give it a name, and have it save it in your repo.
- you can then modify these files to make it your own.
- 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, above.
- 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.
Other ways to deploy (NOT NEEDED FOR BIS180L)
deployment
Now that we have our awesome application how do we share it?
Multiple options:
- 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.
-
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")
-
You can use Rstudio’s free shiny server
To use their server (required to complete the assignment)
- 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” and then “copy to clipboard”
- Paste it into R. 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
- If you are advanced you can run your own server (I actually set up a server my lab–it isn’t that hard)