An introduction to shiny apps
Jack Dolgin
What are they?
Interactive graph/tables/pseudo-websites
shiny.john-coene.com/coronavirus/

Statistics

malcolmbarrett.shinyapps.io/precisely/

Teaching

dgranjon.shinyapps.io/entry_level/

Running surveys

jwyckoff.shinyapps.io/TIPIpersonality/
daattali.com/shiny/mimic-google-form/

Upload and perform eye-tracking analyses without coding

colinquirk.shinyapps.io/shinyeyes/

Upload and analyze EEG data without coding

electrophysiology.shinyapps.io/BacAv/

Build pseudo-websites for studies

pablobernabeu.shinyapps.io/Dutch-modality-exclusivity-norms/

Analyze brain data

rpomponio.shinyapps.io/neuro_lifespan/
carolinaeuan.shinyapps.io/hcc-vis/
shiny.rstudio.com/gallery/isee.html
You have convinced me, Jack
Ok just tell me how to make them already
I like how you think
Are there going to be memes on every slide?
What did I sign up for?
Really, just two parts

Interface

Server

gallery.shinyapps.io/013-selectize/_w_aa3b0136/_w_8c716b7f

Interface

Server

Build and learn
youtu.be/Gyrfsrd4zK0?t=96
shiny.rstudio.com/gallery/sliders.html
Aim: Build a slider
Given

								# Hint: https://gallery.shinyapps.io/077-widget-slider/
							
Solution

								sliderInput("timeRange",
								  label = "Time range to plot",
								  min = -199,
								  max = 598,
								  value = c(-100, 400))
							

								function(input, output){

								}
							
Aim: Build a responsive app
Given

								sliderInput("timeRange",
								  label = "Time range to plot",
								  min = -199,
								  max = 598,
								  value = c(-100, 400))
							

								# tidyverse is already loaded for you
								library(tidyverse)

								# imports data and helper function
								source("setup_helper.R")

								function(input, output){
								  # Delete this comment, replace
								  # with missing line

								  # This line calls ggplot(data, aes) and
								  # other helper functions for plotting
								  graph_setup +

								    # Replace the two underscores with the
								    # correct values
								    coord_cartesian(xlim = _____, ____)

								  }
							


							# The dataset and most of this code are taken from https://github.com/craddm/ERPdemo/blob/master/ERPdemo/app.R
							# You won't have to make any changes to this script

							dataset <- read_csv(
							  "https://raw.githubusercontent.com/craddm/ERPdemo/master/ERPdemo/data/levCatObjNon.csv",
							  c("Object", "Non-Object",
							    "Time", "Subject")) %>%
							  mutate(
							   Difference = Object - `Non-Object`) %>%
							  gather(condition, amplitude,
							  	-Time, -Subject) %>%
							  mutate(
							    effectType = factor(if_else(
							      condition == "Difference", "Difference",
								  "Main"
							    )),
							    condition = factor(
							      condition,
							      levels = c("Object", "Non-Object",
								  	"Difference"),
							      labels = c("Object", "Non-Object",
								  	"Difference")
							    )
							  )

							dataset$Subject <- factor(dataset$Subject)
							dataset$condition <- factor(dataset$condition)


							graph_setup <- ggplot(data = dataset,
									      aes(Time, amplitude)) +
							  list(
							    scale_color_brewer(palette = "Set1"),
							    theme_minimal(),
							    stat_summary(
							      data = dataset,
							      fun = mean,
							      geom = "line",
							      size = 1,
							      aes(colour = condition)
							    ),
							    scale_colour_discrete(
								  limits = levels(dataset$condition)),
							    labs(
								  x = "Time (ms)",
								  y = expression(paste(
								    "Amplitude (",mu,"V)")),
								  colour = ""),
							    geom_vline(xintercept = 0,
								  linetype = "dashed" ),
							    geom_hline(yintercept = 0,
								  linetype = "dashed"),
							    theme(
								 axis.text = element_text(size = 14),
								 axis.title = element_text(size = 14),
								 legend.text = element_text(size=14))
							  )
							
