Commit ·
5beae85
1
Parent(s): 472b641
cleaning up app structure
Browse files- .gitignore +1 -0
- BICS_polarization_shiny.Rproj +13 -0
- app.Rmd +67 -34
- test.csv +0 -0
.gitignore
CHANGED
|
@@ -1 +1,2 @@
|
|
| 1 |
.env
|
|
|
|
|
|
| 1 |
.env
|
| 2 |
+
.Rproj.user
|
BICS_polarization_shiny.Rproj
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Version: 1.0
|
| 2 |
+
|
| 3 |
+
RestoreWorkspace: Default
|
| 4 |
+
SaveWorkspace: Default
|
| 5 |
+
AlwaysSaveHistory: Default
|
| 6 |
+
|
| 7 |
+
EnableCodeIndexing: Yes
|
| 8 |
+
UseSpacesForTab: Yes
|
| 9 |
+
NumSpacesForTab: 2
|
| 10 |
+
Encoding: UTF-8
|
| 11 |
+
|
| 12 |
+
RnwWeave: Sweave
|
| 13 |
+
LaTeX: pdfLaTeX
|
app.Rmd
CHANGED
|
@@ -96,13 +96,20 @@ ui <- fluidPage(
|
|
| 96 |
sidebarLayout(
|
| 97 |
sidebarPanel(
|
| 98 |
width = 3,
|
| 99 |
-
selectInput("model", "
|
| 100 |
-
choices = c(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 101 |
),
|
| 102 |
selectInput("plots_to_display", "Plot to Show:",
|
| 103 |
choices = c("Prevalence", "Incidence", "Infection Sources", "Proportion Dead", "Contacts", "Population Size", "Proportion of Contacts with a Mask", "Contact Homophily", "Multi-Panel Epidemic Outcomes", "Homophily Sensitivity", "Multi-Panel Homophily Sensitivity", "Population Composition Sensitivity", "Multi-Panel Population Composition Sensitivity")
|
| 104 |
),
|
| 105 |
-
sliderInput("time", "Simulation Time (days):", value = 365, min = 365, max = 1000, step = 365, ticks = FALSE),
|
| 106 |
conditionalPanel(
|
| 107 |
condition = "input.model != 'Homogenous Behavior' && input.plot_to_display != 'Homophily Sensitivity' && input.plot_to_display != 'Multi-Panel Homophily Sensitivity'",
|
| 108 |
uiOutput("beta_a_slider")
|
|
@@ -160,6 +167,7 @@ ui <- fluidPage(
|
|
| 160 |
shinyjs::hidden(
|
| 161 |
div(
|
| 162 |
id = "advanced_options",
|
|
|
|
| 163 |
numericInput("frac_a", "Proportion of Population Republican:", value = 0.33333333, min = 0, max = 1, step = 0.1),
|
| 164 |
numericInput("frac_b", "Proportion of Population Democrat:", value = 0.33333333, min = 0, max = 1, step = 0.1),
|
| 165 |
numericInput("cmax_a", "Upper Bound for Contacts (Republicans):", value = no_zeta_contacts_r, min = 0, max = 100, step = .1),
|
|
@@ -192,28 +200,28 @@ ui <- fluidPage(
|
|
| 192 |
numericInput("gamma", "Waning Immunity Rate:", value = 1 / 182.5, min = 0, max = 1, step = 0.01),
|
| 193 |
numericInput("trans_p", "Transmission Probability", value = 0.05, min = 0, max = 1, step = 0.01),
|
| 194 |
numericInput("rho", "recovery rate", value = 0.1, min = 0, max = 1, step = .01),
|
| 195 |
-
numericInput("kappa", "Probability of Transmission for Protected", value = 0.7, min = 0, max = 1, step = .1)
|
| 196 |
-
|
| 197 |
-
|
| 198 |
-
selectInput("show_scenario_customization", "Scenario Customization",
|
| 199 |
-
choices = c("Hide", "Show")
|
| 200 |
-
),
|
| 201 |
-
shinyjs::hidden(
|
| 202 |
-
div(
|
| 203 |
-
id = "scenario_options",
|
| 204 |
checkboxInput("republican_zeta", "Republicans Respond to Death", value = FALSE),
|
| 205 |
checkboxInput("null_combines_mortality", "The Null Averages Partisan-Specific Death Rates", value = FALSE),
|
| 206 |
-
checkboxInput("partisan_mortality", "Incorporate Age-Specific Mortality Rates For Partisans", value =
|
| 207 |
conditionalPanel(
|
| 208 |
condition = "input.model != 'Manual'",
|
| 209 |
selectInput("locale", "Choose a Population:",
|
| 210 |
-
choices =
|
|
|
|
|
|
|
|
|
|
|
|
|
| 211 |
)
|
| 212 |
)
|
| 213 |
)
|
| 214 |
),
|
| 215 |
actionButton("information", "The Purpose of this App"),
|
| 216 |
-
actionButton("vaccine_information", "How We Incorporate Vaccination")
|
|
|
|
|
|
|
| 217 |
),
|
| 218 |
mainPanel(
|
| 219 |
plotOutput("sirPlot", width = "110%", height = "800px"), # make plot bigger
|
|
@@ -239,15 +247,47 @@ server <- function(input, output, session) {
|
|
| 239 |
shinyalert(title = "Implementing Vaccination", text = "In order to see the effects of vaccination, ensure that the vaccination start day occures within your simulation time window.", type = "info")
|
| 240 |
})
|
| 241 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 242 |
# opening pop up screen
|
| 243 |
observeEvent(input$information, {
|
| 244 |
shinyalert(
|
| 245 |
title = "The purpose of this app",
|
| 246 |
text = HTML("This app demonstrates how political differences in behavior can affect the spread of a COVID-19-like disease. Key features:<br><br>
|
| 247 |
-
1. Compare
|
| 248 |
-
-
|
| 249 |
-
-
|
| 250 |
-
-
|
|
|
|
| 251 |
2. Explore various metrics:<br>
|
| 252 |
- Infection rates<br>
|
| 253 |
- Death rates<br>
|
|
@@ -255,7 +295,7 @@ server <- function(input, output, session) {
|
|
| 255 |
- Social mixing patterns (homophily)<br><br>
|
| 256 |
3. Customize your view:<br>
|
| 257 |
- Toggle between party lines<br>
|
| 258 |
-
- Compare against the
|
| 259 |
Use these tools to understand how partisan behaviors can shape both group-specific and overall pandemic outcomes.<br><br>
|
| 260 |
Click 'Next' to begin exploring."),
|
| 261 |
closeOnEsc = FALSE,
|
|
@@ -335,13 +375,6 @@ server <- function(input, output, session) {
|
|
| 335 |
}
|
| 336 |
})
|
| 337 |
|
| 338 |
-
observeEvent(input$show_scenario_customization, {
|
| 339 |
-
if (input$show_scenario_customization == "Show") {
|
| 340 |
-
shinyjs::show("scenario_options")
|
| 341 |
-
} else {
|
| 342 |
-
shinyjs::hide("scenario_options")
|
| 343 |
-
}
|
| 344 |
-
})
|
| 345 |
|
| 346 |
output$beta_a_slider <- renderUI({
|
| 347 |
sliderInput("beta_a", "Republican Homophily:",
|
|
@@ -922,7 +955,7 @@ server <- function(input, output, session) {
|
|
| 922 |
|
| 923 |
plots_to_display <- input$plots_to_display
|
| 924 |
plot_title_size <- input$title_size
|
| 925 |
-
# defining the
|
| 926 |
includes_null_lines <- c("Total" = "solid", "Null" = "dashed")
|
| 927 |
no_null_lines <- c("Total" = "solid")
|
| 928 |
|
|
@@ -935,7 +968,7 @@ server <- function(input, output, session) {
|
|
| 935 |
current_params$cmax_b * (current_params$N0 * current_params$frac_b) +
|
| 936 |
current_params$cmax_c * (current_params$N0 * (1 - (current_params$frac_a + current_params$frac_b)))) / current_params$N0
|
| 937 |
|
| 938 |
-
print(paste("the
|
| 939 |
|
| 940 |
null_model_three_party <- sir_three_group_pu(
|
| 941 |
frac_a = current_params$frac_a,
|
|
@@ -1494,7 +1527,7 @@ server <- function(input, output, session) {
|
|
| 1494 |
} +
|
| 1495 |
labs(
|
| 1496 |
title = if (input$show_title) "Prevalence" else element_blank(),
|
| 1497 |
-
subtitle = if (input$show_subtitle) paste0("Compared to the
|
| 1498 |
x = "Time (days)",
|
| 1499 |
y = element_blank(),
|
| 1500 |
color = "Partisan Prevalence",
|
|
@@ -1532,7 +1565,7 @@ server <- function(input, output, session) {
|
|
| 1532 |
coord_cartesian(xlim = if (input$zoom_plot) c(75, max(sim_three$time)) else c(0, max(sim_three$time)))
|
| 1533 |
|
| 1534 |
table_data_three <- data.frame(
|
| 1535 |
-
Model = c("
|
| 1536 |
Outbreak_Size = c(null_outbreak_size_three, current_outbreak_size_three),
|
| 1537 |
Peak = c(round(peak_null_three_proportion, digits = 3), round(peak_three_proportion, digits = 3)),
|
| 1538 |
Days_Until_Peak = c(crossing_time_null_three_party, crossing_time_three)
|
|
@@ -1772,7 +1805,7 @@ server <- function(input, output, session) {
|
|
| 1772 |
} +
|
| 1773 |
labs(
|
| 1774 |
title = if (input$show_title) "Cumulative Proportion Deceased" else element_blank(),
|
| 1775 |
-
subtitle = if (input$show_subtitle) paste0("In this simulation that starts with ", format(current_params$N0, big.mark = ","), " people:
|
| 1776 |
x = "Time (days)",
|
| 1777 |
y = element_blank(),
|
| 1778 |
color = "Partisan Deaths",
|
|
@@ -2157,12 +2190,12 @@ server <- function(input, output, session) {
|
|
| 2157 |
coord_cartesian(xlim = c(0, max(sim_three$time))) +
|
| 2158 |
geom_text(
|
| 2159 |
data = sim_three %>% filter(time == max(time)),
|
| 2160 |
-
aes(x = time, y = null_total_prop_dead, label = "
|
| 2161 |
nudge_y = -0.002, hjust = 0.5, color = "gray", size = 4
|
| 2162 |
) +
|
| 2163 |
geom_text(
|
| 2164 |
data = sim_three %>% filter(time == median(time)),
|
| 2165 |
-
aes(x = time, y = total_prop_dead, label = "
|
| 2166 |
nudge_y = 0.002, hjust = 0.4, color = "black", size = 4
|
| 2167 |
) +
|
| 2168 |
{
|
|
|
|
| 96 |
sidebarLayout(
|
| 97 |
sidebarPanel(
|
| 98 |
width = 3,
|
| 99 |
+
selectInput("model", "Model Scenario:",
|
| 100 |
+
choices = c(
|
| 101 |
+
"No Partisan Heterogeneity (Baseline)" = "Homogenous Behavior",
|
| 102 |
+
"All Partisans Adopt Best Behavior (Hypothetical)" = "Ideal Homogenous Behavior",
|
| 103 |
+
"Partisans Differ in Contact Rates" = "Contacts",
|
| 104 |
+
"Partisans Differ in Mask Usage" = "Mask Usage",
|
| 105 |
+
"Partisans Differ in Vaccination" = "Vaccination",
|
| 106 |
+
"All Partisan Differences Combined" = "All Partisan Differences",
|
| 107 |
+
"Manual Parameter Entry" = "Manual"
|
| 108 |
+
)
|
| 109 |
),
|
| 110 |
selectInput("plots_to_display", "Plot to Show:",
|
| 111 |
choices = c("Prevalence", "Incidence", "Infection Sources", "Proportion Dead", "Contacts", "Population Size", "Proportion of Contacts with a Mask", "Contact Homophily", "Multi-Panel Epidemic Outcomes", "Homophily Sensitivity", "Multi-Panel Homophily Sensitivity", "Population Composition Sensitivity", "Multi-Panel Population Composition Sensitivity")
|
| 112 |
),
|
|
|
|
| 113 |
conditionalPanel(
|
| 114 |
condition = "input.model != 'Homogenous Behavior' && input.plot_to_display != 'Homophily Sensitivity' && input.plot_to_display != 'Multi-Panel Homophily Sensitivity'",
|
| 115 |
uiOutput("beta_a_slider")
|
|
|
|
| 167 |
shinyjs::hidden(
|
| 168 |
div(
|
| 169 |
id = "advanced_options",
|
| 170 |
+
sliderInput("time", "Simulation Time (days):", value = 365, min = 365, max = 1000, step = 365, ticks = FALSE),
|
| 171 |
numericInput("frac_a", "Proportion of Population Republican:", value = 0.33333333, min = 0, max = 1, step = 0.1),
|
| 172 |
numericInput("frac_b", "Proportion of Population Democrat:", value = 0.33333333, min = 0, max = 1, step = 0.1),
|
| 173 |
numericInput("cmax_a", "Upper Bound for Contacts (Republicans):", value = no_zeta_contacts_r, min = 0, max = 100, step = .1),
|
|
|
|
| 200 |
numericInput("gamma", "Waning Immunity Rate:", value = 1 / 182.5, min = 0, max = 1, step = 0.01),
|
| 201 |
numericInput("trans_p", "Transmission Probability", value = 0.05, min = 0, max = 1, step = 0.01),
|
| 202 |
numericInput("rho", "recovery rate", value = 0.1, min = 0, max = 1, step = .01),
|
| 203 |
+
numericInput("kappa", "Probability of Transmission for Protected", value = 0.7, min = 0, max = 1, step = .1),
|
| 204 |
+
hr(),
|
| 205 |
+
h5("Scenario Customization"),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 206 |
checkboxInput("republican_zeta", "Republicans Respond to Death", value = FALSE),
|
| 207 |
checkboxInput("null_combines_mortality", "The Null Averages Partisan-Specific Death Rates", value = FALSE),
|
| 208 |
+
checkboxInput("partisan_mortality", "Incorporate Age-Specific Mortality Rates For Partisans", value = FALSE),
|
| 209 |
conditionalPanel(
|
| 210 |
condition = "input.model != 'Manual'",
|
| 211 |
selectInput("locale", "Choose a Population:",
|
| 212 |
+
choices = list(
|
| 213 |
+
"Default" = "Default",
|
| 214 |
+
"Cities (2025)" = c("Berkeley", "Seattle", "Philadelphia"),
|
| 215 |
+
"States (2025)" = c("Wyoming")
|
| 216 |
+
)
|
| 217 |
)
|
| 218 |
)
|
| 219 |
)
|
| 220 |
),
|
| 221 |
actionButton("information", "The Purpose of this App"),
|
| 222 |
+
actionButton("vaccine_information", "How We Incorporate Vaccination"),
|
| 223 |
+
actionButton("data_source", "Where Does the Data Come From?"),
|
| 224 |
+
actionButton("population_source", "Where Does Population Data Come From?")
|
| 225 |
),
|
| 226 |
mainPanel(
|
| 227 |
plotOutput("sirPlot", width = "110%", height = "800px"), # make plot bigger
|
|
|
|
| 247 |
shinyalert(title = "Implementing Vaccination", text = "In order to see the effects of vaccination, ensure that the vaccination start day occures within your simulation time window.", type = "info")
|
| 248 |
})
|
| 249 |
|
| 250 |
+
# data source popup
|
| 251 |
+
observeEvent(input$data_source, {
|
| 252 |
+
shinyalert(
|
| 253 |
+
title = "Data Source: Berkeley Interpersonal Contact Study",
|
| 254 |
+
text = HTML("The Berkeley Interpersonal Contact Study (BICS) collected data on contact rates and health behaviors during the COVID-19 pandemic (April 2020 - May 2021) through nationally representative surveys.<br><br>
|
| 255 |
+
<b>What was measured:</b><br>
|
| 256 |
+
• <b>Daily contacts:</b> Number of in-person contacts the day before the survey<br>
|
| 257 |
+
• <b>Mask usage:</b> Whether respondents wore masks during contacts<br>
|
| 258 |
+
• <b>Vaccination:</b> Self-reported COVID-19 vaccination status (Wave 6, May 2021)<br><br>
|
| 259 |
+
<b>Political affiliation:</b> Respondents self-identified as Democrat, Republican, or Independent upon enrollment in the survey panel.<br><br>
|
| 260 |
+
<b>Reference:</b> Feehan & Mahmud (2021), <i>Quantifying interpersonal contact in the United States during the spread of COVID-19</i>"),
|
| 261 |
+
type = "info",
|
| 262 |
+
html = TRUE,
|
| 263 |
+
size = "m"
|
| 264 |
+
)
|
| 265 |
+
})
|
| 266 |
+
|
| 267 |
+
# population data source popup
|
| 268 |
+
observeEvent(input$population_source, {
|
| 269 |
+
shinyalert(
|
| 270 |
+
title = "Population Data Source",
|
| 271 |
+
text = HTML("Population sizes are from the U.S. Census Bureau. Partisan composition for cities and states is derived from voter registration data.<br><br>
|
| 272 |
+
<b>References:</b><br>
|
| 273 |
+
U.S. Census Bureau. (2024). <i>American Community Survey 1-year estimates</i>. https://data.census.gov/<br><br>
|
| 274 |
+
USAFacts. (2025, August 29). <i>How many voters have a party affiliation?</i> https://usafacts.org/articles/how-many-voters-have-a-party-affiliation/"),
|
| 275 |
+
type = "info",
|
| 276 |
+
html = TRUE,
|
| 277 |
+
size = "m"
|
| 278 |
+
)
|
| 279 |
+
})
|
| 280 |
+
|
| 281 |
# opening pop up screen
|
| 282 |
observeEvent(input$information, {
|
| 283 |
shinyalert(
|
| 284 |
title = "The purpose of this app",
|
| 285 |
text = HTML("This app demonstrates how political differences in behavior can affect the spread of a COVID-19-like disease. Key features:<br><br>
|
| 286 |
+
1. Compare model scenarios:<br>
|
| 287 |
+
- No Partisan Heterogeneity: Baseline with uniform behavior<br>
|
| 288 |
+
- All Partisans Adopt Best Behavior: Hypothetical best-case scenario<br>
|
| 289 |
+
- Partisan difference models: Vary contacts, mask usage, or vaccination<br>
|
| 290 |
+
- All Partisan Differences Combined: Incorporates all observed differences<br><br>
|
| 291 |
2. Explore various metrics:<br>
|
| 292 |
- Infection rates<br>
|
| 293 |
- Death rates<br>
|
|
|
|
| 295 |
- Social mixing patterns (homophily)<br><br>
|
| 296 |
3. Customize your view:<br>
|
| 297 |
- Toggle between party lines<br>
|
| 298 |
+
- Compare against the baseline (no heterogeneity)<br><br>
|
| 299 |
Use these tools to understand how partisan behaviors can shape both group-specific and overall pandemic outcomes.<br><br>
|
| 300 |
Click 'Next' to begin exploring."),
|
| 301 |
closeOnEsc = FALSE,
|
|
|
|
| 375 |
}
|
| 376 |
})
|
| 377 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 378 |
|
| 379 |
output$beta_a_slider <- renderUI({
|
| 380 |
sliderInput("beta_a", "Republican Homophily:",
|
|
|
|
| 955 |
|
| 956 |
plots_to_display <- input$plots_to_display
|
| 957 |
plot_title_size <- input$title_size
|
| 958 |
+
# defining the baseline line types
|
| 959 |
includes_null_lines <- c("Total" = "solid", "Null" = "dashed")
|
| 960 |
no_null_lines <- c("Total" = "solid")
|
| 961 |
|
|
|
|
| 968 |
current_params$cmax_b * (current_params$N0 * current_params$frac_b) +
|
| 969 |
current_params$cmax_c * (current_params$N0 * (1 - (current_params$frac_a + current_params$frac_b)))) / current_params$N0
|
| 970 |
|
| 971 |
+
print(paste("the baseline contacts are", null_three_party_contacts))
|
| 972 |
|
| 973 |
null_model_three_party <- sir_three_group_pu(
|
| 974 |
frac_a = current_params$frac_a,
|
|
|
|
| 1527 |
} +
|
| 1528 |
labs(
|
| 1529 |
title = if (input$show_title) "Prevalence" else element_blank(),
|
| 1530 |
+
subtitle = if (input$show_subtitle) paste0("Compared to the baseline (no heterogeneity), the peak comes ", crossing_time_diff, " days sooner and is ", peak_three_increase, "% taller. Total cases increase by ", outbreak_size_percentage_increase, "%.\nThe proportion of Republican population infected is ", rep_versus_dem_prop_infected_three, "% larger than the proportion Democrat population infected.") else element_blank(),
|
| 1531 |
x = "Time (days)",
|
| 1532 |
y = element_blank(),
|
| 1533 |
color = "Partisan Prevalence",
|
|
|
|
| 1565 |
coord_cartesian(xlim = if (input$zoom_plot) c(75, max(sim_three$time)) else c(0, max(sim_three$time)))
|
| 1566 |
|
| 1567 |
table_data_three <- data.frame(
|
| 1568 |
+
Model = c("Baseline (No Heterogeneity)", "Current Model"),
|
| 1569 |
Outbreak_Size = c(null_outbreak_size_three, current_outbreak_size_three),
|
| 1570 |
Peak = c(round(peak_null_three_proportion, digits = 3), round(peak_three_proportion, digits = 3)),
|
| 1571 |
Days_Until_Peak = c(crossing_time_null_three_party, crossing_time_three)
|
|
|
|
| 1805 |
} +
|
| 1806 |
labs(
|
| 1807 |
title = if (input$show_title) "Cumulative Proportion Deceased" else element_blank(),
|
| 1808 |
+
subtitle = if (input$show_subtitle) paste0("In this simulation that starts with ", format(current_params$N0, big.mark = ","), " people: Republican deaths exceed Democrat deaths by ", diff_deaths_three, "%.\nThe inflection point comes at day ", inflection_point_three, " in the current model compared to ", inflection_point_null_three, " in the baseline.") else element_blank(),
|
| 1809 |
x = "Time (days)",
|
| 1810 |
y = element_blank(),
|
| 1811 |
color = "Partisan Deaths",
|
|
|
|
| 2190 |
coord_cartesian(xlim = c(0, max(sim_three$time))) +
|
| 2191 |
geom_text(
|
| 2192 |
data = sim_three %>% filter(time == max(time)),
|
| 2193 |
+
aes(x = time, y = null_total_prop_dead, label = "Baseline"),
|
| 2194 |
nudge_y = -0.002, hjust = 0.5, color = "gray", size = 4
|
| 2195 |
) +
|
| 2196 |
geom_text(
|
| 2197 |
data = sim_three %>% filter(time == median(time)),
|
| 2198 |
+
aes(x = time, y = total_prop_dead, label = "Heterogeneous"),
|
| 2199 |
nudge_y = 0.002, hjust = 0.4, color = "black", size = 4
|
| 2200 |
) +
|
| 2201 |
{
|
test.csv
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|