Spaces:
Sleeping
Sleeping
Update app.R
Browse files
app.R
CHANGED
|
@@ -1,58 +1,642 @@
|
|
| 1 |
-
library(
|
| 2 |
-
library(
|
| 3 |
library(dplyr)
|
| 4 |
-
library(
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 18 |
),
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 25 |
)
|
| 26 |
|
|
|
|
| 27 |
server <- function(input, output, session) {
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
})
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 49 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 50 |
}
|
| 51 |
-
|
| 52 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 53 |
},
|
| 54 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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)
|