robertvidigal commited on
Commit
46299d2
Β·
verified Β·
1 Parent(s): 22647bd

Update app.R

Browse files
Files changed (1) hide show
  1. app.R +630 -46
app.R CHANGED
@@ -1,58 +1,642 @@
1
- library(shiny)
2
- library(bslib)
3
  library(dplyr)
4
- library(ggplot2)
5
-
6
- df <- readr::read_csv("penguins.csv")
7
- # Find subset of columns that are suitable for scatter plot
8
- df_num <- df |> select(where(is.numeric), -Year)
9
-
10
- ui <- page_sidebar(
11
- theme = bs_theme(bootswatch = "minty"),
12
- title = "Penguins explorer",
13
- sidebar = sidebar(
14
- varSelectInput("xvar", "X variable", df_num, selected = "Bill Length (mm)"),
15
- varSelectInput("yvar", "Y variable", df_num, selected = "Bill Depth (mm)"),
16
- checkboxGroupInput("species", "Filter by species",
17
- choices = unique(df$Species), selected = unique(df$Species)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18
  ),
19
- hr(), # Add a horizontal rule
20
- checkboxInput("by_species", "Show species", TRUE),
21
- checkboxInput("show_margins", "Show marginal plots", TRUE),
22
- checkboxInput("smooth", "Add smoother"),
23
- ),
24
- plotOutput("scatter")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
  )
26
 
 
27
  server <- function(input, output, session) {
28
- subsetted <- reactive({
29
- req(input$species)
30
- df |> filter(Species %in% input$species)
31
- })
32
-
33
- output$scatter <- renderPlot(
34
- {
35
- p <- ggplot(subsetted(), aes(!!input$xvar, !!input$yvar)) +
36
- theme_light() +
37
- list(
38
- theme(legend.position = "bottom"),
39
- if (input$by_species) aes(color = Species),
40
- geom_point(),
41
- if (input$smooth) geom_smooth()
42
- )
43
-
44
- if (input$show_margins) {
45
- margin_type <- if (input$by_species) "density" else "histogram"
46
- p <- p |> ggExtra::ggMarginal(
47
- type = margin_type, margins = "both",
48
- size = 8, groupColour = input$by_species, groupFill = input$by_species
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49
  )
 
 
 
 
50
  }
51
-
52
- p
 
 
 
 
 
 
 
53
  },
54
- res = 100
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55
  )
56
  }
57
 
 
58
  shinyApp(ui, server)
 
1
+ library(lapop)
2
+ library(haven)
3
  library(dplyr)
