# load the necessary libraries
library(tidyverse)
library(shiny)
library(readr)
library(janitor)
library(purrr)
library(lubridate)
library(DT)
library(ggthemes)
library(rvest)
library(polite)Class Activity 18
Basic Shiny App for Tracking COVID-19 Trends
The Shiny app you are developing will allow users to interactively select parameters such as month, year, and county to visualize COVID-19 trends in Minnesota based on real-time data scraping and manipulation.
Read Data
table_usafacts <- bow(url = "https://usafacts.org/visualizations/coronavirus-covid-19-spread-map/state/minnesota") %>%
  scrape() %>%  html_nodes("a") %>%       # find all links
  html_attr("href") %>%     # get the url
  str_subset(".csv")        # find those that end in csvlibrary(lubridate)
covid_data <- read_csv(table_usafacts[2]) %>% filter(State == "MN") %>% 
  select(-countyFIPS, -StateFIPS, -State) %>% 
  slice(-1) %>% 
  pivot_longer(-1, names_to = "Dates", values_to = "Cases") %>% 
  janitor::clean_names() %>% 
  mutate(county_name = str_remove(county_name, " County"), 
         dates = ymd(dates), 
         counties = factor(county_name), 
         month = month(dates), 
         year = year(dates)) %>%
  select(-county_name)
head(covid_data)# A tibble: 6 × 5
  dates      cases counties month  year
  <date>     <dbl> <fct>    <dbl> <dbl>
1 2020-01-22     0 Aitkin       1  2020
2 2020-01-23     0 Aitkin       1  2020
3 2020-01-24     0 Aitkin       1  2020
4 2020-01-25     0 Aitkin       1  2020
5 2020-01-26     0 Aitkin       1  2020
6 2020-01-27     0 Aitkin       1  2020
# County level data
county_names <- covid_data %>% pull(counties) %>% unique()
county_data <- map(county_names, ~filter(covid_data, counties == .x))You’re already given the code to scrape, clean, and manipulate the data. Ensure that the data frame covid_data is correctly formatted, with each row representing a unique combination of date and county case counts. The transformations include:
- Pivoting the data to a long format where each date-case pair is a row.
 - Cleaning column names and extracting relevant date components (e.g., month, year).
 
Building the Shiny UI
The ui object defines the layout and appearance of your app. Start with a basic structure:
Title Panel: Displays the title of your app at the top.Sidebar Layout: Contains two main parts:Sidebar Panel: Includes interactive controls like sliders, radio buttons, and dropdown menus to filter the data.Main Panel: Displays the outputs (graphs and tables) based on user inputs.
ui <- fluidPage(
  titlePanel(" a title to my app "), # separated by comma
  sidebarLayout(
    sidebarPanel(" this is where user interacts "),
    mainPanel(" this is the results section")
  )
)
server <- function(input, output) {}
shinyApp(ui = ui, server = server)Adding Interactive Inputs
Populate the sidebar with input controls: - Sliderinput: Allows selection of the range of months. - RadioButtons: Enables choosing the year. - SelectInput: Dropdown to select the county from available data.
ui <- fluidPage(
  titlePanel("Tracking Covid in Minnesota"),
  sidebarLayout(
    sidebarPanel(
      sliderInput(inputId = "month", label = "Month?", min = 1, max = 12, value = 6),
      radioButtons(inputId = "year", label = "Year?", choices = 2020:2023),
      selectInput(inputId = "county", label = "County?", choices = county_names, selected = "Rice")
    ),
    mainPanel(" the results go here")
  )
)
server <- function(input, output) {}
shinyApp(ui = ui, server = server, options = list(height = 800))Configuring Outputs in UI
Define placeholders in the main panel where outputs will be rendered:
plotOutput: To display trend plots.tableOutput: To show data tables.
ui <- fluidPage(
  titlePanel("Tracking Covid in Minnesota"),
  sidebarLayout(
    sidebarPanel(
      sliderInput(inputId = "month", label = "Month?", min = 1, max = 12, value = 6),
      radioButtons(inputId = "year", label = "Year?", choices = 2020:2023),
      selectInput(inputId = "county", label = "County?", choices = county_names, selected = "Rice")
    ),
    mainPanel(
      plotOutput("myplot"),
      DT::dataTableOutput("mydata")
    )
  )
)
server <- function(input, output) {}
shinyApp(ui = ui, server = server, options = list(height = 800))Writing the Server Function
The server part of your Shiny app listens for changes in the inputs and dynamically updates the outputs. Here’s how you can set it up:
Reactive Expression: Creates a subset ofcovid_databased on user inputs. This reactive expression ensures that any change in inputs automatically triggers data filtering.- Render Functions:
renderPlot: Generates and renders a plot based on the filtered data.renderDataTable: Displays the filtered data as a table.
 
