4
4
# #
5
5
# # Usage:
6
6
# #
7
- # # Rscript generate-codebook.R path/to/qsf path/to/codebook
7
+ # # Rscript generate-codebook.R [UMD/CMU] path/to/qsf path/to/codebook
8
8
9
9
suppressPackageStartupMessages({
10
10
library(tidyverse )
@@ -17,81 +17,33 @@ suppressPackageStartupMessages({
17
17
18
18
19
19
process_qsf <- function (path_to_qsf ,
20
+ survey_version = c(" CMU" , " UMD" ),
20
21
path_to_shortname_map = " ./static/item_shortquestion_map.csv" ,
21
22
path_to_replacement_map = " ./static/item_replacement_map.csv" ) {
23
+ survey_version <- match.arg(survey_version )
22
24
q <- read_json(path_to_qsf )
23
25
wave <- get_wave(path_to_qsf )
24
26
25
- # get the survey elements with flow logic (should be one per block randomization branch)
26
- ii_flow <- q $ SurveyElements %> %
27
- map_chr(" Element" ) %> %
28
- {. == " FL" } %> %
29
- which()
30
- ii_block_randomizer <- q $ SurveyElements [ii_flow ] %> %
31
- map(~ .x $ Payload $ Flow ) %> %
32
- map(~ map(.x ,~ .x $ Type == " BlockRandomizer" )) %> %
33
- unlist() %> %
34
- which()
35
- random_block_ids <- q $ SurveyElements [ii_flow ] %> %
36
- map(~ .x $ Payload $ Flow ) %> %
37
- map(~ .x [ii_block_randomizer ]) %> %
38
- map(~ map(.x ,~ .x $ Flow )) %> %
39
- map(~ map(.x ,~ map(.x ,~ .x $ ID ))) %> %
40
- unlist()
41
-
42
- block_id_item_map <- get_block_item_map(q )
43
- block_id_item_map <- block_id_item_map %> % filter(BlockID %in% random_block_ids ) %> %
44
- select(- BlockID )
45
-
46
- # get the survey elements that are questions:
47
- ii_questions <- q $ SurveyElements %> %
48
- map_chr(" Element" ) %> %
49
- {. == " SQ" } %> %
50
- which()
51
-
52
- # get the questions that were shown to respondents
53
- shown_items <- get_shown_items(q )
54
- ii_shown <- q $ SurveyElements [ii_questions ] %> %
55
- map_chr(~ .x $ Payload $ QuestionID ) %> %
56
- {. %in% shown_items } %> %
57
- which()
27
+ block_id_item_map <- map_qids_to_module(q )
28
+ displayed_questions <- subset_qsf_to_displayed(q )
58
29
59
- # subset qsf to valid elements
60
- displayed_questions <- q $ SurveyElements [ii_questions ][ii_shown ]
61
-
62
- # Qualtrics auto-assigned question IDs
30
+ # get Qualtrics auto-assigned question IDs
63
31
qids <- displayed_questions %> %
64
32
map_chr(~ .x $ Payload $ QuestionID )
65
33
66
- # the items are how we will match these to the survey data:
67
- items <- displayed_questions %> %
68
- map_chr(~ .x $ Payload $ DataExportTag )
69
-
70
- # B13 was originally named incorrectly. Rename manually as needed
71
- items [items == " B13 " ] <- " B13"
72
- # V2a in Wave 13 was originally named incorrectly. Rename manually as needed
73
- if (wave == 13 ) {
74
- items [items == " V2a" ] <- " V2d"
75
- }
34
+ # get item names
35
+ item_names <- displayed_questions %> %
36
+ map_chr(~ .x $ Payload $ DataExportTag ) %> %
37
+ patch_item_names(survey_version , wave )
76
38
77
- # get the text of the question :
39
+ # get question text:
78
40
questions <- displayed_questions %> %
79
41
map_chr(~ .x $ Payload $ QuestionText )
80
42
81
- # get the type of question:
82
- type_map <- c(MC = " Multiple choice" , TE = " Text" , Matrix = " Matrix" )
83
- qtype <- displayed_questions %> %
84
- map_chr(~ .x $ Payload $ QuestionType ) %> %
85
- {type_map [. ]}
86
-
87
- ii_multiselect <- displayed_questions %> %
88
- map_chr(~ .x $ Payload $ Selector ) %> %
89
- {. == " MAVR" } %> %
90
- which()
91
- qtype [ii_multiselect ] <- " Multiselect"
92
- qtype [items == " A5" ] <- " Matrix" # this will be treated like C10
93
-
94
- # get the choices (for MC and Matrix):
43
+ # get question types
44
+ qtype <- get_question_formats(displayed_questions , item_names , survey_version )
45
+
46
+ # get choices for multiple choice (MC) and Matrix items:
95
47
choices <- displayed_questions %> %
96
48
map(~ .x $ Payload $ Choices ) %> %
97
49
map(~ map(.x , " Display" ))
@@ -122,8 +74,8 @@ process_qsf <- function(path_to_qsf,
122
74
map(which ) %> %
123
75
map(names ) %> %
124
76
unlist()
125
- other_text_items <- paste(items [ii_other_text_option ], text_elem , " TEXT" , sep = " _" ) %> %
126
- setNames(items [ii_other_text_option ])
77
+ other_text_items <- paste(item_names [ii_other_text_option ], text_elem , " TEXT" , sep = " _" ) %> %
78
+ setNames(item_names [ii_other_text_option ])
127
79
128
80
# some questions port the choices from other questions
129
81
ii_carryforward <- displayed_questions %> %
@@ -189,7 +141,7 @@ process_qsf <- function(path_to_qsf,
189
141
paste(c(qid , selectable_text , option_code ), collapse = " " )
190
142
}, .x )) %> %
191
143
# Replace QID with question number (A2, etc)
192
- map(~ gsubfn(" (QID[0-9]+)" , function (qid ) {items [qids == qid ]}, .x )) %> %
144
+ map(~ gsubfn(" (QID[0-9]+)" , function (qid ) {item_names [qids == qid ]}, .x )) %> %
193
145
# Collapse logic into a single string.
194
146
map(~ paste(.x , collapse = " " ))
195
147
@@ -203,7 +155,7 @@ process_qsf <- function(path_to_qsf,
203
155
unlist()
204
156
205
157
# format all qsf content lists into a single tibble
206
- qdf <- tibble(variable = items ,
158
+ qdf <- tibble(variable = item_names ,
207
159
question = questions ,
208
160
type = qtype ,
209
161
choices = choices ,
@@ -213,7 +165,7 @@ process_qsf <- function(path_to_qsf,
213
165
214
166
# Add on module randomization
215
167
block_id_item_map <- block_id_item_map %> %
216
- left_join(data.frame (qid = qids , item = items ), by = c(" Questions" = " qid" ))
168
+ left_join(data.frame (qid = qids , item = item_names ), by = c(" Questions" = " qid" ))
217
169
qdf <- qdf %> % left_join(block_id_item_map , by = c(variable = " item" )) %> %
218
170
rename(group_of_respondents_item_was_shown_to = BlockName )
219
171
@@ -272,12 +224,17 @@ process_qsf <- function(path_to_qsf,
272
224
select(new ) %> %
273
225
unnest(new )
274
226
275
- # A5 and C10 are special cases b/c of they are matrix of text entry questions:
276
- # also C10 needs an extra _1.
277
- matrix_items <- matrix_items %> %
278
- mutate(variable = if_else(str_starts(variable , " C10" ), paste0(variable , " _1" ), variable ),
279
- type = if_else(str_starts(variable , " A5|C10" ), " Text" , type ),
280
- choices = if_else(str_starts(variable , " A5|C10" ), list (list ()), choices ))
227
+ # Custom matrix formatting
228
+ if (survey_version == " CMU" ) {
229
+ # A5 and C10 are special cases b/c they are matrices of text entry questions:
230
+ # also C10 needs an extra _1.
231
+ matrix_items <- matrix_items %> %
232
+ mutate(variable = if_else(str_starts(variable , " C10" ), paste0(variable , " _1" ), variable ),
233
+ type = if_else(str_starts(variable , " A5|C10" ), " Text" , type ),
234
+ choices = if_else(str_starts(variable , " A5|C10" ), list (list ()), choices ))
235
+ } else if (survey_version == " UMD" ) {
236
+ # pass
237
+ }
281
238
282
239
qdf <- bind_rows(nonmatrix_items , matrix_items )
283
240
@@ -448,11 +405,12 @@ add_qsf_to_codebook <- function(path_to_qsf, path_to_codebook) {
448
405
449
406
args <- commandArgs(TRUE )
450
407
451
- if (length(args ) != 2 ) {
452
- stop(" Usage: Rscript generate-codebook.R path/to/qsf path/to/codebook" )
408
+ if (length(args ) != 3 ) {
409
+ stop(" Usage: Rscript generate-codebook.R [UMD/CMU] path/to/qsf path/to/codebook" )
453
410
}
454
411
455
- path_to_qsf <- args [1 ]
456
- path_to_codebook <- args [2 ]
412
+ survey_version <- args [1 ]
413
+ path_to_qsf <- args [2 ]
414
+ path_to_codebook <- args [3 ]
457
415
458
416
invisible (add_qsf_to_codebook(path_to_qsf , path_to_codebook ))
0 commit comments