4
+ library(tidyr)
5
+ library(stringr)
6
+ library(shinyWidgets)
7
+ library(Hmisc)
8
+
9
+ lapop_fonts()
10
+
11
+ dstrata <- readRDS("gm_shiny_data_en.rds")
12
+ labs <- readRDS("labs_en.rds")
13
+ vars_labels <- read.csv("variable_labels_shiny.csv", encoding = "latin1")
14
+
15
+ Error<-function(x){
16
+ tryCatch(x,error=function(e) return(FALSE))
17
+ }
18
+
19
+ waves_total = c("2004", "2006", "2008", "2010", "2012", "2014", "2016/17", "2018/19", "2021", "2023")
20
+
21
+
22
+ #helper function for cleaning ts -- handle missing values at end or middle of series
23
+ omit_na_edges <- function(df) {
24
+ # Find which rows have NA values
25
+ na_rows <- apply(df, 1, function(row) any(is.na(row)))
26
+
27
+ # Find the first and last non-NA row
28
+ first_non_na <- which(!na_rows)[1]
29
+ last_non_na <- which(!na_rows)[length(which(!na_rows))]
30
+
31
+ # Subset df to only include rows between the first and last non-NA rows
32
+ df_clean <- df[first_non_na:last_non_na, ]
33
+
34
+ return(df_clean)
35
+ }
36
+
37
+ #custom weighted averages and CIs, to speed up computational speed vs. survey_mean
38
+ weighted.ttest.ci <- function(x, weights) {
39
+ nx <- length(x)
40
+ vx <- Hmisc::wtd.var(x, weights, normwt = TRUE, na.rm = TRUE) ## From Hmisc
41
+ mx <- weighted.mean(x, weights, na.rm = TRUE)
42
+ stderr <- sqrt(vx/nx)
43
+ tstat <- mx/stderr ## not mx - mu
44
+ cint <- qt(1 - 0.05/2, nx - 1)
45
+ cint <- tstat + c(-cint, cint)
46
+ confint = cint * stderr
47
+ result = data.frame(prop = mx, lb = confint[1], ub = confint[2])
48
+ return(result)
49
+ }
50
+
51
+ # helper function for mover
52
+ process_data <- function(data, outcome_var, recode_range, group_var, var_label, weight_var = "weight1500") {
53
+ if (is.null(group_var)) {
54
+ return(NULL)
55
+ }
56
+ processed_data <- data %>%
57
+ drop_na(!!sym(outcome_var)) %>%
58
+ mutate(outcome_rec = case_when(
59
+ is.na(!!sym(outcome_var)) ~ NA_real_,
60
+ !!sym(outcome_var) >= recode_range[1] & !!sym(outcome_var) <= recode_range[2] ~ 100,
61
+ TRUE ~ 0
62
+ )) %>%
63
+ group_by(vallabel = haven::as_factor(zap_missing(!!sym(group_var)))) %>%
64
+ summarise_at(vars("outcome_rec"), list(~weighted.ttest.ci(., !!sym(weight_var)))) %>%
65
+ unnest_wider(col = "outcome_rec") %>%
66
+ mutate(
67
+ varlabel = var_label,
68
+ proplabel = paste0(round(prop), "%")
69
+ ) %>%
70
+ drop_na(.)
71
+
72
+ return(processed_data)
73
+ }
74
+
75
+ ui <- fluidPage(
76
+
77
+ titlePanel(""), # Leave it Empty
78
+
79
+ sidebarLayout(
80
+
81
+ # Sidebar panel for inputs ----
82
+ sidebarPanel(
83
+ width = 3, # Reduce width (default is 4)
84
+
85
+ selectInput("variable", "Variable",
86
+ labs[order(names(labs))],
87
+ selected = "ing4"),
88
+
89
+ pickerInput(inputId = "pais",
90
+ label = "Countries",
91
+ choices = sort(levels(as_factor(dstrata$pais)[!is.na(dstrata$pais)])),
92
+ selected = c("Argentina", "Bolivia", "Brazil", "Chile",
93
+ "Colombia", "Costa Rica", "Dominican Republic",
94
+ "Ecuador", "El Salvador", "Guatemala", "Haiti",
95
+ "Honduras", "Jamaica", "Mexico", "Nicaragua",
96
+ "Panama", "Paraguay", "Peru", "Uruguay"),
97
+ options = list(`actions-box` = TRUE),
98
+ multiple = TRUE),
99
+
100
+
101
+ #this fixes a formatting issue with checkboxGroupInput below
102
+ tags$head(
103
+ tags$style(
104
+ HTML(
105
+ ".checkbox-inline {
106
+ margin-left: 0px;
107
+ margin-right: 10px;
108
+ }
109
+ .checkbox-inline+.checkbox-inline {
110
+ margin-left: 0px;
111
+ margin-right: 10px;
112
+ }
113
+ "
114
+ )
115
+ )
116
+ ),
117
+
118
+ #this makes slider input only integers
119
+ tags$style(type = "text/css", ".irs-grid-pol.small {height: 0px;}"),
120
+
121
+
122
+
123
+ pickerInput(inputId = "wave",
124
+ label = "Survey Rounds",
125
+ choices = c("2004" = "2004",
126
+ "2006" = "2006",
127
+ "2008" = "2008",
128
+ "2010" = "2010",
129
+ "2012" = "2012",
130
+ "2014" = "2014",
131
+ "2016/17" = "2016/17",
132
+ "2018/19" = "2018/19",
133
+ "2021" = "2021",
134
+ "2023" = "2023"),
135
+ selected = c("2006", "2008", "2010", "2012", "2014",
136
+ "2016/17", "2018/19", "2021", "2023"),
137
+ options = list(`actions-box` = TRUE),
138
+ # options = list
139
+ multiple = TRUE),
140
+
141
+ # show recode slider only for time series, cc, and breakdown (not hist)
142
+ conditionalPanel(
143
+ 'input.tabs == "Time Series" | input.tabs == "Cross Country" | input.tabs == "Breakdown"',
144
+ uiOutput("sliderUI"),
145
+ ),
146
+
147
+
148
+ conditionalPanel(
149
+ 'input.tabs == "Breakdown"',
150
+ selectInput("variable_sec", "Secondary Variable",
151
+ c("None" = "None",
152
+ labs[order(names(labs))])),
153
+ checkboxGroupInput("demog", "Demographic Variables",
154
+ c("Gender" = "gendermc",
155
+ "Age" = "edad",
156
+ "Wealth" = "wealth",
157
+ "Education" = "edre",
158
+ "Urban/Rural" = "ur"),
159
+ selected = c("gendermc", "edad", "edre"),
160
+ inline = TRUE)
161
+ ),
162
+
163
+ actionButton("go", "Generate")
164
+
165
  ),
166
+
167
+ # Main panel for displaying outputs ----
168
+ mainPanel(
169
+ #width = 8, # Adjust accordingly (default is 8)
170
+ # Output: Formatted text for caption ----
171
+ h3(textOutput("caption")),
172
+ h5(textOutput("wording")),
173
+ h5(textOutput("response")),
174
+
175
+ tabsetPanel(id = "tabs",
176
+ tabPanel("Histogram", plotOutput("hist")),
177
+
178
+ tabPanel("Time Series", plotOutput("ts")),
179
+
180
+ tabPanel("Cross Country", plotOutput("cc")),
181
+
182
+ tabPanel("Breakdown", plotOutput("mover"))
183
+ ),
184
+ br(),
185
+ fluidRow(column(12, "",
186
+ downloadButton(outputId = "downloadPlot", label = "Download Figure"),
187
+ downloadButton(outputId = "downloadTable", label = "Download Table")))
188
+ )
189
+ )
190
  )
