Author

Ben Best

Published

2023-03-06

Background

Here’s a presentation to accompany these introductory materials:

Creating Interactive Web Applications with R & Shiny

Numbered folders in this repository correspond with iterative development and enhancement of a Shiny app:

  • 01_faithful: default app from using RStudio, File > New File > Shiny Web App…
  • 02_quakes_mag: swap to quakes dataset, adjust histogram by magnitude
  • 03_quakes_depth: add depth slider, select box for variable to histogram
  • 04_quakes_map: add leaflet map
  • 05_quakes_dashboard: enhance ui with shinydashboard

The latest versions of R and RStudio are highly recommended to follow along.

The following sections in this Rmarkdown document demonstrate how you can develop output visualizations for use in a Shiny app, especially by defining input variables as a list (input$*). Knitting this Rmarkdown document docs/index.Rmd to docs/index.html in this repo and pushing to Github then allows the HTML to be viewable at https://bbest.github.io/shiny-intro (using the Github Pages feature). In contrast, note that Github and most web hosting services can not host a Shiny app. Although the leaflet and plotly visualizations in this document are interactive in the web browser, they do not require the Shiny library or a Shiny server to be displayed. Rather, the HTML output can be easily hosted on the most basic web server or passed as an email attachment. The Shiny context allows for ultimate flexibility with user interactions, but may be overkill for basic visualization. Check out all the amazing htmlwidgets.org and framework that works in the three contexts of: 1) RStudio, 2) Rmarkdown, and 3) Shiny.

Download

To run locally, first download the repository of files here:

  • https://github.com/bbest/shiny-intro/archive/master.zip

(Or use git clone https://github.com/bbest/shiny-intro.git.) Then unzip and launch RStudio into that working directory by double-clicking on the shiny-intro.Rproj file.

01_faithful

  • Code: 01_faithful

  • Run from GitHub:

    shiny::runGitHub("bbest/shiny-intro", subdir="01_faithful")
  • Run locally:

    shiny::runApp("01_faithful")

In order to quickly experiment with visualization, we could pull the code from within the rendering function of the Shiny app and set the input list values that would otherwise be set from the user interface…

Code
input = list(bins = 30)

x <- faithful[, 2] 
bins <- seq(min(x), max(x), length.out = input$bins + 1)
    
hist(x, breaks = bins, col = 'darkgray', border = 'white')

02_quakes_mag

Code
library(tidyverse)

input <- list(slider_mag = c(4, 6))

d <- quakes %>%
  filter(
    mag >= input$slider_mag[1],
    mag <= input$slider_mag[2])

hist(d$mag, col = 'darkgray', border = 'white')

  • Code: 02_quakes_mag

  • Run from GitHub:

    shiny::runGitHub("bbest/shiny-intro", subdir="02_quakes_mag")
  • Run locally:

    shiny::runApp("02_quakes_mag")

03_quakes_depth

Code
library(tidyverse)

input <- list(
  select_var = "depth", 
  slider_mag = c(4, 5), 
  slider_depth = c(0, 100))

d <- quakes %>%
  filter(
    mag   >= input$slider_mag[1],
    mag   <= input$slider_mag[2],
    depth >= input$slider_depth[1],
    depth <= input$slider_depth[2])

hist(d[,input$select_var], col = 'darkgray', border = 'white')

04_quakes_map

Code
library(leaflet)
library(glue)

leaflet(data = quakes[1:20,]) %>% 
  addTiles() %>%
  addCircleMarkers(
    radius = ~mag, color = "red", stroke = FALSE, fillOpacity = 0.5,
    popup = ~glue("<b>mag</b>: {mag}<br>depth: {depth} m"), label = ~as.character(mag))
  • Code: 04_quakes_map

  • Run from GitHub:

    shiny::runGitHub("bbest/shiny-intro", subdir="04_quakes_map")
  • Run locally:

    shiny::runApp("04_quakes_map")

05_quakes_dashboard

Use: - http://rstudio.github.io/shinydashboard - https://github.com/tidyverse/ggplot2 - https://plot.ly/ggplot2

Code
library(tidyverse)
library(glue)

input <- list(
  select_var   = "depth", 
  slider_mag   = c(4, 5), 
  slider_depth = c(0, 100))

get_df <- function(){
  df <- quakes %>%
    filter(
      mag   >= input$slider_mag[1],
      mag   <= input$slider_mag[2],
      depth >= input$slider_depth[1],
      depth <= input$slider_depth[2])
  df$var <- df[[input$select_var]]
  df
}

df        <- get_df()
bin_width <- min(c(7, length(unique(df$var))))
    
g <- ggplot(df, aes(var)) + 
  geom_histogram(binwidth=bin_width)

plotly::ggplotly(g)
  • Code: 05_quakes_dashboard

  • Run from GitHub:

    shiny::runGitHub("bbest/shiny-intro", subdir="05_quakes_dashboard")
  • Run locally:

    shiny::runApp("05_quakes_dashboard")
  • View app directly: https://bdbest.shinyapps.io/05_quakes_dashboard

Rmarkdown using Crosstalk

  • https://rstudio.github.io/crosstalk
Code
library(crosstalk)
library(leaflet)
library(DT)

# Wrap data frame in SharedData
sd <- SharedData$new(quakes[sample(nrow(quakes), 100),])

# Create a filter input
filter_slider("mag", "Magnitude", sd, column=~mag, step=0.1, width=250)
Code
# Use SharedData like a dataframe with Crosstalk-enabled widgets
bscols(
  leaflet(sd) %>% 
    addTiles() %>% 
    addMarkers(),
  datatable(
    sd, extensions="Scroller", style="bootstrap", class="compact", width="100%",
    options=list(deferRender=TRUE, scrollY=300, scroller=TRUE)))