Running the App
ui <- fluidPage(
  titlePanel("Tracking Covid in Minnesota"),
  sidebarLayout(
    sidebarPanel(
      sliderInput(inputId = "months", label = "Month?", min = 1, max = 12, value = c(3,6)),
      radioButtons(inputId = "years", label = "Year?", choices = 2020:2023, selected = 2023),
      selectInput(inputId = "county", label = "County?", choices = county_names, selected = "Rice")
    ),
    mainPanel(
      plotOutput(outputId = "plot"), br(),
      DT::dataTableOutput(outputId = "table")
    )
  )
)server <- function(input, output) {
    filtered_data <- reactive({
        subset(covid_data,
               counties %in% input$county &
               month >= input$months[1] & month <= input$months[2] & 
          year == input$years) })
    output$plot <- renderPlot({
        ggplot(filtered_data(), aes(x=dates, y=cases, color=counties)) + theme_economist_white()+
                geom_point(alpha=0.5, color = "blue") + theme(legend.position = "none") +
                    ylab("Number of Cases") + xlab("Date")})
    output$table <- DT::renderDataTable({
        filtered_data()})
        
}app <- shinyApp(ui = ui, server = server, options = list(height = 1200))
app(Time permitting) Additional Layout
To enhance your Shiny app, first install and load the shinythemes package to access additional aesthetic themes. Update your UI to utilize a navbarPage structure, incorporating tabPanel elements to separate the plot and data table into distinct tabs. Apply one of the themes, such as “cerulean”, to improve the visual appeal and user experience of your app. Replace the month and year selection inputs in your Shiny app with a dateRangeInput to allow users to select a specific date range for viewing COVID-19 trends.
library(shinythemes)
ui1 <- navbarPage(theme = shinytheme("cerulean"), title = "Tracking Covid in Minnesota",
  tabPanel("Plot",
    fluidPage(
      titlePanel("Covid Trends by County"),
      sidebarLayout(
        sidebarPanel(
          dateRangeInput("dateRange", 
                         "Select Date Range", 
                         start = min(covid_data$dates), 
                         end = max(covid_data$dates),
                         min = min(covid_data$dates), 
                         max = max(covid_data$dates)
                         ),
          selectInput(inputId = "dv", label = "County", choices = levels(covid_data$counties), selected = "Aitkin")
        ),
        mainPanel(
          plotOutput(outputId = "plot")
        )
      )
    )
  ),
  tabPanel("Data",
    fluidPage(
      titlePanel("Covid Data Table"),
      sidebarLayout(
        sidebarPanel(),  
        mainPanel(
          DT::dataTableOutput(outputId = "table")
        )
      )
    )
  )
)
server1 <- function(input, output) {
  filtered_data <- reactive({
    filter(covid_data, 
           counties %in% input$dv &
           dates >= input$dateRange[1] & dates <= input$dateRange[2])
  })
  output$plot <- renderPlot({
    data <- filtered_data()  
    ggplot(data, aes(x = dates, y = cases, color = counties)) +
      geom_point(alpha = 0.5, color = "blue") +
      labs(y = "Number of Cases", x = "Date") +
      theme_minimal()
  })
  output$table <- DT::renderDataTable({
    filtered_data()  
  })
}
app1 <- shinyApp(ui = ui1, server = server1, options = list(height = 1200))
app1