191
 
192
+ # Define server logic to plot various variables ----
193
  server <- function(input, output, session) {
194
+
195
+ formulaText <- reactive({
196
+ paste(input$variable)
197
+ })
198
+
199
+ outcome <- reactive({
200
+ input$variable
201
+ })
202
+
203
+ variable_sec <- reactive({
204
+ input$variable_sec
205
+ })
206
+
207
+ variable_sec_lab <- reactive({
208
+ vars_labels$question_short_en[which(vars_labels$column_name == paste(variable_sec()))]
209
+ })
210
+
211
+ sliderParams <- reactiveValues(valuex = c(1, 1))
212
+
213
+ #set default slider values - 5-7 for 1-7 variable, 2 for 1-2 variable, 3-4 for 1-4 variable, etc.
214
+ observeEvent(input$variable, {
215
+ if (max(as.numeric(dstrata[[formulaText()]]), na.rm=TRUE) == 7) {
216
+ sliderParams$valuex <- c(5, 7)
217
+ } else if (max(as.numeric(dstrata[[formulaText()]]), na.rm=TRUE) == 2) {
218
+ sliderParams$valuex <- c(2, 2)
219
+ } else if (max(as.numeric(dstrata[[formulaText()]]), na.rm=TRUE) == 3) {
220
+ sliderParams$valuex <- c(3, 3)
221
+ } else if (max(as.numeric(dstrata[[formulaText()]]), na.rm=TRUE) == 4) {
222
+ sliderParams$valuex <- c(3, 4)
223
+ } else if (max(as.numeric(dstrata[[formulaText()]]), na.rm=TRUE) == 5) {
224
+ sliderParams$valuex <- c(4, 5)
225
+ } else if (max(as.numeric(dstrata[[formulaText()]]), na.rm=TRUE) == 10) {
226
+ sliderParams$valuex <- c(7, 10)
227
+ }
228
+ })
229
+
230
+ output$sliderUI <- renderUI({
231
+ sliderInput(inputId = "recode",
232
+ label = "Response values included in percentage",
233
+ min = min(as.numeric(dstrata[[formulaText()]]), na.rm=TRUE),
234
+ max = max(as.numeric(dstrata[[formulaText()]]), na.rm=TRUE),
235
+ value = sliderParams$valuex,
236
+ step = 1)
237
+ })
238
+
239
+
240
+
241
+ dff <- eventReactive(input$go, ignoreNULL = FALSE, {
242
+ dstrata %>%
243
+ filter(as_factor(wave) %in% input$wave) %>%
244
+ filter(pais_nam %in% input$pais)
245
+ })
246
+
247
+ cap <- renderText({
248
+ vars_labels$question_short_en[which(vars_labels$column_name == formulaText())]
249
+ })
250
+
251
+ output$caption <- eventReactive(input$go, ignoreNULL = FALSE, {
252
+ cap()
253
+ })
254
+
255
+ word <- renderText({
256
+ vars_labels$question_en[which(vars_labels$column_name == formulaText())]
257
+ })
258
+
259
+ output$wording <- eventReactive(input$go, ignoreNULL = FALSE, {
260
+ word()
261
+ })
262
+
263
+ resp <- renderText({
264
+ vars_labels$responses_en_rec[which(vars_labels$column_name == formulaText())]
265
+ })
266
+
267
+ output$response <- eventReactive(input$go, ignoreNULL = FALSE, {
268
+ resp()
269
+ })
270
+
271
+ slider_values <- renderText({
272
+ if(input$recode[1] == input$recode[2]) {
273
+ paste0("(value: ", unique(input$recode), ")")
274
+ } else {
275
+ paste0("(range: ", paste(input$recode, collapse = " to "), ")")
276
+ }
277
+ })
278
+
279
+ output$selected_values <- eventReactive(input$go, ignoreNULL = FALSE, {
280
+ slider_values()
281
+ })
282
+
283
+ # SOURCE INFO WITH PAIS and WAVE
284
+ source_info_both <- reactive({
285
+ # Get country abbreviations that match selected country names
286
+ pais_abbr <- dstrata %>%
287
+ filter(pais_nam %in% input$pais) %>%
288
+ distinct(pais_nam, pais_lab) %>%
289
+ arrange(match(pais_nam, input$pais)) %>% # preserve input order
290
+ pull(pais_lab)
291
+
292
+ pais_display <- paste(pais_abbr, collapse = ", ")
293
+ wave_display <- paste(input$wave, collapse = ", ")
294
+
295
+ paste0(", AmericasBarometer Data Playground\nCountries included: ", pais_display, "\nSurvey rounds included: ", wave_display)
296
+
297
+ })
298
+
299
+ source_info_pais <- reactive({
300
+ # Get country abbreviations that match selected country names
301
+ pais_abbr <- dstrata %>%
302
+ filter(pais_nam %in% input$pais) %>%
303
+ distinct(pais_nam, pais_lab) %>%
304
+ arrange(match(pais_nam, input$pais)) %>% # preserve input order
305
+ pull(pais_lab)
306
+
307
+ pais_display <- paste(pais_abbr, collapse = ", ")
308
+ wave_display <- paste(input$wave, collapse = ", ")
309
+
310
+ paste0(", AmericasBarometer Data Playground\nCountries included: ", pais_display)
311
+ })
312
+
313
+ source_info_wave <- reactive({
314
+ # Get country abbreviations that match selected country names
315
+ pais_abbr <- dstrata %>%
316
+ filter(pais_nam %in% input$pais) %>%
317
+ distinct(pais_nam, pais_lab) %>%
318
+ arrange(match(pais_nam, input$pais)) %>% # preserve input order
319
+ pull(pais_lab)
320
+
321
+ pais_display <- paste(pais_abbr, collapse = ", ")
322
+ wave_display <- paste(input$wave, collapse = ", ")
323
+
324
+ paste0(", AmericasBarometer Data Playground\nSurvey rounds included: ", wave_display)
325
+ })
326
+
327
+ #hist
328
+ # must break into data event, graph event, and renderPlot to get download buttons to work
329
+ histd <- eventReactive(input$go, ignoreNULL = FALSE, {
330
+ hist_df = Error(
331
+ dff() %>%
332
+ group_by(across(outcome())) %>%
333
+ summarise(n = n()) %>%
334
+ drop_na() %>%
335
+ rename(cat = 1) %>%
336
+ mutate(prop = prop.table(n) * 100,
337
+ proplabel = paste(round(prop), "%", sep = ""),
338
+ cat = str_wrap(as.character(haven::as_factor(cat)), width = 25)))
339
+
340
+ validate(
341
+ need(hist_df, "Error: no data available. Please verify that this question was asked in this country/year combination")
342
+ )
343
+ return(hist_df)
344
+ })
345
+
346
+
347
+ histg <- eventReactive(input$go, ignoreNULL = FALSE, {
348
+ histg <- lapop_hist(histd(),
349
+ ymax = ifelse(any(histd()$prop > 90), 110, 100),
350
+ source_info = source_info_both())
351
+ return(histg)
352
+ })
353
+
354
+ output$hist <- renderPlot({
355
+ return(histg())
356
+ })
357
+
358
+
359
+ #ts
360
+ tsd <- eventReactive(input$go, ignoreNULL = FALSE, {
361
+ dta_ts = Error(
362
+ dff() %>%
363
+ drop_na(outcome()) %>%
364
+ mutate(outcome_rec = case_when(
365
+ is.na(!!sym(outcome())) ~ NA_real_,
366
+ !!sym(outcome()) >= input$recode[1] &
367
+ !!sym(outcome()) <= input$recode[2] ~ 100,
368
+ TRUE ~ 0)) %>%
369
+ group_by(as.character(as_factor(wave))) %>%
370
+ summarise_at(vars("outcome_rec"),
371
+ list(~weighted.ttest.ci(., weight1500))) %>%
372
+ unnest_wider(col = "outcome_rec") %>%
373
+ mutate(proplabel = paste0(round(prop), "%")) %>%
374
+ rename(., wave = 1) %>%
375
+ filter(prop != 0)
376
+ )
377
+ validate(
378
+ need(dta_ts, "Error: no data available. Please verify that this question was asked in this country/year combination")
379
+ )
380
+ dta_ts = merge(dta_ts, data.frame(wave = as.character(waves_total), empty = 1), by = "wave", all.y = TRUE)
381
+ return(omit_na_edges(dta_ts))
382
+ })
383
+
384
+ tsg <- eventReactive(input$go, ignoreNULL = FALSE, {
385
+ tsg = lapop_ts(tsd(),
386
+ ymax = ifelse(any(tsd()$prop > 88, na.rm = TRUE), 110, 100),
387
+ label_vjust = ifelse(any(tsd()$prop > 80, na.rm = TRUE), -1.1, -1.5),
388
+ source_info = source_info_pais(),
389
+ subtitle = "% in selected category")
390
+ return(tsg)
391
+ })
392
+
393
+
394
+ output$ts <- renderPlot({
395
+ return(tsg())
396
+ })
397
+
398
+ #cc
399
+ ccd <- eventReactive(input$go, ignoreNULL = FALSE, {
400
+ dta_cc = Error(
401
+ dff() %>%
402
+ drop_na(outcome()) %>%
403
+ mutate(outcome_rec = case_when(
404
+ is.na(!!sym(outcome())) ~ NA_real_,
405
+ !!sym(outcome()) >= input$recode[1] &
406
+ !!sym(outcome()) <= input$recode[2] ~ 100,
407
+ TRUE ~ 0)) %>%
408
+ group_by(vallabel = pais_lab) %>%
409
+ summarise_at(vars("outcome_rec"),
410
+ list(~weighted.ttest.ci(., weight1500))) %>%
411
+ unnest_wider(col = "outcome_rec") %>%
412
+ filter(prop != 0) %>%
413
+ mutate(proplabel = paste0(round(prop), "%"))
414
+ )
415
+ validate(
416
+ need(dta_cc, "Error: no data available. Please verify that this question was asked in this country/year combination")
417
+ )
418
+ return(dta_cc)
419
+ })
420
+
421
+ ccg <- eventReactive(input$go, ignoreNULL = FALSE, {
422
+ ccg = lapop_cc(ccd(), sort = "hi-lo",
423
+ subtitle = "% in selected category",
424
+ ymax = ifelse(any(ccd()$prop > 90, na.rm = TRUE), 110, 100),
425
+ source_info = source_info_wave())
426
+ return(ccg)
427
+ })
428
+
429
+ output$cc <- renderPlot({
430
+ return(ccg())
431
+ })
432
+
433
+ # Use function for each demographic breakdown variable
434
+ secdf <- eventReactive(input$go, ignoreNULL = FALSE, {
435
+ if (input$variable_sec == "None") {
436
+ NULL
437
+ } else if (variable_sec() == outcome()) {
438
+ showNotification("You cannot break the outcome variable by itself.", type = "error")
439
+ NULL
440
+ } else {
441
+ process_data(
442
+ data = dff(),
443
+ outcome_var = outcome(),
444
+ recode_range = input$recode,
445
+ group_var = input$variable_sec,
446
+ var_label = str_wrap(variable_sec_lab(), width = 25)
447
+ )
448
+ }
449
+ })
450
+
451
+ genderdf <- eventReactive(input$go, ignoreNULL = FALSE, {
452
+ if ("gendermc" %in% input$demog) {
453
+ process_data(
454
+ data = dff(),
455
+ outcome_var = outcome(),
456
+ recode_range = input$recode,
457
+ group_var = "gendermc",
458
+ var_label = "Gender"
459
+ )
460
+ } else {
461
+ NULL
462
+ }
463
+ })
464
+
465
+ wealthdf <- eventReactive(input$go, ignoreNULL = FALSE, {
466
+ if ("wealth" %in% input$demog) {
467
+ process_data(
468
+ data = dff(),
469
+ outcome_var = outcome(),
470
+ recode_range = input$recode,
471
+ group_var = "wealthf",
472
+ var_label = "Wealth"
473
+ )
474
+ } else {
475
+ NULL
476
+ }
477
+ })
478
+
479
+ eddf <- eventReactive(input$go, ignoreNULL = FALSE, {
480
+ if ("edre" %in% input$demog) {
481
+ process_data(
482
+ data = dff(),
483
+ outcome_var = outcome(),
484
+ recode_range = input$recode,
485
+ group_var = "edrerf",
486
+ var_label = "Education"
487
+ )
488
+ } else {
489
+ NULL
490
+ }
491
+ })
492
+
493
+ edaddf <- eventReactive(input$go, ignoreNULL = FALSE, {
494
+ if ("edad" %in% input$demog) {
495
+ process_data(
496
+ data = dff(),
497
+ outcome_var = outcome(),
498
+ recode_range = input$recode,
499
+ group_var = "edad",
500
+ var_label = "Age"
501
+ )
502
+ } else {
503
+ NULL
504
+ }
505
+ })
506
+
507
+ urdf <- eventReactive(input$go, ignoreNULL = FALSE, {
508
+ if ("ur" %in% input$demog) {
509
+ process_data(
510
+ data = dff(),
511
+ outcome_var = outcome(),
512
+ recode_range = input$recode,
513
+ group_var = "ur",
514
+ var_label = "Place of\nResidence"
515
+ )
516
+ } else {
517
+ NULL
518
+ }
519
+ })
520
+
521
+ # Combine =demographic data frames into one df
522
+ moverd <- eventReactive(input$go, ignoreNULL = FALSE, {
523
+ dta_mover <- Error(rbind(secdf(), genderdf(), edaddf(), wealthdf(), eddf(), urdf()))
524
+ validate(
525
+ need(dta_mover, "Error: no data available. Please verify that this question was asked in this country/year combination")
526
+ )
527
+ dta_mover$vallabel <- as.character(dta_mover$vallabel)
528
+ return(dta_mover)
529
+ })
530
+
531
+ moverg <- eventReactive(input$go, ignoreNULL = FALSE, {
532
+ moverg <- lapop_mover(moverd(),
533
+ subtitle = "% in selected category",
534
+ ymax = ifelse(any(moverd()$prop > 90, na.rm = TRUE), 119,
535
+ ifelse(any(moverd()$prop > 80, na.rm = TRUE), 109, 100)),
536
+ source_info = source_info_both())
537
+ return(moverg)
538
+ })
539
+
540
+ output$mover <- renderPlot({
541
+ return(moverg())
542
+ })
543
+
544
+ # DOWNLOAD SECTION
545
+ output$downloadPlot <- downloadHandler(
546
+ filename = function(file) {
547
+ ifelse(input$tabs == "Histogram", paste0("hist_", outcome(),".svg"),
548
+ ifelse(input$tabs == "Time Series", paste0("ts_", outcome(),".svg"),
549
+ ifelse(input$tabs == "Cross Country", paste0("cc_", outcome(),".svg"), paste0("mover_", outcome(),".svg"))))
550
+ },
551
+
552
+ content = function(file) {
553
+ if(input$tabs == "Histogram") {
554
+ title_text <- isolate(cap())
555
+
556
+ hist_to_save <- lapop_hist(histd(),
557
+ main_title = title_text,
558
+ subtitle = "% in selected category ",
559
+ ymax = ifelse(any(histd()$prop > 90), 110, 100),
560
+ source_info = source_info_both())
561
+
562
+ lapop_save(hist_to_save, file)
563
+ showNotification(HTML("Plot download complete βœ“ "), type = "message")
564
+
565
+ } else if (input$tabs == "Time Series") {
566
+ title_text <- isolate(cap())
567
+ subtitle_text <- slider_values()
568
+
569
+ ts_to_save <- lapop_ts(tsd(),
570
+ main_title = title_text,
571
+ subtitle = paste0("% in selected category ", subtitle_text),
572
+ ymax = ifelse(any(tsd()$prop > 88, na.rm = TRUE), 110, 100),
573
+ label_vjust = ifelse(any(tsd()$prop > 80, na.rm = TRUE), -1.1, -1.5),
574
+ source_info = source_info_pais())
575
+
576
+ lapop_save(ts_to_save, file)
577
+ showNotification(HTML("Plot download complete βœ“ "), type = "message")
578
+
579
+ } else if (input$tabs == "Cross Country") {
580
+ title_text <- isolate(cap())
581
+ subtitle_text <- slider_values()
582
+
583
+ cc_to_save <- lapop_cc(ccd(), sort = "hi-lo",
584
+ main_title = title_text,
585
+ subtitle = paste0("% in selected category ", subtitle_text),
586
+ ymax = ifelse(any(ccd()$prop > 90, na.rm = TRUE), 110, 100),
587
+ source_info = source_info_wave())
588
+
589
+ lapop_save(cc_to_save, file)
590
+ showNotification(HTML("Plot download complete βœ“ "), type = "message")
591
+
592
+ } else {
593
+ title_text <- isolate(cap())
594
+ subtitle_text <- slider_values()
595
+
596
+ mover_to_save <- lapop_mover(
597
+ moverd(),
598
+ main_title = title_text,
599
+ subtitle = paste0("% in selected category ", subtitle_text),
600
+ ymax = ifelse(any(moverd()$prop > 90, na.rm = TRUE), 119,
601
+ ifelse(any(moverd()$prop > 80, na.rm = TRUE), 109, 100)),
602
+ source_info = source_info_both()
603
  )
604
+
605
+ lapop_save(mover_to_save, file)
606
+ showNotification(HTML("Plot download complete βœ“ "), type = "message")
607
+
608
  }
609
+ }
610
+ )
611
+
612
+
613
+ output$downloadTable <- downloadHandler(
614
+ filename = function(file) {
615
+ ifelse(input$tabs == "Histogram", paste0("hist_", outcome(),".svg"),
616
+ ifelse(input$tabs == "Time Series", paste0("ts_", outcome(),".svg"),
617
+ ifelse(input$tabs == "Cross Country", paste0("cc_", outcome(),".svg"), paste0("mover_", outcome(),".svg"))))
618
  },
619
+ content = function(file) {
620
+ if(input$tabs == "Histogram") {
621
+ write.csv(histd(), file)
622
+ showNotification(HTML("File download complete βœ“ "), type = "message")
623
+
624
+ } else if (input$tabs == "Time Series") {
625
+ write.csv(tsd(), file)
626
+ showNotification(HTML("File download complete βœ“ "), type = "message")
627
+
628
+ } else if (input$tabs == "Cross Country") {
629
+ write.csv(ccd(), file)
630
+ showNotification(HTML("File download complete βœ“ "), type = "message")
631
+
632
+ } else {
633
+ write.csv(moverd(), file)
634
+ showNotification(HTML("File download complete βœ“ "), type = "message")
635
+
636
+ }
637
+ }
638
  )
639
  }
640
 
641
+ # Launch App
642
  shinyApp(ui, server)