Solution

								fluidPage(
								  sliderInput("timeRange",
								    label = "Time range to plot",
								    min = -199,
								    max = 598,
								    value = c(-100, 400)),
								  plotOutput("main_plot"))
							

								# tidyverse is already loaded for you
								library(tidyverse)

								# imports data and helper function
								source("setup_helper.R")

								function(input, output){
								  output$main_plot <- renderPlot({

								    # This line calls ggplot(data, aes) and
								    # other helper functions for plotting
								    graph_setup +

								      coord_cartesian(
									    xlim = c(input$timeRange[1],
										  input$timeRange[2]))
								    })
								  }

							


								# The dataset and most of this code are taken from https://github.com/craddm/ERPdemo/blob/master/ERPdemo/app.R
								# You won't have to make any changes to this script

								dataset <- read_csv(
								  "https://raw.githubusercontent.com/craddm/ERPdemo/master/ERPdemo/data/levCatObjNon.csv",
								  c("Object", "Non-Object",
								    "Time", "Subject")) %>%
								  mutate(
								   Difference = Object - `Non-Object`) %>%
								  gather(condition, amplitude,
								  	-Time, -Subject) %>%
								  mutate(
								    effectType = factor(if_else(
								      condition == "Difference", "Difference",
									  "Main"
								    )),
								    condition = factor(
								      condition,
								      levels = c("Object", "Non-Object",
									  	"Difference"),
								      labels = c("Object", "Non-Object",
									  	"Difference")
								    )
								  )

								dataset$Subject <- factor(dataset$Subject)
								dataset$condition <- factor(dataset$condition)


								graph_setup <- ggplot(data = dataset,
										      aes(Time, amplitude)) +
								  list(
								    scale_color_brewer(palette = "Set1"),
								    theme_minimal(),
								    stat_summary(
								      data = dataset,
								      fun = mean,
								      geom = "line",
								      size = 1,
								      aes(colour = condition)
								    ),
								    scale_colour_discrete(
									  limits = levels(dataset$condition)),
								    labs(
									  x = "Time (ms)",
									  y = expression(paste(
									    "Amplitude (",mu,"V)")),
									  colour = ""),
								    geom_vline(xintercept = 0,
									  linetype = "dashed" ),
								    geom_hline(yintercept = 0,
									  linetype = "dashed"),
								    theme(
									 axis.text = element_text(size = 14),
									 axis.title = element_text(size = 14),
									 legend.text = element_text(size=14))
								  )
							
Aim: Add choices
Given

								fluidPage(
								  sliderInput("timeRange",
								    label = "Time range to plot",
								    min = -199,
								    max = 598,
								    value = c(-100, 400)),
								  plotOutput("main_plot"))
							

								# tidyverse is already loaded for you
								library(tidyverse)

								# imports data and helper functions
								source("setup_helper.R")

								function(input, output){
								  output$main_plot <- renderPlot({

								    # This line calls ggplot(data, aes) and
								    # other helper functions for plotting
								    graph_setup +

								      coord_cartesian(
									    xlim = c(input$timeRange[1],
										  input$timeRange[2]))
								    })
								  }

							

								# The dataset and most of this code are taken from https://github.com/craddm/ERPdemo/blob/master/ERPdemo/app.R
								# You won't have to make any changes to this script

								dataset <- read_csv(
								  "https://raw.githubusercontent.com/craddm/ERPdemo/master/ERPdemo/data/levCatObjNon.csv",
								  c("Object", "Non-Object",
								    "Time", "Subject")) %>%
								  mutate(
								   Difference = Object - `Non-Object`) %>%
								  gather(condition, amplitude,
								  	-Time, -Subject) %>%
								  mutate(
								    effectType = factor(if_else(
								      condition == "Difference", "Difference",
									  "Main"
								    )),
								    condition = factor(
								      condition,
								      levels = c("Object", "Non-Object",
									  	"Difference"),
								      labels = c("Object", "Non-Object",
									  	"Difference")
								    )
								  )

								dataset$Subject <- factor(dataset$Subject)
								dataset$condition <- factor(dataset$condition)


								graph_setup <- ggplot(data = dataset,
										      aes(Time, amplitude)) +
								  list(
								    scale_color_brewer(palette = "Set1"),
								    theme_minimal(),
								    stat_summary(
								      data = dataset,
								      fun = mean,
								      geom = "line",
								      size = 1,
								      aes(colour = condition)
								    ),
								    scale_colour_discrete(
									  limits = levels(dataset$condition)),
								    labs(
									  x = "Time (ms)",
									  y = expression(paste(
									    "Amplitude (",mu,"V)")),
									  colour = ""),
								    geom_vline(xintercept = 0,
									  linetype = "dashed" ),
								    geom_hline(yintercept = 0,
									  linetype = "dashed"),
								    theme(
									 axis.text = element_text(size = 14),
									 axis.title = element_text(size = 14),
									 legend.text = element_text(size=14))
								  )
								  add_check_boxes <- function(myval){
								    if (is.null(myval) == FALSE){
								      list(
								        geom_line(
									  data = filter(dataset,
									                effectType %in% myval),
								          aes(group = interaction(
										  Subject, condition),
								            colour = condition,
								            alpha = 0.2
								          )),
								        guides(alpha = "none")
								      )
								    }
								  }
							
