Goal

Components of a Shiny App

A ShinyApp has two 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

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 processing 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)
}

ui and server Information Transfer

Information must be sent between the ui and server functions

User input: trait in ui can be accessed as input$trait in server

ui:

radioButtons("trait", #the input variable that the value will go into
             "Choose a trait to display:", #title
             c("Sepal.Length","Sepal.Width",
               "Petal.Length","Petal.Width") ) #options

server:

  output$boxPlot <- renderPlot({
    plotTrait <- as.name(input$trait) # convert user input to a name
        pl <- ggplot(data = iris,aes(x=Species,
                                     y= !! plotTrait,
                                     fill=Species))
        pl + geom_boxplot()
  })

ui and server Information Transfer

output to ui: output$boxPlot in server is accessed as boxPlot in ui

ui

mainPanel(plotOutput("boxPlot"))

server

  output$boxPlot <- renderPlot({
    plotTrait <- as.name(input$trait) # convert user input to a name
        pl <- ggplot(data = iris,aes(x=Species,
                                     y= !! plotTrait,
                                     fill=Species))
        pl + geom_boxplot()
  })

ui and server Information Transfer

Summary:

  • In the server function, the objects output and input contain the information going to and from the ui
  • In server each item must be accessed as an element of input or output (e.g. input$trait)
  • In the ui function, the element names are used directly (with quotes).

IMPORTANT: Force eval in ggplot with !!

ggplot aes() uses something called non-standard evaluation, which makes it easy to specify columns by name.

colnames(iris)
## [1] "Sepal.Length" "Sepal.Width"  "Petal.Length" "Petal.Width"  "Species"
iris %>% ggplot(aes(x=Sepal.Length)) + geom_histogram() 

IMPORTANT: Force eval in ggplot with !!

  • Difficult to specify columns for ggplot aes() indirectly.
  • What if you have the column name specified in a variable?
  • Need this to allow users to select traits in your Shiny app.
input <- list(trait="Sepal.Length")
input$trait
## [1] "Sepal.Length"

Will R would substitute “Sepal.Length” for input$trait ??

iris %>% ggplot(aes(x= input$trait)) + geom_histogram() 
## Error in `geom_histogram()`:
## ! Problem while computing stat.
## ℹ Error occurred in the 1st layer.
## Caused by error in `setup_params()`:
## ! `stat_bin()` requires a continuous x aesthetic
## ✖ the x aesthetic is discrete.
## ℹ Perhaps you want `stat="count"`?

aes() Looks for a column called “input$trait” or takes the text inside (“Sepal.Length”) literally and does not know to look for a column named “Sepal.Length”.

IMPORTANT: Force eval in ggplot with !!

  • The solution is to use as.name() and !!
  • as.name() gets rid of the quotes around Sepal.Length and tells R that we want to use this as a name.
  • !! Tells R to get the value of whatever follows it.
input <- list(trait="Sepal.Length")
plotTrait <- as.name(input$trait) # convert to a name

# use !! to substitute Sepal.Length for selected.column
iris %>% ggplot(aes(x= !! plotTrait )) + geom_histogram() 

Keep your script fast

  • Anything within a renderNNN statement will be run every time that the plot changes.
  • So load data files and do one-time calculations at the begining of your app.R script.

server.R:

library(shiny)
library(ggplot2)

#load files and do one-time calculations here!

shinyServer(function(input, output) {
  output$boxPlot <- renderPlot({
    
  # Anything here gets re-run every time user input changes!
...

Running on your computer

To run a shiny app on your computer, save the app.R script in a directory for this app.

  • Click on the RunApp Button in R studio
  • OR from the R console:
library(shiny)
runApp('PATH_TO_APP_DIRECTORY')    

Sharing

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.

Sharing: GitHub

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")

Sharing: www.shinyapps.io

You can use Rstudio’s free shiny server Once you have signed up for an account and authenticated, it is as simple as:

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

You can see my version here

Sharing: set up your own server

If you are advanced you can run your own server

(I actually set up a server my lab–it isn’t that hard)

Teams

We will work in our normal breakout room teams. Each team will produce and deploy a Shiny app that will be collectively graded.

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, or from the tomato measurements data set that you used for the ggplot tutorial, available here. 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

  • Make an interactive version of any of the plots you made for Assignment 4
  • 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.
    • You could allow the user to choose the binwidth for the histogram
  • 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 traits.

Other data ideas

  • If any of you have a data set from your lab work you could use that.
  • You could use the tomato data set that was used in the ggplot tutorial and explore relationship between altitude and plant height, or plot trait averages per species letting the user choose the trait, etc. (Link to data in webpage).

Scoring (out of 20 points)

4 points for exercises on demoApp

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

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