library(shiny)
library(bslib)
Attaching package: 'bslib'
The following object is masked from 'package:utils':
page
library(tidyverse)── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
✔ dplyr 1.2.1 ✔ readr 2.2.0
✔ forcats 1.0.1 ✔ stringr 1.6.0
✔ ggplot2 4.0.3 ✔ tibble 3.3.1
✔ lubridate 1.9.5 ✔ tidyr 1.3.2
✔ purrr 1.2.2
── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag() masks stats::lag()
ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(plotly)
Attaching package: 'plotly'
The following object is masked from 'package:ggplot2':
last_plot
The following object is masked from 'package:stats':
filter
The following object is masked from 'package:graphics':
layout
library(DT)
Attaching package: 'DT'
The following objects are masked from 'package:shiny':
dataTableOutput, renderDataTable
library(scales)
Attaching package: 'scales'
The following object is masked from 'package:purrr':
discard
The following object is masked from 'package:readr':
col_factor
# Paste the outbreak_data creation code here.
outbreak_data <- tidyr::expand_grid(
week = 1:12,
district = c("North", "Central", "South", "East", "West"),
sex = c("Female", "Male"),
age_group = c("<5", "5–14", "15–29", "30–49", "50+"),
disease = c("Cholera", "Measles")
) |>
mutate(
cases = rpois(
n(),
lambda = case_when(
district == "North" & disease == "Cholera" ~ week * 2.6,
district == "Central" ~ 12,
district == "East" ~ 9,
TRUE ~ 6
)
),
deaths = rbinom(n(), size = cases, prob = 0.025),
facility = sample(
paste("Facility", LETTERS[1:8]),
size = n(),
replace = TRUE
)
)
outbreak_data# A tibble: 1,200 × 8
week district sex age_group disease cases deaths facility
<int> <chr> <chr> <chr> <chr> <int> <int> <chr>
1 1 North Female <5 Cholera 1 0 Facility F
2 1 North Female <5 Measles 3 0 Facility C
3 1 North Female 5–14 Cholera 9 0 Facility E
4 1 North Female 5–14 Measles 6 0 Facility D
5 1 North Female 15–29 Cholera 0 0 Facility A
6 1 North Female 15–29 Measles 5 0 Facility B
7 1 North Female 30–49 Cholera 2 0 Facility G
8 1 North Female 30–49 Measles 8 0 Facility B
9 1 North Female 50+ Cholera 2 0 Facility C
10 1 North Female 50+ Measles 6 1 Facility A
# ℹ 1,190 more rows
ui <- page_sidebar(
title = "Weekly Disease Surveillance Dashboard",
sidebar = sidebar(
selectInput(
"district",
"District",
choices = c("All", sort(unique(outbreak_data$district)))
),
selectInput(
"disease",
"Disease",
choices = c("All", sort(unique(outbreak_data$disease)))
)
),
layout_columns(
value_box("Total cases", textOutput("total_cases")),
value_box("Total deaths", textOutput("total_deaths")),
value_box("CFR", textOutput("cfr")),
value_box("New cases", textOutput("new_cases"))
),
layout_columns(
card(card_header("Weekly trend"), plotlyOutput("trend_plot")),
card(card_header("Cases by district"), plotlyOutput("district_plot"))
),
layout_columns(
card(card_header("Cases by age group"), plotlyOutput("age_plot")),
card(card_header("Data table"), DTOutput("data_table"))
)
)
server <- function(input, output, session) {
filtered_data <- reactive({
data <- outbreak_data
if (input$district != "All") {
data <- data |> filter(district == input$district)
}
if (input$disease != "All") {
data <- data |> filter(disease == input$disease)
}
data
})
output$total_cases <- renderText(comma(sum(filtered_data()$cases)))
output$total_deaths <- renderText(comma(sum(filtered_data()$deaths)))
output$cfr <- renderText({
percent(sum(filtered_data()$deaths) / sum(filtered_data()$cases), accuracy = 0.1)
})
output$new_cases <- renderText({
latest_week <- max(filtered_data()$week)
comma(sum(filtered_data()$cases[filtered_data()$week == latest_week]))
})
output$trend_plot <- renderPlotly({
p <- filtered_data() |>
summarise(cases = sum(cases), .by = week) |>
ggplot(aes(x = week, y = cases)) +
geom_line(color = "#00507F", linewidth = 1.2) +
geom_point(color = "#3F9C35", size = 2) +
labs(x = "Week", y = "Cases") +
theme_minimal(base_size = 14)
ggplotly(p)
})
output$district_plot <- renderPlotly({
p <- filtered_data() |>
summarise(cases = sum(cases), .by = district) |>
mutate(district = fct_reorder(district, cases)) |>
ggplot(aes(x = district, y = cases)) +
geom_col(fill = "#00507F") +
coord_flip() +
labs(x = NULL, y = "Cases") +
theme_minimal(base_size = 14)
ggplotly(p)
})
output$age_plot <- renderPlotly({
p <- filtered_data() |>
summarise(cases = sum(cases), .by = age_group) |>
ggplot(aes(x = age_group, y = cases)) +
geom_col(fill = "#3F9C35") +
labs(x = "Age group", y = "Cases") +
theme_minimal(base_size = 14)
ggplotly(p)
})
output$data_table <- renderDT({
filtered_data() |>
arrange(desc(week), district, disease) |>
datatable(options = list(pageLength = 10))
})
}
shinyApp(ui, server)Shiny applications not supported in static R Markdown documents