Solution

								fluidPage(
								  titlePanel("Exploring ERP plot options"),

								  sidebarLayout(
								    sidebarPanel(
								      sliderInput("timeRange",
								        label = "Time range to plot",
								        min = -199,
										max = 598,
										value = c(-100, 400)),

								      checkboxGroupInput(
								        "indivEffects",
								        label = h4("Individual effects"),
								        choices = list("Main effects" = "Main",
								          "Difference waves" = "Difference"),
								        inline = TRUE
								      )
								    ),
								    mainPanel(
								      plotOutput("main_plot")
								    )
								  )
								)

							


								# tidyverse is already loaded for you
								library(tidyverse)

								# imports data and helper functions
								source("setup_helper.R")

								function(input, output){
								  output$main_plot <- renderPlot({

								    # This line calls ggplot(data, aes) and
								    # other helper functions for plotting
								    graph_setup +

								      coord_cartesian(
									    xlim = c(input$timeRange[1],
										  input$timeRange[2])) +
									add_check_boxes(input$indivEffects)
								    })
								  }
							


								# The dataset and most of this code are taken from https://github.com/craddm/ERPdemo/blob/master/ERPdemo/app.R
								# You won't have to make any changes to this script

								dataset <- read_csv(
								  "https://raw.githubusercontent.com/craddm/ERPdemo/master/ERPdemo/data/levCatObjNon.csv",
								  c("Object", "Non-Object",
									"Time", "Subject")) %>%
								  mutate(
								   Difference = Object - `Non-Object`) %>%
								  gather(condition, amplitude,
									-Time, -Subject) %>%
								  mutate(
								   effectType = factor(if_else(
								     condition == "Difference", "Difference",
								       "Main"
								    )),
									condition = factor(
									  condition,
									  levels = c("Object", "Non-Object",
										"Difference"),
									  labels = c("Object", "Non-Object",
										"Difference")
									)
								  )

								dataset$Subject <- factor(dataset$Subject)
								dataset$condition <- factor(dataset$condition)


								graph_setup <- ggplot(data = dataset,
											  aes(Time, amplitude)) +
								  list(
									scale_color_brewer(palette = "Set1"),
									theme_minimal(),
									stat_summary(
									  data = dataset,
									  fun = mean,
									  geom = "line",
									  size = 1,
									  aes(colour = condition)
									),
									scale_colour_discrete(
									  limits = levels(dataset$condition)),
									labs(
									  x = "Time (ms)",
									  y = expression(paste(
										"Amplitude (",mu,"V)")),
									  colour = ""),
									geom_vline(xintercept = 0,
									  linetype = "dashed" ),
									geom_hline(yintercept = 0,
									  linetype = "dashed"),
									theme(
									 axis.text = element_text(size = 14),
									 axis.title = element_text(size = 14),
									 legend.text = element_text(size=14))
								  )

								  add_check_boxes <- function(myval){
								    if (is.null(myval) == FALSE){
								      list(
								        geom_line(
									  data = filter(dataset,
									                effectType %in% myval),
								          aes(group = interaction(
										  Subject, condition),
								            colour = condition,
								            alpha = 0.2
								          )),
								        guides(alpha = "none")
								      )
								    }
								  }
							
Downsides?
View count
Speed
Flexibility

But the app can be downloaded via Github and run locally for unlimited time

shinyapps.io/#pricing
Can always embed a lot of html/css/javascript
ceefluz.shinyapps.io/radar/_w_38fd0d0b/
github.com/ceefluz/radar/blob/master/www/radar_style.css

Putting it all together

craddm.shinyapps.io/ERPdemo/
Ta da
Special thanks to Dr. Matthew Craddock, who permitted the re-use of his data and analyses
Presentation code