From 68104fa425dd59c995d6fe1da62eae5e1c9f884c Mon Sep 17 00:00:00 2001 From: Sean Fahey Date: Sat, 24 Dec 2016 12:20:35 -0500 Subject: [PATCH 01/76] removed api_key references from the code --- R/smlogin.r | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/R/smlogin.r b/R/smlogin.r index 6891b67..005ff90 100644 --- a/R/smlogin.r +++ b/R/smlogin.r @@ -1,23 +1,18 @@ smlogin <- function(client_id = getOption('sm_client_id'), - api_key = getOption('sm_api_key'), secret = getOption('sm_secret'), redirect_uri = 'http://localhost:1410', response_type='code'){ if(is.null(client_id)) stop("Must supply developer username as 'client_id'") - if(is.null(api_key)) - stop("Must supply developer API key as 'api_key'") if(is.null(secret)) stop("Must supply developer secret key as 'secret'") a <- list(response_type = response_type, redirect_uri = redirect_uri, - client_id = client_id, - api_key = api_key) + client_id = client_id) a <- paste(names(a), curl_escape(a), sep='=', collapse='&') e <- structure(list(authorize = 'https://api.surveymonkey.net/oauth/authorize', access = 'https://api.surveymonkey.net/oauth/token'), class='oauth_endpoint') e$authorize <- paste(e$authorize,a,sep='?') - e$access <- paste(e$access,'?api_key=',api_key,sep='') smapp <- oauth_app('surveymonkey', client_id, secret) token <- oauth2.0_token(e, smapp, use_oob = FALSE, cache = FALSE) From 18bd2282473e9800129373604497c0696f39fd56 Mon Sep 17 00:00:00 2001 From: Sean Fahey Date: Mon, 26 Dec 2016 09:16:19 -0500 Subject: [PATCH 02/76] initial commit. Separated out from the surveylist function --- R/print.sm_survey.r | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 R/print.sm_survey.r diff --git a/R/print.sm_survey.r b/R/print.sm_survey.r new file mode 100644 index 0000000..0c1b73f --- /dev/null +++ b/R/print.sm_survey.r @@ -0,0 +1,27 @@ +print.sm_survey <- function(x, ...){ + if(!is.null(x$title)) { + if(is.list(x$title)) + cat('Survey Title:', x$title$text, '\n') + else + cat('Survey Title:', x$title, '\n') + } + if(!is.null(x$survey_id)) + cat('ID:', x$survey_id, '\n') + if(!is.null(x$language_id)) + cat('Language:', x$language_id, '\n') + if(!is.null(x$question_count)) + cat('No. of Questions:', x$question_count, '\n') + if(!is.null(x$num_responses)) + cat('Respondents:', x$num_responses, '\n') + if(!is.null(x$preview_url)) + cat('Preview URL:', x$preview_url, '\n') + if(!is.null(x$analysis_url)) + cat('Analysis URL:', x$analysis_url, '\n') + if(!is.null(x$date_created)) + cat('Date Created: ', x$date_created, '\n') + if(!is.null(x$date_modified)) + cat('Date Modified:', x$date_modified, '\n') + if(!is.null(x$pages)) + cat('Survey Pages:', length(x$pages), '\n') + invisible(x) +} From cba3d42b7e3bf4c6907cb103228cde9bc6fd04a0 Mon Sep 17 00:00:00 2001 From: Sean Fahey Date: Mon, 26 Dec 2016 09:17:24 -0500 Subject: [PATCH 03/76] updated content to parsed_content, removed api_key references, updated url to api v3 --- R/userdetails.r | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/R/userdetails.r b/R/userdetails.r index b0487b1..7bbe818 100644 --- a/R/userdetails.r +++ b/R/userdetails.r @@ -1,20 +1,15 @@ userdetails <- function( - api_key = getOption('sm_api_key'), oauth_token = getOption('sm_oauth_token'), ... ){ - if(!is.null(api_key)) { - u <- paste('https://api.surveymonkey.net/v2/user/get_user_details?', - 'api_key=', api_key, sep='') - } else - stop("Must specify 'api_key'") + u <- 'https://api.surveymonkey.net/v3/users/me' if(!is.null(oauth_token)) token <- paste('bearer', oauth_token) else stop("Must specify 'oauth_token'") - out <- POST(u, config = add_headers(Authorization=token), ...) + out <- POST(u, config = add_headers(Authorization=token)) stop_for_status(out) - content <- content(out, as='parsed') + content <- parsed_content(out) if(content$status != 0) warning("An error occurred: ",content$errmsg) structure(content$data$user_details, class='sm_userdetails') From 2f5ca72d39da407e96bdb9269efb057edd46e8f5 Mon Sep 17 00:00:00 2001 From: Sean Fahey Date: Mon, 26 Dec 2016 09:19:19 -0500 Subject: [PATCH 04/76] removed api_key references, updated api url to v3, changed post to get, commented out content$status lines --- R/surveylist.r | 54 ++++++++++---------------------------------------- 1 file changed, 11 insertions(+), 43 deletions(-) diff --git a/R/surveylist.r b/R/surveylist.r index 52cf2eb..f302e42 100644 --- a/R/surveylist.r +++ b/R/surveylist.r @@ -7,17 +7,13 @@ surveylist <- function( recipient_email = NULL, order_asc = NULL, fields = NULL, - api_key = getOption('sm_api_key'), oauth_token = getOption('sm_oauth_token'), ... ){ - if(!is.null(api_key)) { - u <- paste('https://api.surveymonkey.net/v2/surveys/get_survey_list?', - 'api_key=', api_key, sep='') - } else - stop("Must specify 'api_key'") - if(!is.null(oauth_token)) + if(!is.null(oauth_token)){ + u <- 'https://api.surveymonkey.net/v3/surveys?' token <- paste('bearer', oauth_token) + } else stop("Must specify 'oauth_token'") if(inherits(start_date, "POSIXct") | inherits(start_date, "Date")) @@ -35,40 +31,12 @@ surveylist <- function( b <- toJSON(b[!nulls], auto_unbox = TRUE) h <- add_headers(Authorization=token, 'Content-Type'='application/json') - out <- POST(u, config = h, ..., body = b) + out <- GET(u, config = h, ..., body = b) stop_for_status(out) - content <- content(out, as='parsed') - if(content$status != 0){ - warning("An error occurred: ",content$errmsg) - return(content) - } else - lapply(content$data$surveys, `class<-`, 'sm_survey') -} - -print.sm_survey <- function(x, ...){ - if(!is.null(x$title)) { - if(is.list(x$title)) - cat('Survey Title:', x$title$text, '\n') - else - cat('Survey Title:', x$title, '\n') - } - if(!is.null(x$survey_id)) - cat('ID:', x$survey_id, '\n') - if(!is.null(x$language_id)) - cat('Language:', x$language_id, '\n') - if(!is.null(x$question_count)) - cat('No. of Questions:', x$question_count, '\n') - if(!is.null(x$num_responses)) - cat('Respondents:', x$num_responses, '\n') - if(!is.null(x$preview_url)) - cat('Preview URL:', x$preview_url, '\n') - if(!is.null(x$analysis_url)) - cat('Analysis URL:', x$analysis_url, '\n') - if(!is.null(x$date_created)) - cat('Date Created: ', x$date_created, '\n') - if(!is.null(x$date_modified)) - cat('Date Modified:', x$date_modified, '\n') - if(!is.null(x$pages)) - cat('Survey Pages:', length(x$pages), '\n') - invisible(x) -} + content <- parsed_content(out) + # if(content$status != 0){ + # warning("An error occurred: ",content$errmsg) + # return(content) + # } else + # lapply(content$data$surveys, `class<-`, 'sm_survey') +} \ No newline at end of file From 3f2afebaec7e2ecd9baacdd3f479ce3a9cda95f8 Mon Sep 17 00:00:00 2001 From: Sean Fahey Date: Mon, 26 Dec 2016 09:19:32 -0500 Subject: [PATCH 05/76] initial commit --- Rmonkey.Rproj | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 Rmonkey.Rproj diff --git a/Rmonkey.Rproj b/Rmonkey.Rproj new file mode 100644 index 0000000..21a4da0 --- /dev/null +++ b/Rmonkey.Rproj @@ -0,0 +1,17 @@ +Version: 1.0 + +RestoreWorkspace: Default +SaveWorkspace: Default +AlwaysSaveHistory: Default + +EnableCodeIndexing: Yes +UseSpacesForTab: Yes +NumSpacesForTab: 2 +Encoding: UTF-8 + +RnwWeave: Sweave +LaTeX: pdfLaTeX + +BuildType: Package +PackageUseDevtools: Yes +PackageInstallArgs: --no-multiarch --with-keep.source From f3364335f11be0bfa41e4283db997a9633bb84d2 Mon Sep 17 00:00:00 2001 From: Sean Fahey Date: Mon, 26 Dec 2016 09:31:02 -0500 Subject: [PATCH 06/76] returned print.sm_survey to surveylist --- R/print.sm_survey.r | 27 --------------------------- R/surveylist.r | 30 +++++++++++++++++++++++++++++- 2 files changed, 29 insertions(+), 28 deletions(-) delete mode 100644 R/print.sm_survey.r diff --git a/R/print.sm_survey.r b/R/print.sm_survey.r deleted file mode 100644 index 0c1b73f..0000000 --- a/R/print.sm_survey.r +++ /dev/null @@ -1,27 +0,0 @@ -print.sm_survey <- function(x, ...){ - if(!is.null(x$title)) { - if(is.list(x$title)) - cat('Survey Title:', x$title$text, '\n') - else - cat('Survey Title:', x$title, '\n') - } - if(!is.null(x$survey_id)) - cat('ID:', x$survey_id, '\n') - if(!is.null(x$language_id)) - cat('Language:', x$language_id, '\n') - if(!is.null(x$question_count)) - cat('No. of Questions:', x$question_count, '\n') - if(!is.null(x$num_responses)) - cat('Respondents:', x$num_responses, '\n') - if(!is.null(x$preview_url)) - cat('Preview URL:', x$preview_url, '\n') - if(!is.null(x$analysis_url)) - cat('Analysis URL:', x$analysis_url, '\n') - if(!is.null(x$date_created)) - cat('Date Created: ', x$date_created, '\n') - if(!is.null(x$date_modified)) - cat('Date Modified:', x$date_modified, '\n') - if(!is.null(x$pages)) - cat('Survey Pages:', length(x$pages), '\n') - invisible(x) -} diff --git a/R/surveylist.r b/R/surveylist.r index f302e42..9ce6993 100644 --- a/R/surveylist.r +++ b/R/surveylist.r @@ -39,4 +39,32 @@ surveylist <- function( # return(content) # } else # lapply(content$data$surveys, `class<-`, 'sm_survey') -} \ No newline at end of file +} + +print.sm_survey <- function(x, ...){ + if(!is.null(x$title)) { + if(is.list(x$title)) + cat('Survey Title:', x$title$text, '\n') + else + cat('Survey Title:', x$title, '\n') + } + if(!is.null(x$survey_id)) + cat('ID:', x$survey_id, '\n') + if(!is.null(x$language_id)) + cat('Language:', x$language_id, '\n') + if(!is.null(x$question_count)) + cat('No. of Questions:', x$question_count, '\n') + if(!is.null(x$num_responses)) + cat('Respondents:', x$num_responses, '\n') + if(!is.null(x$preview_url)) + cat('Preview URL:', x$preview_url, '\n') + if(!is.null(x$analysis_url)) + cat('Analysis URL:', x$analysis_url, '\n') + if(!is.null(x$date_created)) + cat('Date Created: ', x$date_created, '\n') + if(!is.null(x$date_modified)) + cat('Date Modified:', x$date_modified, '\n') + if(!is.null(x$pages)) + cat('Survey Pages:', length(x$pages), '\n') + invisible(x) +} From 4e44f41fc2778266c5780cd51ecd9b3f36663b93 Mon Sep 17 00:00:00 2001 From: Sean Fahey Date: Mon, 26 Dec 2016 09:51:07 -0500 Subject: [PATCH 07/76] modified lapply function --- R/surveylist.r | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/surveylist.r b/R/surveylist.r index 9ce6993..0f4ab89 100644 --- a/R/surveylist.r +++ b/R/surveylist.r @@ -38,7 +38,7 @@ surveylist <- function( # warning("An error occurred: ",content$errmsg) # return(content) # } else - # lapply(content$data$surveys, `class<-`, 'sm_survey') + lapply(content$data, `class<-`, 'sm_survey') } print.sm_survey <- function(x, ...){ From fc8d0e94bcc0b28b8146ce33ef870e86e26970ea Mon Sep 17 00:00:00 2001 From: Sean Fahey Date: Mon, 26 Dec 2016 19:10:15 -0500 Subject: [PATCH 08/76] updated to use SurveyMonkey API V3 urls, removed api_key references, removed body JSON now in url, modified class structure line, added new function call to get question_details --- R/surveydetails.r | 37 ++++++++++++++++++------------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/R/surveydetails.r b/R/surveydetails.r index 3f34dfb..52dcc24 100644 --- a/R/surveydetails.r +++ b/R/surveydetails.r @@ -1,42 +1,41 @@ surveydetails <- function( survey, - api_key = getOption('sm_api_key'), oauth_token = getOption('sm_oauth_token'), + question_details = FALSE, ... ){ if(inherits(survey, 'sm_survey')) - survey <- survey$survey_id - if(!is.null(api_key)) { - u <- paste('https://api.surveymonkey.net/v2/surveys/get_survey_details?', - 'api_key=', api_key, sep='') - } else - stop("Must specify 'api_key'") - if(!is.null(oauth_token)) - token <- paste('bearer', oauth_token) + survey <- survey$id + if(question_details) { + u <- paste('https://api.surveymonkey.net/v3/surveys/',survey,'/details?',sep='') + } + else + u <- paste('https://api.surveymonkey.net/v3/surveys/',survey,'?',sep='') + if(!is.null(oauth_token)) { + token <- paste('bearer', oauth_token) + } else stop("Must specify 'oauth_token'") h <- add_headers(Authorization=token, 'Content-Type'='application/json') - b <- toJSON(list(survey_id = survey), auto_unbox = TRUE) - out <- POST(u, config = h, ..., body = b) + out <- GET(u, config = h, ...) stop_for_status(out) - content <- content(out, as='parsed') - if(content$status != 0) { - warning("An error occurred: ",content$errmsg) - return(content) - } else - structure(content$data, class='sm_survey') + content <- parsed_content(out) + # if(content$status != 0) { + # warning("An error occurred: ",content$errmsg) + # return(content) + # } else + structure(content, class = "sm_survey") } surveyquestions <- function( survey, details, - api_key = getOption('sm_api_key'), oauth_token = getOption('sm_oauth_token'), ... ){ if (!missing(survey)) { - d <- surveydetails(survey, api_key = api_key, oauth_token = oauth_token, ...) + d <- surveydetails(survey, oauth_token = oauth_token, ...) } else { d <- details } From 8507b7dd44eef7e0d16a9635e5c95ad84513edde Mon Sep 17 00:00:00 2001 From: Sean Fahey Date: Mon, 26 Dec 2016 19:32:11 -0500 Subject: [PATCH 09/76] updated surveyquetions function to match new api data structure and to remove HTML tags from heading responses. updated surveypreview function to match new api data structure --- R/surveydetails.r | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/R/surveydetails.r b/R/surveydetails.r index 52dcc24..deafc5d 100644 --- a/R/surveydetails.r +++ b/R/surveydetails.r @@ -35,16 +35,17 @@ surveyquestions <- function( ... ){ if (!missing(survey)) { - d <- surveydetails(survey, oauth_token = oauth_token, ...) + d <- surveydetails(survey, oauth_token = getOption('sm_oauth_token'), question_details = TRUE, ...) } else { d <- details } questions <- unlist(unlist(lapply(d$pages, `[`, "questions"), recursive = FALSE), recursive = FALSE) - n <- unname(unlist(lapply(questions, `[`, "question_id"))) - w <- unname(unlist(lapply(questions, `[`, "heading"))) + n <- unname(unlist(lapply(questions, `[`, "id"))) + w <- unname(unlist(lapply(questions, `[`, "headings"))) + w <- gsub("<.*?>", "", w) structure(w, names = n, class = c("character", "sm_surveyquestions")) } surveypreview <- function(details) { - browseURL(details$preview_url) + browseURL(details$preview) } From 000dc2ca021db75bd6984e7f37f451dff16d6c53 Mon Sep 17 00:00:00 2001 From: Sean Fahey Date: Mon, 26 Dec 2016 19:40:28 -0500 Subject: [PATCH 10/76] modified surveyquestions and surveypreview functions to use the survey as an input instead of using the survey detail to offer consistency across functions --- R/surveydetails.r | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/R/surveydetails.r b/R/surveydetails.r index deafc5d..8d08d6d 100644 --- a/R/surveydetails.r +++ b/R/surveydetails.r @@ -28,17 +28,8 @@ surveydetails <- function( structure(content, class = "sm_survey") } -surveyquestions <- function( - survey, - details, - oauth_token = getOption('sm_oauth_token'), - ... -){ - if (!missing(survey)) { - d <- surveydetails(survey, oauth_token = getOption('sm_oauth_token'), question_details = TRUE, ...) - } else { - d <- details - } +surveyquestions <- function(survey){ + d <- surveydetails(survey, oauth_token = getOption('sm_oauth_token'), question_details = TRUE) questions <- unlist(unlist(lapply(d$pages, `[`, "questions"), recursive = FALSE), recursive = FALSE) n <- unname(unlist(lapply(questions, `[`, "id"))) w <- unname(unlist(lapply(questions, `[`, "headings"))) @@ -46,6 +37,7 @@ surveyquestions <- function( structure(w, names = n, class = c("character", "sm_surveyquestions")) } -surveypreview <- function(details) { - browseURL(details$preview) +surveypreview <- function(survey) { + d <- surveydetails(survey, oauth_token = getOption('sm_oauth_token'), question_details = TRUE) + browseURL(d$preview) } From fcbbb0a446f635fb076b9895019ecdb1c2bd71e3 Mon Sep 17 00:00:00 2001 From: Sean Fahey Date: Mon, 26 Dec 2016 19:40:28 -0500 Subject: [PATCH 11/76] updated print.sm_survey to match fields for SurveyMonkey V3 API --- R/surveydetails.r | 18 +++++------------- R/surveylist.r | 28 +++++++++++++--------------- 2 files changed, 18 insertions(+), 28 deletions(-) diff --git a/R/surveydetails.r b/R/surveydetails.r index deafc5d..8d08d6d 100644 --- a/R/surveydetails.r +++ b/R/surveydetails.r @@ -28,17 +28,8 @@ surveydetails <- function( structure(content, class = "sm_survey") } -surveyquestions <- function( - survey, - details, - oauth_token = getOption('sm_oauth_token'), - ... -){ - if (!missing(survey)) { - d <- surveydetails(survey, oauth_token = getOption('sm_oauth_token'), question_details = TRUE, ...) - } else { - d <- details - } +surveyquestions <- function(survey){ + d <- surveydetails(survey, oauth_token = getOption('sm_oauth_token'), question_details = TRUE) questions <- unlist(unlist(lapply(d$pages, `[`, "questions"), recursive = FALSE), recursive = FALSE) n <- unname(unlist(lapply(questions, `[`, "id"))) w <- unname(unlist(lapply(questions, `[`, "headings"))) @@ -46,6 +37,7 @@ surveyquestions <- function( structure(w, names = n, class = c("character", "sm_surveyquestions")) } -surveypreview <- function(details) { - browseURL(details$preview) +surveypreview <- function(survey) { + d <- surveydetails(survey, oauth_token = getOption('sm_oauth_token'), question_details = TRUE) + browseURL(d$preview) } diff --git a/R/surveylist.r b/R/surveylist.r index 0f4ab89..de28783 100644 --- a/R/surveylist.r +++ b/R/surveylist.r @@ -42,24 +42,22 @@ surveylist <- function( } print.sm_survey <- function(x, ...){ - if(!is.null(x$title)) { - if(is.list(x$title)) - cat('Survey Title:', x$title$text, '\n') - else + if(!is.null(x$title)) cat('Survey Title:', x$title, '\n') - } - if(!is.null(x$survey_id)) - cat('ID:', x$survey_id, '\n') - if(!is.null(x$language_id)) - cat('Language:', x$language_id, '\n') + if(!is.null(x$nickname)) + cat('Survey Nickname:', x$nickname, '\n') + if(!is.null(x$id)) + cat('ID:', x$id, '\n') + if(!is.null(x$language)) + cat('Language:', x$language, '\n') if(!is.null(x$question_count)) cat('No. of Questions:', x$question_count, '\n') - if(!is.null(x$num_responses)) - cat('Respondents:', x$num_responses, '\n') - if(!is.null(x$preview_url)) - cat('Preview URL:', x$preview_url, '\n') - if(!is.null(x$analysis_url)) - cat('Analysis URL:', x$analysis_url, '\n') + if(!is.null(x$response_count)) + cat('Respondents:', x$response_count, '\n') + if(!is.null(x$preview)) + cat('Preview URL:', x$preview, '\n') + if(!is.null(x$analyze_url)) + cat('Analysis URL:', x$analyze_url, '\n') if(!is.null(x$date_created)) cat('Date Created: ', x$date_created, '\n') if(!is.null(x$date_modified)) From dd1f4a37618a000e82f63030c2cb7e730a3fc0f6 Mon Sep 17 00:00:00 2001 From: Sean Fahey Date: Tue, 27 Dec 2016 14:00:50 -0500 Subject: [PATCH 12/76] changed POST to GET, updated class function, commented out content$status warning --- R/userdetails.r | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/R/userdetails.r b/R/userdetails.r index 7bbe818..bc1df1b 100644 --- a/R/userdetails.r +++ b/R/userdetails.r @@ -6,11 +6,11 @@ userdetails <- function( if(!is.null(oauth_token)) token <- paste('bearer', oauth_token) else - stop("Must specify 'oauth_token'") - out <- POST(u, config = add_headers(Authorization=token)) + stop("Must specify 'oauth_token'. Try smlogin() first to get a token.") + out <- GET(u, config = add_headers(Authorization=token)) stop_for_status(out) content <- parsed_content(out) - if(content$status != 0) - warning("An error occurred: ",content$errmsg) - structure(content$data$user_details, class='sm_userdetails') + # if(content$status != 0) + # warning("An error occurred: ",content$errmsg) + structure(content$data$user_details, class="sm_userdetails") } From 3136434f7f95bd4bf3337528eb8d57986ca82af4 Mon Sep 17 00:00:00 2001 From: Sean Fahey Date: Tue, 27 Dec 2016 14:15:39 -0500 Subject: [PATCH 13/76] added json to header and fixed code to add sm_userdetails class --- R/userdetails.r | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/R/userdetails.r b/R/userdetails.r index bc1df1b..bd6e128 100644 --- a/R/userdetails.r +++ b/R/userdetails.r @@ -7,10 +7,11 @@ userdetails <- function( token <- paste('bearer', oauth_token) else stop("Must specify 'oauth_token'. Try smlogin() first to get a token.") - out <- GET(u, config = add_headers(Authorization=token)) + out <- GET(u, config = add_headers(Authorization=token, + 'Content-Type'='application/json')) stop_for_status(out) content <- parsed_content(out) # if(content$status != 0) # warning("An error occurred: ",content$errmsg) - structure(content$data$user_details, class="sm_userdetails") + structure(content, class="sm_userdetails") } From d33041f4306d37679c6111d333417c2424bfd923 Mon Sep 17 00:00:00 2001 From: Sean Fahey Date: Tue, 27 Dec 2016 14:18:37 -0500 Subject: [PATCH 14/76] initial commit --- RMonkey Demo.R | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 RMonkey Demo.R diff --git a/RMonkey Demo.R b/RMonkey Demo.R new file mode 100644 index 0000000..884a4ce --- /dev/null +++ b/RMonkey Demo.R @@ -0,0 +1,42 @@ +# RMonkey library demo +# +# Sean Fahey +# 2016-12-28 +# +# This program shows how the RMonkey library can be used to access SurveyMonkey data +# via API V3. +# + +# load needed libraries +library(curl) +library(httr) + +# Load the latest Rmonkey library from github +if(!require("devtools")) { + install.packages("devtools") + library("devtools") +} +install_github("seanofahey/Rmonkey") +library("Rmonkey") + +# Create a SurveyMonkey App to enable the API +# 1) go to https://developer.surveymonkey.com/apps/ to create an app +# 2) set the OAuth redirect URL as http://localhost:1410 +# 3) set the scope permissions (I used all the view ones but no create ones) +# 4) note the following values from the App screen: clientID, Secret + + +# Enter your app API info into R +options(sm_client_id = 'YourMasheryDeveloperUsername') +options(sm_secret = 'YourAPISecret') + +# Get a long lasting oauth token. This function completes the OAuth handshake +# and saves a long lasting token on the computer. It needs to be done only once +smlogin() + +# Lookup userdetails to test API +userdetails() + +# Show a list of surveys +surveylist() + From 8ecfba3aa2d4e60fcf6b977e214b5a35c7c543d7 Mon Sep 17 00:00:00 2001 From: Sean Fahey Date: Tue, 27 Dec 2016 14:24:05 -0500 Subject: [PATCH 15/76] moved print.sm_survey to surveydetails from surveylist --- R/surveydetails.r | 26 ++++++++++++++++++++++++++ R/surveylist.r | 28 +--------------------------- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/R/surveydetails.r b/R/surveydetails.r index 8d08d6d..6c38a9e 100644 --- a/R/surveydetails.r +++ b/R/surveydetails.r @@ -41,3 +41,29 @@ surveypreview <- function(survey) { d <- surveydetails(survey, oauth_token = getOption('sm_oauth_token'), question_details = TRUE) browseURL(d$preview) } + +print.sm_survey <- function(x, ...){ + if(!is.null(x$title)) + cat('Survey Title:', x$title, '\n') + if(!is.null(x$nickname)) + cat('Survey Nickname:', x$nickname, '\n') + if(!is.null(x$id)) + cat('ID:', x$id, '\n') + if(!is.null(x$language)) + cat('Language:', x$language, '\n') + if(!is.null(x$question_count)) + cat('No. of Questions:', x$question_count, '\n') + if(!is.null(x$response_count)) + cat('Respondents:', x$response_count, '\n') + if(!is.null(x$preview)) + cat('Preview URL:', x$preview, '\n') + if(!is.null(x$analyze_url)) + cat('Analysis URL:', x$analyze_url, '\n') + if(!is.null(x$date_created)) + cat('Date Created: ', x$date_created, '\n') + if(!is.null(x$date_modified)) + cat('Date Modified:', x$date_modified, '\n') + if(!is.null(x$pages)) + cat('Survey Pages:', length(x$pages), '\n') + invisible(x) +} diff --git a/R/surveylist.r b/R/surveylist.r index de28783..557928a 100644 --- a/R/surveylist.r +++ b/R/surveylist.r @@ -39,30 +39,4 @@ surveylist <- function( # return(content) # } else lapply(content$data, `class<-`, 'sm_survey') -} - -print.sm_survey <- function(x, ...){ - if(!is.null(x$title)) - cat('Survey Title:', x$title, '\n') - if(!is.null(x$nickname)) - cat('Survey Nickname:', x$nickname, '\n') - if(!is.null(x$id)) - cat('ID:', x$id, '\n') - if(!is.null(x$language)) - cat('Language:', x$language, '\n') - if(!is.null(x$question_count)) - cat('No. of Questions:', x$question_count, '\n') - if(!is.null(x$response_count)) - cat('Respondents:', x$response_count, '\n') - if(!is.null(x$preview)) - cat('Preview URL:', x$preview, '\n') - if(!is.null(x$analyze_url)) - cat('Analysis URL:', x$analyze_url, '\n') - if(!is.null(x$date_created)) - cat('Date Created: ', x$date_created, '\n') - if(!is.null(x$date_modified)) - cat('Date Modified:', x$date_modified, '\n') - if(!is.null(x$pages)) - cat('Survey Pages:', length(x$pages), '\n') - invisible(x) -} +} \ No newline at end of file From e93df556015db3d0285b3ebf33c7ab9436f6c451 Mon Sep 17 00:00:00 2001 From: Sean Fahey Date: Tue, 27 Dec 2016 14:28:16 -0500 Subject: [PATCH 16/76] switched order of parameters in the function call --- R/surveydetails.r | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/surveydetails.r b/R/surveydetails.r index 6c38a9e..0890af9 100644 --- a/R/surveydetails.r +++ b/R/surveydetails.r @@ -1,7 +1,7 @@ surveydetails <- function( survey, - oauth_token = getOption('sm_oauth_token'), question_details = FALSE, + oauth_token = getOption('sm_oauth_token'), ... ){ if(inherits(survey, 'sm_survey')) From c6f390f0a9bb18a9ea16c70884d716e7561117e1 Mon Sep 17 00:00:00 2001 From: Sean Fahey Date: Tue, 27 Dec 2016 14:28:43 -0500 Subject: [PATCH 17/76] updated to demonstrate more functions --- RMonkey Demo.R | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/RMonkey Demo.R b/RMonkey Demo.R index 884a4ce..ddbeac3 100644 --- a/RMonkey Demo.R +++ b/RMonkey Demo.R @@ -35,8 +35,20 @@ options(sm_secret = 'YourAPISecret') smlogin() # Lookup userdetails to test API -userdetails() +users <- userdetails() # Show a list of surveys -surveylist() +sl <- surveylist() + +# Display the list of surveys +# (This shows each survey using the print.sm_survey function which overrides the standard +# print function) +sl + +# Get and display more details for the first survey on the list +# (This uses the same print.sm_survey function but has more data to display) +sd1 <- surveydetails(sl[[1]]) + +# Get and display survey deatils including the details on the survey questions +sd1.q <- surveydetails(sl[[1]], question_details = TRUE) From cc26c75d5613ca6b15be2a25e0425797feebd015 Mon Sep 17 00:00:00 2001 From: Sean Fahey Date: Wed, 28 Dec 2016 00:13:09 -0500 Subject: [PATCH 18/76] removed question_details option from surveydetails call since it is not needed --- R/surveydetails.r | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/surveydetails.r b/R/surveydetails.r index 0890af9..ccac3e6 100644 --- a/R/surveydetails.r +++ b/R/surveydetails.r @@ -38,7 +38,7 @@ surveyquestions <- function(survey){ } surveypreview <- function(survey) { - d <- surveydetails(survey, oauth_token = getOption('sm_oauth_token'), question_details = TRUE) + d <- surveydetails(survey, oauth_token = getOption('sm_oauth_token')) browseURL(d$preview) } From 804b915b62fdc6dc660a755251b223e15456854a Mon Sep 17 00:00:00 2001 From: Sean Fahey Date: Wed, 28 Dec 2016 00:13:27 -0500 Subject: [PATCH 19/76] added more functions --- RMonkey Demo.R | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/RMonkey Demo.R b/RMonkey Demo.R index ddbeac3..a4d1b20 100644 --- a/RMonkey Demo.R +++ b/RMonkey Demo.R @@ -35,9 +35,9 @@ options(sm_secret = 'YourAPISecret') smlogin() # Lookup userdetails to test API -users <- userdetails() +userdetails() -# Show a list of surveys +# Return a list of surveys sl <- surveylist() # Display the list of surveys @@ -48,7 +48,11 @@ sl # Get and display more details for the first survey on the list # (This uses the same print.sm_survey function but has more data to display) sd1 <- surveydetails(sl[[1]]) +sd1 # Get and display survey deatils including the details on the survey questions sd1.q <- surveydetails(sl[[1]], question_details = TRUE) +str(sd1.q) +# Show the responses to a survey +sl1.r <- getresponses(sl[[1]]) From 69625847c3c5b3ede8a33ca0ebeb8773ff377370 Mon Sep 17 00:00:00 2001 From: Sean Fahey Date: Wed, 28 Dec 2016 00:14:15 -0500 Subject: [PATCH 20/76] removed content$status error checking block. Reformatted class assignment --- R/getresponses.r | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/R/getresponses.r b/R/getresponses.r index 3b59712..98e97cd 100644 --- a/R/getresponses.r +++ b/R/getresponses.r @@ -33,15 +33,10 @@ getresponses <- function( out <- GET(u, config = h, ...) stop_for_status(out) content <- parsed_content(out) - # if (content$status != 0) { - # warning("An error occurred: ",content$errmsg) - # return(content) - # } else { if (!is.null(content$data)) { lapply(content$data, `class<-`, "sm_response") - # content$data <- lapply(content$data, `attr<-`, 'survey_id', survey) } - return(structure(content, class = 'sm_response_list')) + structure(content, class = 'sm_response_list') } print.sm_response <- function(x, ...){ From 9781142c08a5861b4b9e0015f5d51ed7e3f28a08 Mon Sep 17 00:00:00 2001 From: Sean Fahey Date: Wed, 28 Dec 2016 00:29:20 -0500 Subject: [PATCH 21/76] added survey questions, surveypreview, and getreponses examples --- RMonkey Demo.R | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/RMonkey Demo.R b/RMonkey Demo.R index a4d1b20..5dc6e49 100644 --- a/RMonkey Demo.R +++ b/RMonkey Demo.R @@ -50,9 +50,18 @@ sl sd1 <- surveydetails(sl[[1]]) sd1 -# Get and display survey deatils including the details on the survey questions +# Get and display survey deatils including the details of the survey questions sd1.q <- surveydetails(sl[[1]], question_details = TRUE) str(sd1.q) -# Show the responses to a survey +# Show just the questions for a survey +sl1.q <- surveyquestions(sl[[1]]) + +# Open browser to a web preview of the survey +surveypreview(sl[[1]]) + +# Show the list of response ids to a survey sl1.r <- getresponses(sl[[1]]) + +# Show the expanded list of responses including answers to all questions +sl1.rd <- getresponses(sl[[1]], bulk = TRUE) From e0ab98698ef0a37a23e8736a98a7b1f19d151c31 Mon Sep 17 00:00:00 2001 From: Sean Fahey Date: Wed, 28 Dec 2016 09:19:58 -0500 Subject: [PATCH 22/76] created new documentation for smlogin --- DESCRIPTION | 20 ++++++++++++++++---- NAMESPACE | 30 +----------------------------- R/smlogin.r | 15 +++++++++++++++ man/sm_login.Rd | 29 ----------------------------- man/smlogin.Rd | 32 ++++++++++++++++++++++++++++++++ 5 files changed, 64 insertions(+), 62 deletions(-) delete mode 100644 man/sm_login.Rd create mode 100644 man/smlogin.Rd diff --git a/DESCRIPTION b/DESCRIPTION index 63643dc..7c5b887 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,17 +1,29 @@ Package: Rmonkey -Version: 0.3.3 -Date: 2016-03-20 +Version: 0.4 +Date: 2016-12-28 Title: A Survey Monkey R Client Authors@R: c(person("Thomas J.", "Leeper", role = c("aut", "cre"), email = "thosjleeper@gmail.com"), + person("Sean", "Fahey", role = "ctb", + email = 'seanmfahey@yahoo.com), person("Kevin", "Little", role = "ctb", email = "klittle@iecodesign.com"), person("David", "Robinson", role = "ctb", email = "drobinson@stackoverflow.com"), person("Stephan", "Renatus", role = "ctb")) Maintainer: Thomas J. Leeper -Imports: stats, utils, httr, jsonlite, curl, plyr -Description: Programmatic access to the Survey Monkey API , which currently provides extensive functionality for monitoring surveys and retrieving survey results and some functionality for creating new surveys and data collectors. +Imports: + stats, + utils, + httr, + jsonlite, + curl, + plyr +Description: Programmatic access to the Survey Monkey API , which currently provides extensive functionality + for monitoring surveys and retrieving survey results and some functionality for + creating new surveys and data collectors. License: GPL-2 URL: https://github.com/cloudyr/Rmonkey BugReports: https://github.com/cloudyr/Rmonkey/issues +RoxygenNote: 5.0.1 diff --git a/NAMESPACE b/NAMESPACE index dcf5e4b..6ae9268 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,30 +1,2 @@ -export('smlogin') -export('userdetails') -export('surveylist') -export('surveydetails') -export('surveyquestions') -export('surveypreview') -export('collectors') -export('createcollector') -export('responsecounts') -export('respondentlist') -export('getresponses') -export('getallresponses') -export('templates') -export('createsurvey') +# Generated by roxygen2: do not edit by hand -S3method(print, 'sm_survey') -S3method(print, 'sm_collector') -S3method(print, 'sm_respondent') -S3method(print, 'sm_response') -S3method(print, 'sm_template') - -S3method(as.data.frame, 'sm_response') -S3method(as.data.frame, 'sm_response_list') - -importFrom('stats', 'setNames') -importFrom('utils', 'head', 'browseURL') -importFrom('plyr', 'rbind.fill') -importFrom('curl', 'curl_escape') -import('httr') -import('jsonlite') diff --git a/R/smlogin.r b/R/smlogin.r index 005ff90..acea623 100644 --- a/R/smlogin.r +++ b/R/smlogin.r @@ -1,3 +1,18 @@ +#' smlogin +#' +#' obtains a long lasting oauth token for API access. +#' +#' This function takes as input a SurveyMonkey API account client ID and +#' secret code and conducts the oauth2 authentication process to return +#' an oauth token. The client_id and secret values can be obtained from the settings +#' section of the appropriate SurveyMonkey apps page https://developer.surveymonkey.com/apps/ +#' +#' @param client_id Your SurveyMonkey App client_id. By default, retrieved from \code{getOption('sm_client_id')}. +#' @param secret Your API secret key. By default, retrieved from \code{getOption('sm_secret')}. +#' @param redirect_uri Default value is \samp{http://localhost:1410}. No other value is allowed. This must be the redirect URL registered for your application in your Survey Monkey developer account. +#' @param response_type Default value is \dQuote{code}. No other values are allowed. +#' @return oauth_token + smlogin <- function(client_id = getOption('sm_client_id'), secret = getOption('sm_secret'), redirect_uri = 'http://localhost:1410', diff --git a/man/sm_login.Rd b/man/sm_login.Rd deleted file mode 100644 index 5d65851..0000000 --- a/man/sm_login.Rd +++ /dev/null @@ -1,29 +0,0 @@ -\name{smlogin} -\alias{smlogin} -\title{OAuth Login} -\description{Login into Survey Monkey to generate an OAuth 2.0 token} -\usage{ -smlogin(client_id = getOption('sm_client_id'), - api_key = getOption('sm_api_key'), - secret = getOption('sm_secret'), - redirect_uri = 'http://localhost:1410', - response_type='code') -} -\arguments{ -\item{client_id}{Your Mashery developer account username. By default, retrieved from \code{getOption('sm_client_id')}.} -\item{api_key}{Your API key. By default, retrieved from \code{getOption('sm_api_key')}.} -\item{secret}{Your API secret key. By default, retrieved from \code{getOption('sm_secret')}.} -\item{redirect_uri}{Default value is \samp{http://localhost:1410}. No other value is allowed. This must be the redirect URL registered for your application in your Survey Monkey developer account.} -\item{response_type}{Default value is \dQuote{code}. No other values are allowed.} -\item{...}{Other arguments passed to \code{\link[httr]{POST}}.} -} -\details{Initiate an interactive OAuth 2.0 authentication process by logging into Survey Monkey via a web browser.} -\value{An OAuth 2.0 token object as returned by \code{oauth2.0_token}.} -%\references{} -\author{Thomas J. Leeper} -%\note{} -%\seealso{} -\examples{ -\dontrun{smlogin()} -} -%\keyword{} diff --git a/man/smlogin.Rd b/man/smlogin.Rd new file mode 100644 index 0000000..45702f8 --- /dev/null +++ b/man/smlogin.Rd @@ -0,0 +1,32 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/smlogin.r +\name{smlogin} +\alias{smlogin} +\title{smlogin} +\usage{ +smlogin(client_id = getOption("sm_client_id"), + secret = getOption("sm_secret"), redirect_uri = "http://localhost:1410", + response_type = "code") +} +\arguments{ +\item{client_id}{Your SurveyMonkey App client_id. By default, retrieved from \code{getOption('sm_client_id')}.} + +\item{secret}{Your API secret key. By default, retrieved from \code{getOption('sm_secret')}.} + +\item{redirect_uri}{Default value is \samp{http://localhost:1410}. No other value is allowed. This must be the redirect URL registered for your application in your Survey Monkey developer account.} + +\item{response_type}{Default value is \dQuote{code}. No other values are allowed.} +} +\value{ +oauth_token +} +\description{ +obtains a long lasting oauth token for API access. +} +\details{ +This function takes as input a SurveyMonkey API account client ID and +secret code and conducts the oauth2 authentication process to return +an oauth token. The client_id and secret values can be obtained from the settings +section of the appropriate SurveyMonkey apps page https://developer.surveymonkey.com/apps/ +} + From 6521f7543087c6f4dd3f8f68cee43e8419095637 Mon Sep 17 00:00:00 2001 From: Sean Fahey Date: Wed, 28 Dec 2016 09:25:46 -0500 Subject: [PATCH 23/76] fixed missing quote --- DESCRIPTION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index 7c5b887..014c8e3 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -5,7 +5,7 @@ Title: A Survey Monkey R Client Authors@R: c(person("Thomas J.", "Leeper", role = c("aut", "cre"), email = "thosjleeper@gmail.com"), person("Sean", "Fahey", role = "ctb", - email = 'seanmfahey@yahoo.com), + email = "seanmfahey@yahoo.com"), person("Kevin", "Little", role = "ctb", email = "klittle@iecodesign.com"), person("David", "Robinson", role = "ctb", From ed2f6d0f1c81c06f8225565bb7bc28c12181d697 Mon Sep 17 00:00:00 2001 From: Sean Fahey Date: Wed, 28 Dec 2016 17:23:43 -0500 Subject: [PATCH 24/76] fixed missing quote --- DESCRIPTION | 1 + 1 file changed, 1 insertion(+) diff --git a/DESCRIPTION b/DESCRIPTION index 014c8e3..69516ef 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -27,3 +27,4 @@ License: GPL-2 URL: https://github.com/cloudyr/Rmonkey BugReports: https://github.com/cloudyr/Rmonkey/issues RoxygenNote: 5.0.1 + From 2ce22152d1a243ecddffd00bb8ec4e5461aae590 Mon Sep 17 00:00:00 2001 From: Sean Fahey Date: Wed, 28 Dec 2016 17:41:52 -0500 Subject: [PATCH 25/76] added selected API parameters --- R/getresponses.r | 39 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/R/getresponses.r b/R/getresponses.r index 98e97cd..b16cef9 100644 --- a/R/getresponses.r +++ b/R/getresponses.r @@ -2,6 +2,14 @@ getresponses <- function( survey, collector = NULL, bulk = FALSE, + page = NULL, + per_page = NULL, + start_created_at = NULL, + end_created_at = NULL, + start_modified_at = NULL, + end_modified_at = NULL, + sort_order = 'ASC', + sort_by = 'date_modified', oauth_token = getOption('sm_oauth_token'), ... ){ @@ -28,9 +36,36 @@ getresponses <- function( } else { stop("Must specify 'oauth_token'") } - h <- add_headers(Authorization=token, + if (inherits(start_created_at, "POSIXct") | inherits(start_created_at, "Date")) { + start_created_at <- format(start_created_at, "%Y-%m-%d") + } + if (inherits(end_created_at, "POSIXct") | inherits(end_created_at, "Date")) { + end_created_at <- format(end_created_at, "%Y-%m-%d %H:%M:%S", tz = "UTC") + } + if (inherits(start_modified_at, "POSIXct") | inherits(start_modified_at, "Date")) { + start_modified_at <- format(start_modified_at, "%Y-%m-%d %H:%M:%S", tz = "UTC") + } + if (inherits(end_modified_at, "POSIXct") | inherits(end_modified_at, "Date")) { + end_modified_at <- format(end_modified_at, "%Y-%m-%d %H:%M:%S", tz = "UTC") + } + # need to add error checking for status + b <- list(page = page, + per_page = per_page, + start_created_at = start_created_at, + end_created_at = end_created_at, + start_modified_at = start_modified_at, + end_modified_at = end_modified_at, + sort_order = sort_order, + sort_by = sort_by) + nulls <- sapply(b, is.null) + if (all(nulls)) { + b <- '{}' + } else { + b <- toJSON(b[!nulls], auto_unbox = TRUE) + } + h <- add_headers(Authorization=token, 'Content-Type'='application/json') - out <- GET(u, config = h, ...) + out <- GET(u, config = h, ..., body = b) stop_for_status(out) content <- parsed_content(out) if (!is.null(content$data)) { From 332d160ddb354ff1585bbc4b3ed7b2ba9932b764 Mon Sep 17 00:00:00 2001 From: Sean Fahey Date: Wed, 28 Dec 2016 18:40:23 -0500 Subject: [PATCH 26/76] updated api references for qtype and varnames variables --- R/asdataframe.R | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/R/asdataframe.R b/R/asdataframe.R index c219488..4522f80 100644 --- a/R/asdataframe.R +++ b/R/asdataframe.R @@ -16,9 +16,9 @@ as.data.frame.sm_response <- function(x, row.names, optional, details = NULL, st questions <- do.call('c', lapply(details$pages, function(i) i[['questions']])) # `type` contains info about each question type qtypes <- sapply(questions, function(i) { - fam <- i$type$family + fam <- i$family if (fam == "matrix") { - setNames(paste0(fam, "_", i$type$subtype), i$question_id) + setNames(paste0(fam, "_", i$subtype), i$id) } else { setNames(fam, i$question_id) } @@ -26,7 +26,7 @@ as.data.frame.sm_response <- function(x, row.names, optional, details = NULL, st # set variable names varnames <- sapply(questions, function(i) { # `heading` is the display text - setNames(i$heading, i$question_id) + setNames(i$heading, i$id) }) # extract all answers from the `answers` elements of each subelement of `question` From 97d9da37fbd9a80d759e9caf7787bfc9e01a948c Mon Sep 17 00:00:00 2001 From: Sean Fahey Date: Wed, 28 Dec 2016 23:24:52 -0500 Subject: [PATCH 27/76] changed format of content call --- R/surveydetails.r | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/surveydetails.r b/R/surveydetails.r index ccac3e6..899c5ac 100644 --- a/R/surveydetails.r +++ b/R/surveydetails.r @@ -20,7 +20,7 @@ surveydetails <- function( 'Content-Type'='application/json') out <- GET(u, config = h, ...) stop_for_status(out) - content <- parsed_content(out) + content <- content(out, as = 'parsed') # if(content$status != 0) { # warning("An error occurred: ",content$errmsg) # return(content) From 70a6a1265bec8d26bb6cf68d67b75d0cca6538de Mon Sep 17 00:00:00 2001 From: Sean Fahey Date: Wed, 28 Dec 2016 23:26:02 -0500 Subject: [PATCH 28/76] changed format of content call --- R/surveylist.r | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/surveylist.r b/R/surveylist.r index 557928a..c0751a4 100644 --- a/R/surveylist.r +++ b/R/surveylist.r @@ -33,7 +33,7 @@ surveylist <- function( 'Content-Type'='application/json') out <- GET(u, config = h, ..., body = b) stop_for_status(out) - content <- parsed_content(out) + content <- content(out, as = 'parsed') # if(content$status != 0){ # warning("An error occurred: ",content$errmsg) # return(content) From 2c590d5e29f7eaf6ec9636449bfda81e5c12c726 Mon Sep 17 00:00:00 2001 From: Sean Fahey Date: Wed, 28 Dec 2016 23:27:54 -0500 Subject: [PATCH 29/76] changed format of content call --- R/getresponses.r | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/getresponses.r b/R/getresponses.r index b16cef9..79027c1 100644 --- a/R/getresponses.r +++ b/R/getresponses.r @@ -67,7 +67,7 @@ getresponses <- function( 'Content-Type'='application/json') out <- GET(u, config = h, ..., body = b) stop_for_status(out) - content <- parsed_content(out) + content <- content(out, as = 'parsed') if (!is.null(content$data)) { lapply(content$data, `class<-`, "sm_response") } From cb8159b930d394d1bfcbbcaff7b36b846e7c18d1 Mon Sep 17 00:00:00 2001 From: Sean Fahey Date: Thu, 29 Dec 2016 00:15:15 -0500 Subject: [PATCH 30/76] added jsonlite --- RMonkey Demo.R | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/RMonkey Demo.R b/RMonkey Demo.R index 5dc6e49..c37789a 100644 --- a/RMonkey Demo.R +++ b/RMonkey Demo.R @@ -10,6 +10,7 @@ # load needed libraries library(curl) library(httr) +library(jsonlite) # Load the latest Rmonkey library from github if(!require("devtools")) { @@ -56,12 +57,16 @@ str(sd1.q) # Show just the questions for a survey sl1.q <- surveyquestions(sl[[1]]) +sl1.q # Open browser to a web preview of the survey surveypreview(sl[[1]]) # Show the list of response ids to a survey sl1.r <- getresponses(sl[[1]]) +sl1.r$data # Show the expanded list of responses including answers to all questions sl1.rd <- getresponses(sl[[1]], bulk = TRUE) + + From f0ffcda25d5b95ae0e34c105765ff8a398d070e3 Mon Sep 17 00:00:00 2001 From: Sean Fahey Date: Sat, 31 Dec 2016 08:23:28 -0500 Subject: [PATCH 31/76] add description of SurveyMonkey API response JSON and commented out for now the getallresponses function --- R/getresponses.r | 95 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 72 insertions(+), 23 deletions(-) diff --git a/R/getresponses.r b/R/getresponses.r index 79027c1..a8c2781 100644 --- a/R/getresponses.r +++ b/R/getresponses.r @@ -1,3 +1,52 @@ +# getresponses.r +# +# This function returns details on SurveyMonkey responses +# +# get a set of bulk responses (this will get 50 responses with the following structure: +# $per_page : int = total number of responses per page +# $total : int = number of survey responses +# $data : list = list with data for each survey response +# $data[[x]] : list = individual survey response +# $total_time : int = time spent on the survey +# $href : chr = api url for survey response +# $custom_variables : list = custom variables for respondents +# $ip_address : chr = IP address for respondent +# $id : chr = id of survey response +# $logic_path : list +# $date_modified : chr = date survey response last modified +# $response_status : chr = status of response {completed, partial, etc...} +# $custom_value : chr = ? +# $analyze_url : chr = web browsable url to view responses +# $pages : list = list with data for questions and answers on each survey page +# $id : chr = id +# $ questions : list +# $ id : chr = id +# $ answers : list +# $ choice_id : chr = id of answer choice +# $page_path : list = ? +# $recipient_id : chr = id of survey recipient +# $collector_id : chr = id of survey collector +# $date_created : chr = date the survey response was started +# $survey_id : chr = id of the survey +# $collection_mode : chr = ? +# $edit_url : chr = web browsable url to modify responses +# $metadata : list = list with additional information about respondent +# $contact : list +# $contact$first_name : list +# $contact$first_name$type : chr = type for first_name$value variable +# $contact$first_name$value : chr = respondent first name +# $contact$last_name : list +# $contact$last_name$type : chr = type for last_name$value variable +# $contact$lasy_name$value : chr = respondent last name +# $contact$email : list +# $contact$email$type : chr = type for email variable +# $contact$email$value : chr = respondent email address +# $page : int = page of responses +# $links : list = urls for the previous ($last), current ($self) and next ($next) response pages +# ) + + + getresponses <- function( survey, collector = NULL, @@ -82,26 +131,26 @@ print.sm_response <- function(x, ...){ } -getallresponses <- function( - survey, - collector = NULL, - oauth_token = getOption('sm_oauth_token'), - wait = 0, - ... -) { - r <- respondentlist(survey, api_key = api_key, oauth_token = oauth_token, ...) - Sys.sleep(wait) - respondents <- unname(sapply(r, `[`, "respondent_id")) - Sys.sleep(wait) - n <- ceiling(length(respondents)/100) - w <- split(1:length(respondents), rep(1:n, each = 100)[1:length(respondents)]) - out <- list() - for (i in seq_len(n)) { - out <- c(out, getresponses(unlist(respondents[w[[i]]]), survey = survey, - api_key = api_key, oauth_token = oauth_token, ...)) - Sys.sleep(wait) - } - class(out) <- 'sm_response_list' - d <- surveydetails(survey, api_key = api_key, oauth_token = oauth_token, ...) - as.data.frame(out, details = d) -} +# getallresponses <- function( +# survey, +# collector = NULL, +# oauth_token = getOption('sm_oauth_token'), +# wait = 0, +# ... +# ) { +# r <- respondentlist(survey, api_key = api_key, oauth_token = oauth_token, ...) +# Sys.sleep(wait) +# respondents <- unname(sapply(r, `[`, "respondent_id")) +# Sys.sleep(wait) +# n <- ceiling(length(respondents)/100) +# w <- split(1:length(respondents), rep(1:n, each = 100)[1:length(respondents)]) +# out <- list() +# for (i in seq_len(n)) { +# out <- c(out, getresponses(unlist(respondents[w[[i]]]), survey = survey, +# api_key = api_key, oauth_token = oauth_token, ...)) +# Sys.sleep(wait) +# } +# class(out) <- 'sm_response_list' +# d <- surveydetails(survey, api_key = api_key, oauth_token = oauth_token, ...) +# as.data.frame(out, details = d) +# } From f1a265a44a85afc2749c47b83b962ca4eed08e16 Mon Sep 17 00:00:00 2001 From: Sean Fahey Date: Sat, 31 Dec 2016 08:45:24 -0500 Subject: [PATCH 32/76] added comment detailing the list structure form the JSON response --- R/surveydetails.r | 56 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/R/surveydetails.r b/R/surveydetails.r index 899c5ac..0d8d4dd 100644 --- a/R/surveydetails.r +++ b/R/surveydetails.r @@ -1,3 +1,59 @@ +# surveydetails +# +# This function returns details about a SurveyMonkey survey in the list structure based on the +# JSON response format +# +# $response_count : int = total number of responses +# $pages_count : int = number of pages in the survey +# $buttons_text : list of chr = display text for buttons +# $custom_variables : named list = ? +# $nickname : chr = short name for survey +# $id : chr = SurveyMonkey id for the survey +# $question_count : int = total number of questions on the survey +# $category : chr = broad category for survey +# $preview : chr = web browsable url to preview the survey +# $is_owner : logical = is user owner of the survey(?) +# $language : chr = langauge the survey is written in +# $date_modified : chr = date/time when survey was last modified +# $title : chr = survey title +# $analyze_url : chr = web browsable url to analyze responses +# $pages : list +# $ href : chr = api accessible weblink for data on this page +# $ description : chr = text displayed at top of page +# $ questions : list = length is the number of questions on the page +# $ display_options : list +# $ show_display_number : logical +# $ sorting : +# $ family : chr = general style of question +# $ subtype : chr = detailed style of question +# $ required : +# $ text: chr = text to display if not answered(?) +# $ amount : chr = +# $ type : chr = ? +# $ answers : list +# $ choices : list +# $ visible : logical +# $ text : chr = answerchoice text +# $ position : int = answerchoice position +# $ id : chr = answerchoice id +# $ visible : logical +# $ href : api accessible weblink for this question +# $ headings : list +# $ heading : chr = HTML text displayed with question +# $ position : int = display position for question on the page +# $ validation : +# $ id : chr = id for the question +# $ forced_ranking : logical +# $ title : chr +# $ position : int +# $ id : id for page +# $ question_count : int = number of questions on this page +# $summary_url : chr = web browsable url for survey summary +# $href : chr = api accessible web link for survey data +# $date_created : chr = date survey originally created +# $collect_url : chr = web browsable url to collect responses +# $edit_url : chr = web browsable url to edit the survey + surveydetails <- function( survey, question_details = FALSE, From ef3fec01311cc132e9aa57f1f95deecbba3cd916 Mon Sep 17 00:00:00 2001 From: Sean Fahey Date: Sat, 31 Dec 2016 09:27:24 -0500 Subject: [PATCH 33/76] updated comments about json --- R/surveydetails.r | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/R/surveydetails.r b/R/surveydetails.r index 0d8d4dd..aee30b6 100644 --- a/R/surveydetails.r +++ b/R/surveydetails.r @@ -24,14 +24,24 @@ # $ display_options : list # $ show_display_number : logical # $ sorting : -# $ family : chr = general style of question -# $ subtype : chr = detailed style of question +# $ type : (e..g, random) +# $ ignore_last +# $ family : chr = general style of question (e.g., matrix, single-choice) +# $ subtype : chr = detailed style of question (e.g., single) # $ required : # $ text: chr = text to display if not answered(?) # $ amount : chr = # $ type : chr = ? # $ answers : list +# $ rows : list = used in matrix questions to store row headings +# $ visible +# $ text +# $ position +# $ id # $ choices : list +# $ description : chr = (used in matrix questions?) +# $ weight : int = (used in matrix questions?) +# $ is_na : logical = (used in matrix questions?) # $ visible : logical # $ text : chr = answerchoice text # $ position : int = answerchoice position From 03ca44f4748414bd2aa31a09e9b1bee0737e738c Mon Sep 17 00:00:00 2001 From: Sean Fahey Date: Sat, 31 Dec 2016 12:36:25 -0500 Subject: [PATCH 34/76] changed question_id, and answer_id references to id (per API v3). changed answers references to answers$choices and removed now unneeded logic to parse matrix and menu types. modified nanswers logic to use sapply vs a loop --- R/asdataframe.R | 82 ++++++++++++++++++++++++++++++------------------- 1 file changed, 50 insertions(+), 32 deletions(-) diff --git a/R/asdataframe.R b/R/asdataframe.R index 4522f80..9380aaf 100644 --- a/R/asdataframe.R +++ b/R/asdataframe.R @@ -12,65 +12,83 @@ as.data.frame.sm_response <- function(x, row.names, optional, details = NULL, st } else { stop("'details' is missing and cannot be determined automatically") } + + survey<-x + # These first functions unpack the surveydetails() with questions + details <- surveydetails(survey, question_details = TRUE) + + # extract all questions from the `question` element in all pages + # note: this assumes that all data records are identical and so the first can be used as a model questions <- do.call('c', lapply(details$pages, function(i) i[['questions']])) + # `type` contains info about each question type qtypes <- sapply(questions, function(i) { fam <- i$family if (fam == "matrix") { setNames(paste0(fam, "_", i$subtype), i$id) } else { - setNames(fam, i$question_id) + setNames(fam, i$id) } }) + # set variable names varnames <- sapply(questions, function(i) { # `heading` is the display text setNames(i$heading, i$id) }) + # alternate method which reuses an existing function and cleans HTML tags + varnames2 <- surveyquestions(survey) + # extract all answers from the `answers` elements of each subelement of `question` # `answer_id` is what is recorded in `sm_response` # `text` is the display seen by respondents # `answers` is empty for "open_ended" type questions answerchoices <- sapply(questions, function(i) { out <- list() - for (k in seq_along(i$answers)) { - if (i$type$family == "matrix") { - if (i$type$subtype == "rating") { - if (i$answers[[k]]$type == "other") { - out[[k]] <- setNames(i$answers[[k]]$text, i$answers[[k]]$answer_id) - } else { - # exclude "col" values from matrix questions - if (i$answers[[k]]$type == "row") { - out[[k]] <- setNames(i$answers[[k]]$text, i$answers[[k]]$answer_id) - } - } - out[[k]] <- setNames(i$answers[[k]]$text, i$answers[[k]]$answer_id) - } else if (i$type$subtype == "menu") { - if (i$answers[[k]]$type == "col") { - tmp_txt <- unlist(lapply(i$answers[[k]]$items, `[`, "text")) - tmp_ans <- unlist(lapply(i$answers[[k]]$items, `[`, "answer_id")) - out[[k]] <- setNames(tmp_txt, tmp_ans) - rm(tmp_txt) - rm(tmp_ans) - } - } - } else { - out[[k]] <- setNames(i$answers[[k]]$text, i$answers[[k]]$answer_id) - } + for (k in seq_along(i$answers$choices)) { + # if (i$family == "matrix") { + # if (i$subtype == "rating") { + # if (i$answers[[k]]$type == "other") { + # out[[k]] <- setNames(i$answers[[k]]$text, i$answers[[k]]$id) + # } else { + # # exclude "col" values from matrix questions + # if (i$answers[[k]]$type == "row") { + # out[[k]] <- setNames(i$answers[[k]]$text, i$answers[[k]]$id) + # } + # } + # out[[k]] <- setNames(i$answers[[k]]$text, i$answers[[k]]$id) + # } else if (i$type$subtype == "menu") { + # if (i$answers[[k]]$type == "col") { + # tmp_txt <- unlist(lapply(i$answers[[k]]$items, `[`, "text")) + # tmp_ans <- unlist(lapply(i$answers[[k]]$items, `[`, "id")) + # out[[k]] <- setNames(tmp_txt, tmp_ans) + # rm(tmp_txt) + # rm(tmp_ans) + # } + # } + # } else { + out[[k]] <- setNames(i$answers$choices[[k]]$text, i$answers$choices[[k]]$id) + # } } return(unlist(out)) }) answerchoices <- unlist(do.call(c, answerchoices)) + # extract question_ids - question_ids <- unlist(sapply(x$questions, `[`, 'question_id')) - # count number of answers per question - nanswers <- integer() - for (i in seq_along(x$questions)) { - nanswers[i] <- length(x$questions[[i]]$answers) - } - rm(i) + question_ids <- unlist(sapply(questions, `[`, 'id')) + + # # count number of answers per question + # nanswers <- integer() + # for (i in seq_along(x$questions)) { + # nanswers[i] <- length(x$questions[[i]]$answers) + # } + # rm(i) + + # count the number of answer choices per question + nanswers <- sapply(questions, function(x) {length(x$answers$choices)}) + # create vector of answer names by repeating question names `nanswers` times each answer_names <- rep(question_ids, nanswers) From 00523b03c791a1254c6e7fddcbf8ea06221d0c35 Mon Sep 17 00:00:00 2001 From: Sean Fahey Date: Sun, 1 Jan 2017 14:42:04 -0500 Subject: [PATCH 35/76] initial commit - function to unpack json nested list for survey questions and possible responses into a data frame --- R/surveyquestiondf.R | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 R/surveyquestiondf.R diff --git a/R/surveyquestiondf.R b/R/surveyquestiondf.R new file mode 100644 index 0000000..34025c4 --- /dev/null +++ b/R/surveyquestiondf.R @@ -0,0 +1,44 @@ +# @ surveyquestiondf.r +# +# This program creates a data frame from the survey questions and answers +surveyquestiondf <- function(survey) { + df <- data.frame() + sd <- surveydetails(survey, question_details = TRUE) + questions <- do.call('c', lapply(details$pages, function(i) i[['questions']])) + for (i in questions) { + id <- i$id + family <- i$family + subtype <- i$subtype + heading <- i$heading + if (!is.null(i$answer$rows)) { + for (j in i$answer$rows) { + row_text <- j$text + newrow <- + data.frame( + id, + family, + subtype, + heading, + row_text, + stringsAsFactors = FALSE, + check.rows = FALSE + ) + df <- rbind(df, newrow) + } + } else { + row_text <- '' + newrow <- + data.frame( + id, + family, + subtype, + heading, + row_text, + stringsAsFactors = FALSE, + check.rows = FALSE + ) + df <- rbind(df, newrow) + } + } + return(df) +} \ No newline at end of file From 1807154eeb4433c7da68c93f41c3d3a159d7b3c5 Mon Sep 17 00:00:00 2001 From: Sean Fahey Date: Sun, 1 Jan 2017 18:49:51 -0500 Subject: [PATCH 36/76] added comments and fixed row id and text function --- R/surveyquestiondf.R | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/R/surveyquestiondf.R b/R/surveyquestiondf.R index 34025c4..0c9ba46 100644 --- a/R/surveyquestiondf.R +++ b/R/surveyquestiondf.R @@ -5,6 +5,25 @@ surveyquestiondf <- function(survey) { df <- data.frame() sd <- surveydetails(survey, question_details = TRUE) questions <- do.call('c', lapply(details$pages, function(i) i[['questions']])) + + + + # answerrows <- do.call('c', lapply(questions, function(i) i[['answers']][['rows']])) + # answerchoices <- answerchoices <- do.call('c', lapply(questions, function(i) i[['answers']][['choices']])) + + # q_df <- do.call(rbind, lapply(questions, function(x) data.frame(question_id = x$id, question_type = x$family, question_subtype = x$subtype, question_text = x$heading, stringsAsFactors = FALSE))) + # ac_df <- do.call(rbind, lapply(answerchoices, function(x) data.frame(answerchoice_text = x$text, answerchoice_id = x$id, stringsAsFactors = FALSE))) + # ar_df <- do.call(rbind, lapply(answerrows, function(x) data.frame(subquestion_text = x$text, subquestion_id = x$id, stringsAsFactors = FALSE))) + + # these work but don't preserve the question ID in the ar and ac frames preventing joining + + # experiment to extract row data and then apply question ids as names + # q_id <- do.call('c', lapply(questions, function(i) i[['id']])) + # ar <- lapply(questions, function(i) i[['answers']][['rows']]) + # write the question_id into the answer row list prior to unpacking + # for (i in 1:length( ar) ) {if (!is.null(ar[[i]])) {ar[[i]]$rows$question_id <- questions[[i]]$id}} + # setNames(ar, q_id) + for (i in questions) { id <- i$id family <- i$family @@ -12,10 +31,12 @@ surveyquestiondf <- function(survey) { heading <- i$heading if (!is.null(i$answer$rows)) { for (j in i$answer$rows) { + row_id <- j$id row_text <- j$text newrow <- data.frame( id, + row_id, family, subtype, heading, @@ -26,10 +47,11 @@ surveyquestiondf <- function(survey) { df <- rbind(df, newrow) } } else { - row_text <- '' - newrow <- - data.frame( + row_id <- NA + row_text <- NA + newrow <- data.frame( id, + row_id, family, subtype, heading, From e2591ccb43191ebc87ac3861d068deaf5da67fe4 Mon Sep 17 00:00:00 2001 From: Sean Fahey Date: Sun, 1 Jan 2017 19:34:59 -0500 Subject: [PATCH 37/76] modified structure to include a repeat loop to simplify code --- R/surveyquestiondf.R | 37 ++++++++++++++----------------------- 1 file changed, 14 insertions(+), 23 deletions(-) diff --git a/R/surveyquestiondf.R b/R/surveyquestiondf.R index 0c9ba46..ec4c2ef 100644 --- a/R/surveyquestiondf.R +++ b/R/surveyquestiondf.R @@ -6,8 +6,6 @@ surveyquestiondf <- function(survey) { sd <- surveydetails(survey, question_details = TRUE) questions <- do.call('c', lapply(details$pages, function(i) i[['questions']])) - - # answerrows <- do.call('c', lapply(questions, function(i) i[['answers']][['rows']])) # answerchoices <- answerchoices <- do.call('c', lapply(questions, function(i) i[['answers']][['choices']])) @@ -29,27 +27,19 @@ surveyquestiondf <- function(survey) { family <- i$family subtype <- i$subtype heading <- i$heading - if (!is.null(i$answer$rows)) { - for (j in i$answer$rows) { - row_id <- j$id - row_text <- j$text - newrow <- - data.frame( - id, - row_id, - family, - subtype, - heading, - row_text, - stringsAsFactors = FALSE, - check.rows = FALSE - ) - df <- rbind(df, newrow) + j <- 0 + # use a repeat loop to account for cases where there are no answer rows + repeat { + j <- j + 1 # increment the index first for array indexing + if (is.null(i$answers$rows)) { + row_id <- NA + row_text <- NA + } else { + row_id <- i$answers$rows[[j]]$id + row_text <- i$answers$rows[[j]]$text } - } else { - row_id <- NA - row_text <- NA - newrow <- data.frame( + newrow <- + data.frame( id, row_id, family, @@ -60,7 +50,8 @@ surveyquestiondf <- function(survey) { check.rows = FALSE ) df <- rbind(df, newrow) + if (j >= length(i$answers$rows)) {break} } } return(df) -} \ No newline at end of file +} From 9bac83a4da1184433f36cdf78b0eb84eb5a123cf Mon Sep 17 00:00:00 2001 From: Sean Fahey Date: Sun, 1 Jan 2017 19:57:40 -0500 Subject: [PATCH 38/76] data frame variables renamed. Future work comments added --- R/surveyquestiondf.R | 130 +++++++++++++++++++++++++++++-------------- 1 file changed, 88 insertions(+), 42 deletions(-) diff --git a/R/surveyquestiondf.R b/R/surveyquestiondf.R index ec4c2ef..3501156 100644 --- a/R/surveyquestiondf.R +++ b/R/surveyquestiondf.R @@ -4,54 +4,100 @@ surveyquestiondf <- function(survey) { df <- data.frame() sd <- surveydetails(survey, question_details = TRUE) - questions <- do.call('c', lapply(details$pages, function(i) i[['questions']])) - - # answerrows <- do.call('c', lapply(questions, function(i) i[['answers']][['rows']])) - # answerchoices <- answerchoices <- do.call('c', lapply(questions, function(i) i[['answers']][['choices']])) - - # q_df <- do.call(rbind, lapply(questions, function(x) data.frame(question_id = x$id, question_type = x$family, question_subtype = x$subtype, question_text = x$heading, stringsAsFactors = FALSE))) - # ac_df <- do.call(rbind, lapply(answerchoices, function(x) data.frame(answerchoice_text = x$text, answerchoice_id = x$id, stringsAsFactors = FALSE))) - # ar_df <- do.call(rbind, lapply(answerrows, function(x) data.frame(subquestion_text = x$text, subquestion_id = x$id, stringsAsFactors = FALSE))) - - # these work but don't preserve the question ID in the ar and ac frames preventing joining - - # experiment to extract row data and then apply question ids as names - # q_id <- do.call('c', lapply(questions, function(i) i[['id']])) - # ar <- lapply(questions, function(i) i[['answers']][['rows']]) - # write the question_id into the answer row list prior to unpacking - # for (i in 1:length( ar) ) {if (!is.null(ar[[i]])) {ar[[i]]$rows$question_id <- questions[[i]]$id}} - # setNames(ar, q_id) - + survey_id <- survey$id + questions <- + do.call('c', lapply(details$pages, function(i) + i[['questions']])) for (i in questions) { - id <- i$id - family <- i$family - subtype <- i$subtype - heading <- i$heading + question_id <- i$id + question_type <- i$family + question_subtype <- i$subtype + question_text <- i$heading j <- 0 - # use a repeat loop to account for cases where there are no answer rows - repeat { - j <- j + 1 # increment the index first for array indexing + # use a repeat loop to account for cases where there are no answer rows + repeat { + j <- j + 1 # increment counter first for array indexing if (is.null(i$answers$rows)) { - row_id <- NA - row_text <- NA + subquestion_id <- NA + subquestion_text <- NA } else { - row_id <- i$answers$rows[[j]]$id - row_text <- i$answers$rows[[j]]$text + subquestion_id <- i$answers$rows[[j]]$id + subquestion_text <- i$answers$rows[[j]]$text + } + k <- 0 + repeat { + k <- k + 1 # increment counter first for array indexing + if (is.null(i$answers$choices)) { + answerchoice_id <- NA + answerchoice_text <- NA + answerchoice_weight <- NA + } else { + answerchoice_id <- i$answers$choices[[k]]$id + answerchoice_text <- i$answers$choices[[k]]$text + if (!is.null(i$answers$choices[[k]]$weight)) { + answerchoice_weight <- + i$answers$choices[[k]]$weight + } else { + answerchoice_weight <- NA + } + } + newrow <- + data.frame( + survey_id, + question_id, + subquestion_id, + answerchoice_id, + question_type, + question_subtype, + question_text, + subquestion_text, + answerchoice_text, + answerchoice_weight, + stringsAsFactors = FALSE, + check.rows = FALSE + ) + df <- rbind(df, newrow) + if (k >= length(i$answers$choices)) { + break + } + } + if (j >= length(i$answers$rows)) { + break } - newrow <- - data.frame( - id, - row_id, - family, - subtype, - heading, - row_text, - stringsAsFactors = FALSE, - check.rows = FALSE - ) - df <- rbind(df, newrow) - if (j >= length(i$answers$rows)) {break} } + } return(df) } + +# Future work +# +# This code works but is inelegant since it uses loops (for and repeat) vs. using vectorized approaches like lapply +# or data table approaches like those in dplyr. To use lapply, I have to solve how to nest the functions +# so I can both manage cases where there are no rows for some answers (e.g., single choice answers) and the +# case where there are multiple rows per answer which require applying the choices to each row. +# To use dplyr, I need to figure out how to build tables that I can join for quesitons, answer rows, and +# answer choices. The trick here, is figuring out how to include the question id as a key in the +# answer row and answer choice tables. Some work to this end is below: + +# One can use the lapply in the inner call here to extract the answers$rows elements but they lack the +# question_id. The index of the lapply array is the question number but once the do.call is applied +# that structure is lost. +# answerrows <- do.call('c', lapply(questions, function(i) i[['answers']][['rows']])) +# answerchoices <- answerchoices <- do.call('c', lapply(questions, function(i) i[['answers']][['choices']])) + +# These functions make data frames from the resulting data. If the question ids were included they could be joined +# with dplyr to offer a more elegant solution +# q_df <- do.call(rbind, lapply(questions, function(x) data.frame(question_id = x$id, question_type = x$family, question_subtype = x$subtype, question_text = x$heading, stringsAsFactors = FALSE))) +# ac_df <- do.call(rbind, lapply(answerchoices, function(x) data.frame(answerchoice_text = x$text, answerchoice_id = x$id, stringsAsFactors = FALSE))) +# ar_df <- do.call(rbind, lapply(answerrows, function(x) data.frame(subquestion_text = x$text, subquestion_id = x$id, stringsAsFactors = FALSE))) + +# these work but don't preserve the question ID in the ar and ac frames preventing joining + +# experiment to extract row data and then apply question ids as names +# q_id <- do.call('c', lapply(questions, function(i) i[['id']])) +# ar <- lapply(questions, function(i) i[['answers']][['rows']]) + +# write the question_id into the answer row list prior to unpacking +# for (i in 1:length( ar) ) {if (!is.null(ar[[i]])) {ar[[i]]$rows$question_id <- questions[[i]]$id}} +# setNames(ar, q_id) From a066046aec1bcbe5a87d63ea425f0b72b1e842b9 Mon Sep 17 00:00:00 2001 From: Sean Fahey Date: Sun, 1 Jan 2017 20:02:08 -0500 Subject: [PATCH 39/76] fixed error in variable name (detail -> sd) --- R/surveyquestiondf.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/surveyquestiondf.R b/R/surveyquestiondf.R index 3501156..3e864f1 100644 --- a/R/surveyquestiondf.R +++ b/R/surveyquestiondf.R @@ -6,7 +6,7 @@ surveyquestiondf <- function(survey) { sd <- surveydetails(survey, question_details = TRUE) survey_id <- survey$id questions <- - do.call('c', lapply(details$pages, function(i) + do.call('c', lapply(sd$pages, function(i) i[['questions']])) for (i in questions) { question_id <- i$id From b1a5843a3f45faa828d5ac6a399e52a7a4dd8fb3 Mon Sep 17 00:00:00 2001 From: Sean Fahey Date: Sun, 1 Jan 2017 20:53:24 -0500 Subject: [PATCH 40/76] fixed issue with HTML text clean up --- R/surveyquestiondf.R | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/R/surveyquestiondf.R b/R/surveyquestiondf.R index 3e864f1..5a8a4f5 100644 --- a/R/surveyquestiondf.R +++ b/R/surveyquestiondf.R @@ -4,7 +4,7 @@ surveyquestiondf <- function(survey) { df <- data.frame() sd <- surveydetails(survey, question_details = TRUE) - survey_id <- survey$id + survey_id <- sd$id questions <- do.call('c', lapply(sd$pages, function(i) i[['questions']])) @@ -12,7 +12,8 @@ surveyquestiondf <- function(survey) { question_id <- i$id question_type <- i$family question_subtype <- i$subtype - question_text <- i$heading + question_text <- gsub("<.*?>", "",unlist(i$heading)) + j <- 0 # use a repeat loop to account for cases where there are no answer rows repeat { From 5d626d6c28dd643483a735ddf0db4ae1db87857e Mon Sep 17 00:00:00 2001 From: Sean Fahey Date: Sun, 1 Jan 2017 21:17:03 -0500 Subject: [PATCH 41/76] fixed GET to allow queries --- R/surveylist.r | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/R/surveylist.r b/R/surveylist.r index c0751a4..f59cca8 100644 --- a/R/surveylist.r +++ b/R/surveylist.r @@ -31,12 +31,9 @@ surveylist <- function( b <- toJSON(b[!nulls], auto_unbox = TRUE) h <- add_headers(Authorization=token, 'Content-Type'='application/json') - out <- GET(u, config = h, ..., body = b) + out <- GET(u, config = h, ..., query = b) stop_for_status(out) content <- content(out, as = 'parsed') - # if(content$status != 0){ - # warning("An error occurred: ",content$errmsg) - # return(content) - # } else lapply(content$data, `class<-`, 'sm_survey') + } \ No newline at end of file From 6e168ef45d668eb61ae84ca1ac662d62fb77f3f8 Mon Sep 17 00:00:00 2001 From: Sean Fahey Date: Sun, 1 Jan 2017 21:46:28 -0500 Subject: [PATCH 42/76] modified function arguments to match v3 api. changed GET to pass query vs. body in list vs. JSON form --- R/surveylist.r | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/R/surveylist.r b/R/surveylist.r index f59cca8..484f5d7 100644 --- a/R/surveylist.r +++ b/R/surveylist.r @@ -1,12 +1,12 @@ surveylist <- function( page = NULL, - page_size = NULL, - start_date = NULL, - end_date = NULL, + per_page = NULL, + sort_by = NULL, + sort_order = NULL, + start_modified_at = NULL, + end_modified_at = NULL, title = NULL, - recipient_email = NULL, - order_asc = NULL, - fields = NULL, + include = NULL, oauth_token = getOption('sm_oauth_token'), ... ){ @@ -16,19 +16,23 @@ surveylist <- function( } else stop("Must specify 'oauth_token'") - if(inherits(start_date, "POSIXct") | inherits(start_date, "Date")) - start_date <- format(start_date, "%Y-%m-%d %H:%M:%S", tz = "UTC") - if(inherits(end_date, "POSIXct") | inherits(end_date, "Date")) - end_date <- format(end_date, "%Y-%m-%d %H:%M:%S", tz = "UTC") - b <- list(page = page, page_size = page_size, - start_date = start_date, end_date = end_date, - title = title, recipient_email = recipient_email, - order_asc = order_asc, fields = as.list(fields)) + if(inherits(start_modified_at, "POSIXct") | inherits(start_modified_at, "Date")) + start_modified_at <- format(start_modified_at, "%Y-%m-%d %H:%M:%S", tz = "UTC") + if(inherits(end_modified_at, "POSIXct") | inherits(end_modified_at, "Date")) + end_modified_at <- format(end_modified_at, "%Y-%m-%d %H:%M:%S", tz = "UTC") + b <- list( page = page, + per_page = per_page, + sort_by = sort_by, + sort_order = sort_order, + start_modified_at = start_modified_at, + end_modified_at = end_modified_at, + title = title, + include = include) nulls <- sapply(b, is.null) if(all(nulls)) - b <- '{}' + b <- NULL else - b <- toJSON(b[!nulls], auto_unbox = TRUE) + b <- b[!nulls] h <- add_headers(Authorization=token, 'Content-Type'='application/json') out <- GET(u, config = h, ..., query = b) From 1428faceea1a64b019a022a5b61a9a317c373c20 Mon Sep 17 00:00:00 2001 From: Sean Fahey Date: Sun, 1 Jan 2017 21:56:06 -0500 Subject: [PATCH 43/76] changed default value for question_details to be TRUE --- R/surveydetails.r | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/R/surveydetails.r b/R/surveydetails.r index aee30b6..ec501fe 100644 --- a/R/surveydetails.r +++ b/R/surveydetails.r @@ -66,7 +66,7 @@ surveydetails <- function( survey, - question_details = FALSE, + question_details = TRUE, oauth_token = getOption('sm_oauth_token'), ... ){ @@ -81,16 +81,12 @@ surveydetails <- function( token <- paste('bearer', oauth_token) } else - stop("Must specify 'oauth_token'") + stop("Must specify 'oauth_token'. Try using smlogin() first.") h <- add_headers(Authorization=token, 'Content-Type'='application/json') out <- GET(u, config = h, ...) stop_for_status(out) content <- content(out, as = 'parsed') - # if(content$status != 0) { - # warning("An error occurred: ",content$errmsg) - # return(content) - # } else structure(content, class = "sm_survey") } @@ -133,3 +129,4 @@ print.sm_survey <- function(x, ...){ cat('Survey Pages:', length(x$pages), '\n') invisible(x) } + From c352fe5c9e55f9db1301fb04758ba77804f70358 Mon Sep 17 00:00:00 2001 From: Sean Fahey Date: Sun, 1 Jan 2017 22:24:55 -0500 Subject: [PATCH 44/76] updated the GET command to use query vs. body --- R/getresponses.r | 38 +++++++------------------------------- 1 file changed, 7 insertions(+), 31 deletions(-) diff --git a/R/getresponses.r b/R/getresponses.r index a8c2781..465b770 100644 --- a/R/getresponses.r +++ b/R/getresponses.r @@ -5,8 +5,7 @@ # get a set of bulk responses (this will get 50 responses with the following structure: # $per_page : int = total number of responses per page # $total : int = number of survey responses -# $data : list = list with data for each survey response -# $data[[x]] : list = individual survey response +# $data[[x]] : list = list with an entry for each individual survey response # $total_time : int = time spent on the survey # $href : chr = api url for survey response # $custom_variables : list = custom variables for respondents @@ -83,10 +82,10 @@ getresponses <- function( if (!is.null(oauth_token)) { token <- paste('bearer', oauth_token) } else { - stop("Must specify 'oauth_token'") + stop("Must specify 'oauth_token', Try using smlogin() first.") } if (inherits(start_created_at, "POSIXct") | inherits(start_created_at, "Date")) { - start_created_at <- format(start_created_at, "%Y-%m-%d") + start_created_at <- format(start_created_at, "%Y-%m-%d %H:%M:%S", tz = "UTC") } if (inherits(end_created_at, "POSIXct") | inherits(end_created_at, "Date")) { end_created_at <- format(end_created_at, "%Y-%m-%d %H:%M:%S", tz = "UTC") @@ -108,19 +107,20 @@ getresponses <- function( sort_by = sort_by) nulls <- sapply(b, is.null) if (all(nulls)) { - b <- '{}' + b <- NULL } else { - b <- toJSON(b[!nulls], auto_unbox = TRUE) + b <- b[!nulls] } h <- add_headers(Authorization=token, 'Content-Type'='application/json') - out <- GET(u, config = h, ..., body = b) + out <- GET(u, config = h, ..., query = b) stop_for_status(out) content <- content(out, as = 'parsed') if (!is.null(content$data)) { lapply(content$data, `class<-`, "sm_response") } structure(content, class = 'sm_response_list') + return(content$data) } print.sm_response <- function(x, ...){ @@ -130,27 +130,3 @@ print.sm_response <- function(x, ...){ invisible(x) } - -# getallresponses <- function( -# survey, -# collector = NULL, -# oauth_token = getOption('sm_oauth_token'), -# wait = 0, -# ... -# ) { -# r <- respondentlist(survey, api_key = api_key, oauth_token = oauth_token, ...) -# Sys.sleep(wait) -# respondents <- unname(sapply(r, `[`, "respondent_id")) -# Sys.sleep(wait) -# n <- ceiling(length(respondents)/100) -# w <- split(1:length(respondents), rep(1:n, each = 100)[1:length(respondents)]) -# out <- list() -# for (i in seq_len(n)) { -# out <- c(out, getresponses(unlist(respondents[w[[i]]]), survey = survey, -# api_key = api_key, oauth_token = oauth_token, ...)) -# Sys.sleep(wait) -# } -# class(out) <- 'sm_response_list' -# d <- surveydetails(survey, api_key = api_key, oauth_token = oauth_token, ...) -# as.data.frame(out, details = d) -# } From 175f6007255e1278ae6bee101578f84ee8129307 Mon Sep 17 00:00:00 2001 From: Sean Fahey Date: Sun, 1 Jan 2017 23:21:17 -0500 Subject: [PATCH 45/76] initial commit of code to create a data frame from survey response data --- R/as.data.frame.surveyresponses.r | 60 +++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 R/as.data.frame.surveyresponses.r diff --git a/R/as.data.frame.surveyresponses.r b/R/as.data.frame.surveyresponses.r new file mode 100644 index 0000000..5e870be --- /dev/null +++ b/R/as.data.frame.surveyresponses.r @@ -0,0 +1,60 @@ +# as.data.frame.surveyresponses +# +# This function extracts data from the survey responses data set and formats it as +# a data frame for analysis + +as.data.frame.surveyresponses <- function(survey) { + df <- data.frame() + sr <- getresponses(survey, bulk = TRUE) + survey_id <- survey$id + + # Iterate through responses + for (h in sr) { + response_id <- h$id + recipient_id <- h$recipient_id + collector_id <- h$collector_id + questions <- + do.call('c', lapply(h$pages, function(x) + x[['questions']])) + for (i in questions) { + question_id <- i$id + j <- 0 + # use a repeat loop to account for cases where there are no answer rows + repeat { + j <- j + 1 # increment counter first for array indexing + if (is.null(i$answers[[j]]$row_id)) { + subquestion_id <- NA + } else { + subquestion_id <- i$answers[[j]]$row_id + } + if (is.null(i$answers[[j]]$choice_id)) { + answerchoice_id <- NA + } else { + answerchoice_id <- i$answers[[j]]$choice_id + } + newrow <- + data.frame( + response_id, + survey_id, + recipient_id, + collector_id, + question_id, + subquestion_id, + answerchoice_id, + stringsAsFactors = FALSE, + check.rows = FALSE + ) + df <- rbind(df, newrow) + if (j >= length(i$answers)) { + break + } + } + } + } + return(df) +} + + # Future work + # + + # do.call(rbind, lapply(i$answers, function(x) data.frame(answerchoice_id = x$choice_id, subquestion_id = x$row_id, stringsAsFactors = FALSE))) \ No newline at end of file From fb59e98146e9a15348c519670d6dd5bdb8f20c61 Mon Sep 17 00:00:00 2001 From: Sean Fahey Date: Sun, 1 Jan 2017 23:33:47 -0500 Subject: [PATCH 46/76] added more functions for survey response data frame and decoding --- RMonkey Demo.R | 39 ++++++++++++++++++++++++++++++--------- 1 file changed, 30 insertions(+), 9 deletions(-) diff --git a/RMonkey Demo.R b/RMonkey Demo.R index c37789a..c943656 100644 --- a/RMonkey Demo.R +++ b/RMonkey Demo.R @@ -28,19 +28,29 @@ library("Rmonkey") # Enter your app API info into R -options(sm_client_id = 'YourMasheryDeveloperUsername') +options(sm_client_id = 'YourClientID') options(sm_secret = 'YourAPISecret') # Get a long lasting oauth token. This function completes the OAuth handshake # and saves a long lasting token on the computer. It needs to be done only once smlogin() +### USER FUNCTIONS + # Lookup userdetails to test API userdetails() +### SURVEY FUNCTIONS + # Return a list of surveys sl <- surveylist() +# Return a specific list of surveys +sl <- surveylist(per_page = 100, sort_by = 'num_responses', sort_order = 'desc') + +# Return surveys that have been modified since a certain date +sl <- surveylist(start_modified_at = '2016-12-25') + # Display the list of surveys # (This shows each survey using the print.sm_survey function which overrides the standard # print function) @@ -48,12 +58,12 @@ sl # Get and display more details for the first survey on the list # (This uses the same print.sm_survey function but has more data to display) -sd1 <- surveydetails(sl[[1]]) -sd1 +sd1.q <- surveydetails(sl[[1]]) +sd1.q -# Get and display survey deatils including the details of the survey questions -sd1.q <- surveydetails(sl[[1]], question_details = TRUE) -str(sd1.q) +# Get and display survey deatils without the details of the survey questions +sd1 <- surveydetails(sl[[1]], question_details = FALSE) +str(sd1) # Show just the questions for a survey sl1.q <- surveyquestions(sl[[1]]) @@ -62,11 +72,22 @@ sl1.q # Open browser to a web preview of the survey surveypreview(sl[[1]]) +# Get a dataframe with details on each question in the survey +s1_df <- surveyquestiondf(sl[[1]]) + +### SURVEY RESPONSE FUNCTIONS + # Show the list of response ids to a survey -sl1.r <- getresponses(sl[[1]]) -sl1.r$data +s1.r <- getresponses(sl[[1]]) +s1.r$data # Show the expanded list of responses including answers to all questions -sl1.rd <- getresponses(sl[[1]], bulk = TRUE) +s1.rd <- getresponses(sl[[1]], bulk = TRUE) +# Generate a data frame with response data +s1.r_df <- as.data.frame.surveyresponses(sl[[1]]) +str(s1.r_df) +# Join response data with question data to decode responses +library(dplyr) +s1.r_decode <- left_join (s1.r_df, s1_df) \ No newline at end of file From 7823595acac1bc302bdd1e60222e4e2fdcf8aa76 Mon Sep 17 00:00:00 2001 From: Sean Fahey Date: Sun, 1 Jan 2017 23:43:42 -0500 Subject: [PATCH 47/76] tested end to end -- working --- RMonkey Demo.R | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/RMonkey Demo.R b/RMonkey Demo.R index c943656..29b05f0 100644 --- a/RMonkey Demo.R +++ b/RMonkey Demo.R @@ -11,6 +11,7 @@ library(curl) library(httr) library(jsonlite) +library(dplyr) # Load the latest Rmonkey library from github if(!require("devtools")) { @@ -79,7 +80,7 @@ s1_df <- surveyquestiondf(sl[[1]]) # Show the list of response ids to a survey s1.r <- getresponses(sl[[1]]) -s1.r$data +s1.r # Show the expanded list of responses including answers to all questions s1.rd <- getresponses(sl[[1]], bulk = TRUE) @@ -89,5 +90,4 @@ s1.r_df <- as.data.frame.surveyresponses(sl[[1]]) str(s1.r_df) # Join response data with question data to decode responses -library(dplyr) s1.r_decode <- left_join (s1.r_df, s1_df) \ No newline at end of file From 4b71aa822f0936563cbf63e08f5bc610a2077373 Mon Sep 17 00:00:00 2001 From: Sean Fahey Date: Mon, 2 Jan 2017 16:37:36 -0500 Subject: [PATCH 48/76] updated version number --- DESCRIPTION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index 69516ef..a0b039f 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,5 +1,5 @@ Package: Rmonkey -Version: 0.4 +Version: 0.5 Date: 2016-12-28 Title: A Survey Monkey R Client Authors@R: c(person("Thomas J.", "Leeper", role = c("aut", "cre"), From 2eade4769255b800a5c3ef0bb4941f9d9fceac09 Mon Sep 17 00:00:00 2001 From: Sean Fahey Date: Mon, 2 Jan 2017 16:57:26 -0500 Subject: [PATCH 49/76] updated the make variable names more consistent --- RMonkey Demo.R | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/RMonkey Demo.R b/RMonkey Demo.R index 29b05f0..c05d1a6 100644 --- a/RMonkey Demo.R +++ b/RMonkey Demo.R @@ -43,28 +43,37 @@ userdetails() ### SURVEY FUNCTIONS -# Return a list of surveys +# Get and display a list of surveys sl <- surveylist() +# print the sm_survey object using the print.sm_survey function +sl +# show the structure of the sm_survey object +str(sl[[1]]) # Return a specific list of surveys sl <- surveylist(per_page = 100, sort_by = 'num_responses', sort_order = 'desc') +sl # Return surveys that have been modified since a certain date sl <- surveylist(start_modified_at = '2016-12-25') - -# Display the list of surveys -# (This shows each survey using the print.sm_survey function which overrides the standard -# print function) sl -# Get and display more details for the first survey on the list -# (This uses the same print.sm_survey function but has more data to display) -sd1.q <- surveydetails(sl[[1]]) -sd1.q # Get and display survey deatils without the details of the survey questions -sd1 <- surveydetails(sl[[1]], question_details = FALSE) -str(sd1) +s1.d <- surveydetails(sl[[1]], question_details = FALSE) +# (This uses the same print.sm_survey function but has more data to display) +s1.d +# show the expanded details for the survey +str(s1.d) + + +# Get and display more details for the first survey on the list +s1.dq <- surveydetails(sl[[1]]) +# show the survey summary +s1.dq +# show the expanded details for the survey with all the question data +str(s1.dq) + # Show just the questions for a survey sl1.q <- surveyquestions(sl[[1]]) @@ -75,6 +84,7 @@ surveypreview(sl[[1]]) # Get a dataframe with details on each question in the survey s1_df <- surveyquestiondf(sl[[1]]) +str(s1_df) ### SURVEY RESPONSE FUNCTIONS From 98ba143307a6ac1893d89eb2f6bf54ede58509b0 Mon Sep 17 00:00:00 2001 From: Sean Fahey Date: Mon, 2 Jan 2017 17:30:00 -0500 Subject: [PATCH 50/76] reformatted code and added edits to roxygen comments --- R/smlogin.r | 55 ++++++++++++++++++++++++++++------------------------- 1 file changed, 29 insertions(+), 26 deletions(-) diff --git a/R/smlogin.r b/R/smlogin.r index acea623..bee0499 100644 --- a/R/smlogin.r +++ b/R/smlogin.r @@ -1,12 +1,13 @@ #' smlogin -#' -#' obtains a long lasting oauth token for API access. -#' +#' +#' Obtains a long lasting oauth token for API access. +#' #' This function takes as input a SurveyMonkey API account client ID and #' secret code and conducts the oauth2 authentication process to return #' an oauth token. The client_id and secret values can be obtained from the settings -#' section of the appropriate SurveyMonkey apps page https://developer.surveymonkey.com/apps/ -#' +#' section of the appropriate SurveyMonkey apps page at https://developer.surveymonkey.com/apps/ +#' + #' @param client_id Your SurveyMonkey App client_id. By default, retrieved from \code{getOption('sm_client_id')}. #' @param secret Your API secret key. By default, retrieved from \code{getOption('sm_secret')}. #' @param redirect_uri Default value is \samp{http://localhost:1410}. No other value is allowed. This must be the redirect URL registered for your application in your Survey Monkey developer account. @@ -16,25 +17,27 @@ smlogin <- function(client_id = getOption('sm_client_id'), secret = getOption('sm_secret'), redirect_uri = 'http://localhost:1410', - response_type='code'){ - if(is.null(client_id)) - stop("Must supply developer username as 'client_id'") - if(is.null(secret)) - stop("Must supply developer secret key as 'secret'") - a <- list(response_type = response_type, - redirect_uri = redirect_uri, - client_id = client_id) - a <- paste(names(a), curl_escape(a), sep='=', collapse='&') - e <- structure(list(authorize = 'https://api.surveymonkey.net/oauth/authorize', - access = 'https://api.surveymonkey.net/oauth/token'), class='oauth_endpoint') - e$authorize <- paste(e$authorize,a,sep='?') - smapp <- oauth_app('surveymonkey', client_id, secret) - - token <- oauth2.0_token(e, smapp, use_oob = FALSE, cache = FALSE) - if('error' %in% names(token$credentials)){ - warning('OAuth error ', token$credentials$error, - ': ', token$credentials$error_description, sep='') - } else - options('sm_oauth_token' = token$credentials$access_token) - invisible(token) + response_type = 'code') { + if (is.null(client_id)) + stop("Must supply developer username as 'client_id'") + if (is.null(secret)) + stop("Must supply developer secret key as 'secret'") + a <- list(response_type = response_type, + redirect_uri = redirect_uri, + client_id = client_id) + a <- paste(names(a), + curl_escape(a), + sep = '=', + collapse = '&') + e <- structure(list(authorize = 'https://api.surveymonkey.net/oauth/authorize', + access = 'https://api.surveymonkey.net/oauth/token'), + class = 'oauth_endpoint') + e$authorize <- paste(e$authorize, a, sep = '?') + smapp <- oauth_app('surveymonkey', client_id, secret) + token <- oauth2.0_token(e, smapp, use_oob = FALSE, cache = FALSE) + if ('error' %in% names(token$credentials)) { + warning('OAuth error ', token$credentials$error, ': ', token$credentials$error_description, sep = '') + } else + options('sm_oauth_token' = token$credentials$access_token) + invisible(token) } From e976d0f37206cc4546a8dd53c99b414013e9891b Mon Sep 17 00:00:00 2001 From: Sean Fahey Date: Mon, 2 Jan 2017 17:43:32 -0500 Subject: [PATCH 51/76] added roxygen comments and also reformatted code --- R/userdetails.r | 40 +++++++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/R/userdetails.r b/R/userdetails.r index bd6e128..5e545dc 100644 --- a/R/userdetails.r +++ b/R/userdetails.r @@ -1,17 +1,23 @@ -userdetails <- function( - oauth_token = getOption('sm_oauth_token'), - ... -){ - u <- 'https://api.surveymonkey.net/v3/users/me' - if(!is.null(oauth_token)) - token <- paste('bearer', oauth_token) - else - stop("Must specify 'oauth_token'. Try smlogin() first to get a token.") - out <- GET(u, config = add_headers(Authorization=token, - 'Content-Type'='application/json')) - stop_for_status(out) - content <- parsed_content(out) - # if(content$status != 0) - # warning("An error occurred: ",content$errmsg) - structure(content, class="sm_userdetails") -} +#' userdetails +#' +#' Obtains information about SurveyMonkey user. +#' +#' This function calls the SurveyMonkey API using the current oauth token and returns +#' information about the SurveyMonkey user and account associated with the token. +#' +#' @param oauth_token The SurveyMonkey App oauth_token stored in the environment. +#' @return userdetails + +userdetails <- function(oauth_token = getOption('sm_oauth_token'), ...) { + u <- 'https://api.surveymonkey.net/v3/users/me' + if (!is.null(oauth_token)) + token <- paste('bearer', oauth_token) + else + stop("Must specify 'oauth_token'. Try smlogin() first to get a token.") + out <- GET(u, config = add_headers(Authorization = token, + 'Content-Type' = 'application/json')) + stop_for_status(out) + content <- content(out, as='parsed') + structure(content, class = "sm_userdetails") + return(content) +} \ No newline at end of file From 4f78e99d1b0d161e77c13ba83d412172ad692762 Mon Sep 17 00:00:00 2001 From: Sean Fahey Date: Mon, 2 Jan 2017 18:28:51 -0500 Subject: [PATCH 52/76] added roxygen comments --- R/surveylist.r | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/R/surveylist.r b/R/surveylist.r index 484f5d7..ba5d4f5 100644 --- a/R/surveylist.r +++ b/R/surveylist.r @@ -1,3 +1,21 @@ +#' surveylist +#' +#' Obtains a list of surveys for a SurveyMonkey account. +#' +#' This function calls the SurveyMonkey API using the current oauth token and returns +#' a list of surveys based on the parameters entered. +#' +#' @param page Integer numebr to select which page of resources to return. By default is 1. +#' @param per_page Integer number to set the number of surveys to return per page. By default, is 50 surveys per page. +#' @param sort_by String used to sort returned survey list: ‘title’, 'date_modified’, or 'num_responses’. By default, date_modified. +#' @param sort_order String used to set the sort order for returned surveys: 'ASC’ or 'DESC’. By default, DESC. +#' @param start_modified_at Date string used to select surveys last modified after this date. By default is NULL. +#' @param end_modified_at Date string used to select surveys modified before this date. By default is NULL. +#' @param title String used to select survey by survey title. By default is NULL. +#' @param include Comma separated strings used to filter survey list: 'shared_with’, 'shared_by’, or 'owned’ (useful for teams) or to specify additional fields to return per survey: 'response_count’, 'date_created’, 'date_modified’, 'language’, 'question_count’, 'analyze_url’, 'preview’. By default is NULL. +#' @param oauth_token The SurveyMonkey App oauth_token stored in the environment. +#' @return sm_surveylist + surveylist <- function( page = NULL, per_page = NULL, @@ -38,6 +56,6 @@ surveylist <- function( out <- GET(u, config = h, ..., query = b) stop_for_status(out) content <- content(out, as = 'parsed') - lapply(content$data, `class<-`, 'sm_survey') - + sl <- content$data + lapply(sl, `class<-`, 'sm_survey') } \ No newline at end of file From 58f611578bcd848cf2b9dad4f1e565b9c41cf881 Mon Sep 17 00:00:00 2001 From: Sean Fahey Date: Mon, 2 Jan 2017 18:42:34 -0500 Subject: [PATCH 53/76] updated with new roxygen comments --- R/smlogin.r | 4 +-- R/surveylist.r | 9 +++--- R/userdetails.r | 9 ++++-- man/smlogin.Rd | 8 +++--- man/surveylist.Rd | 68 +++++++++++++++++++++++----------------------- man/userdetails.Rd | 34 +++++++++++------------ 6 files changed, 67 insertions(+), 65 deletions(-) diff --git a/R/smlogin.r b/R/smlogin.r index bee0499..cf29c63 100644 --- a/R/smlogin.r +++ b/R/smlogin.r @@ -10,8 +10,8 @@ #' @param client_id Your SurveyMonkey App client_id. By default, retrieved from \code{getOption('sm_client_id')}. #' @param secret Your API secret key. By default, retrieved from \code{getOption('sm_secret')}. -#' @param redirect_uri Default value is \samp{http://localhost:1410}. No other value is allowed. This must be the redirect URL registered for your application in your Survey Monkey developer account. -#' @param response_type Default value is \dQuote{code}. No other values are allowed. +#' @param redirect_uri Default value is \url{http://localhost:1410}. No other value is allowed. This must be the redirect URL registered for your application in your Survey Monkey developer account. +#' @param response_type Default value is \code{code}. No other values are allowed. #' @return oauth_token smlogin <- function(client_id = getOption('sm_client_id'), diff --git a/R/surveylist.r b/R/surveylist.r index ba5d4f5..8ba4459 100644 --- a/R/surveylist.r +++ b/R/surveylist.r @@ -1,9 +1,9 @@ #' surveylist #' -#' Obtains a list of surveys for a SurveyMonkey account. +#' Get the list of the user's surveys. #' #' This function calls the SurveyMonkey API using the current oauth token and returns -#' a list of surveys based on the parameters entered. +#' a list of surveys filtered by the parameters entered. #' #' @param page Integer numebr to select which page of resources to return. By default is 1. #' @param per_page Integer number to set the number of surveys to return per page. By default, is 50 surveys per page. @@ -13,8 +13,9 @@ #' @param end_modified_at Date string used to select surveys modified before this date. By default is NULL. #' @param title String used to select survey by survey title. By default is NULL. #' @param include Comma separated strings used to filter survey list: 'shared_with’, 'shared_by’, or 'owned’ (useful for teams) or to specify additional fields to return per survey: 'response_count’, 'date_created’, 'date_modified’, 'language’, 'question_count’, 'analyze_url’, 'preview’. By default is NULL. -#' @param oauth_token The SurveyMonkey App oauth_token stored in the environment. -#' @return sm_surveylist +#' @param oauth_token Your OAuth 2.0 token, as generated by \code{smlogin}. By default, retrieved from \code{getOption('sm_oauth_token')}. +#' @return A list of objects of class \code{sm_survey}. +#' @references SurveyMonkey API V3 at \url{https://developer.surveymonkey.com/api/v3/#surveys} surveylist <- function( page = NULL, diff --git a/R/userdetails.r b/R/userdetails.r index 5e545dc..59d896f 100644 --- a/R/userdetails.r +++ b/R/userdetails.r @@ -3,10 +3,13 @@ #' Obtains information about SurveyMonkey user. #' #' This function calls the SurveyMonkey API using the current oauth token and returns -#' information about the SurveyMonkey user and account associated with the token. +#' information about the SurveyMonkey user and account associated with the token. It can be used +#' as a "Hello World" after \code{smlogin} #' -#' @param oauth_token The SurveyMonkey App oauth_token stored in the environment. -#' @return userdetails +#' @param oauth_token Your OAuth 2.0 token, as generated by \code{\link{smlogin}}. By default, retrieved from \code{getOption('sm_oauth_token')}. +#' @return An object of class \code{sm_userdetails}. +#' @references SurveyMonkey API V3 at \url{https://developer.surveymonkey.com/api/v3/#users-me} + userdetails <- function(oauth_token = getOption('sm_oauth_token'), ...) { u <- 'https://api.surveymonkey.net/v3/users/me' diff --git a/man/smlogin.Rd b/man/smlogin.Rd index 45702f8..025e7d5 100644 --- a/man/smlogin.Rd +++ b/man/smlogin.Rd @@ -13,20 +13,20 @@ smlogin(client_id = getOption("sm_client_id"), \item{secret}{Your API secret key. By default, retrieved from \code{getOption('sm_secret')}.} -\item{redirect_uri}{Default value is \samp{http://localhost:1410}. No other value is allowed. This must be the redirect URL registered for your application in your Survey Monkey developer account.} +\item{redirect_uri}{Default value is \url{http://localhost:1410}. No other value is allowed. This must be the redirect URL registered for your application in your Survey Monkey developer account.} -\item{response_type}{Default value is \dQuote{code}. No other values are allowed.} +\item{response_type}{Default value is \code{code}. No other values are allowed.} } \value{ oauth_token } \description{ -obtains a long lasting oauth token for API access. +Obtains a long lasting oauth token for API access. } \details{ This function takes as input a SurveyMonkey API account client ID and secret code and conducts the oauth2 authentication process to return an oauth token. The client_id and secret values can be obtained from the settings -section of the appropriate SurveyMonkey apps page https://developer.surveymonkey.com/apps/ +section of the appropriate SurveyMonkey apps page at https://developer.surveymonkey.com/apps/ } diff --git a/man/surveylist.Rd b/man/surveylist.Rd index dc90c6b..036266f 100644 --- a/man/surveylist.Rd +++ b/man/surveylist.Rd @@ -1,44 +1,44 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/surveylist.r \name{surveylist} \alias{surveylist} -\alias{print.sm_survey} -\title{Get survey list} -\description{Get the list of the user's survey} +\title{surveylist} \usage{ -surveylist(page = NULL, page_size = NULL, - start_date = NULL, end_date = NULL, - title = NULL, recipient_email = NULL, - order_asc = NULL, fields = NULL, - api_key = getOption('sm_api_key'), - oauth_token = getOption('sm_oauth_token'), ...) +surveylist(page = NULL, per_page = NULL, sort_by = NULL, + sort_order = NULL, start_modified_at = NULL, end_modified_at = NULL, + title = NULL, include = NULL, oauth_token = getOption("sm_oauth_token"), + ...) } \arguments{ -\item{page}{A number indicating which page of results to return.} -\item{page_size}{The number of results to return per API call. Default is 1000.} -\item{start_date}{A start datetime to restrict result to. Any returned surveys must have been created on or after this datetime. Required format is \code{YYYY-MM-DD HH:MM:SS}, implicitly in UTC; if argument is of class \code{POSIXct}, formatting is handled automatically.} -\item{end_date}{An end datetime to restrict result to. Any returned surveys must have been created strictly before this datetime. Required format is \code{YYYY-MM-DD HH:MM:SS}, implicitly in UTC; if argument is of class \code{POSIXct}, formatting is handled automatically.} -\item{title}{A character string containing the title of a survey to search for.} -\item{recipient_email}{A character string containing an email adddress. Only surveys sent to this email will be returned.} -\item{order_asc}{A boolean indicating whether results should be sorted in ascending or descending (the default) order.} -\item{fields}{A character vector containing the names of fields to return in each \code{sm_collector} class object. See Details.} -\item{api_key}{Your API key. By default, retrieved from \code{getOption('sm_api_key')}.} -\item{oauth_token}{Your OAuth 2.0 token, as generated by \code{\link{smlogin}}. By default, retrieved from \code{getOption('sm_oauth_token')}.} -\item{...}{Other arguments passed to \code{\link[httr]{POST}}.} -} -\details{Retrieves the list of surveys available to the user. +\item{page}{Integer numebr to select which page of resources to return. By default is 1.} + +\item{per_page}{Integer number to set the number of surveys to return per page. By default, is 50 surveys per page.} + +\item{sort_by}{String used to sort returned survey list: ‘title’, 'date_modified’, or 'num_responses’. By default, date_modified.} + +\item{sort_order}{String used to set the sort order for returned surveys: 'ASC’ or 'DESC’. By default, DESC.} + +\item{start_modified_at}{Date string used to select surveys last modified after this date. By default is NULL.} + +\item{end_modified_at}{Date string used to select surveys modified before this date. By default is NULL.} -The \code{fields} argument accepts one or more of the following values: \code{title}, \code{analysis_url}, \code{preview_url}, \code{date_created}, \code{date_modified}, \code{language_id}, \code{question_count}, \code{num_responses}. +\item{title}{String used to select survey by survey title. By default is NULL.} + +\item{include}{Comma separated strings used to filter survey list: 'shared_with’, 'shared_by’, or 'owned’ (useful for teams) or to specify additional fields to return per survey: 'response_count’, 'date_created’, 'date_modified’, 'language’, 'question_count’, 'analyze_url’, 'preview’. By default is NULL.} + +\item{oauth_token}{Your OAuth 2.0 token, as generated by \code{smlogin}. By default, retrieved from \code{getOption('sm_oauth_token')}.} } -\value{A list of objects of class \code{sm_survey}.} -\references{ -\url{https://developer.surveymonkey.com/mashery/get_survey_list} +\value{ +A list of objects of class \code{sm_survey}. } -\author{Thomas J. Leeper} -%\note{} -%\seealso{} -\examples{ -\dontrun{ -smlogin() -surveylist() +\description{ +Get the list of the user's surveys. } +\details{ +This function calls the SurveyMonkey API using the current oauth token and returns +a list of surveys filtered by the parameters entered. } -%\keyword{} +\references{ +SurveyMonkey API V3 at \url{https://developer.surveymonkey.com/api/v3/#surveys} +} + diff --git a/man/userdetails.Rd b/man/userdetails.Rd index a76aa42..2185ba9 100644 --- a/man/userdetails.Rd +++ b/man/userdetails.Rd @@ -1,28 +1,26 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/userdetails.r \name{userdetails} \alias{userdetails} -\title{Get User Details} -\description{Once logged in, get basic details about the user account.} +\title{userdetails} \usage{ -userdetails(api_key = getOption('sm_api_key'), - oauth_token = getOption('sm_oauth_token'), ...) +userdetails(oauth_token = getOption("sm_oauth_token"), ...) } \arguments{ -\item{api_key}{Your API key. By default, retrieved from \code{getOption('sm_api_key')}.} \item{oauth_token}{Your OAuth 2.0 token, as generated by \code{\link{smlogin}}. By default, retrieved from \code{getOption('sm_oauth_token')}.} -\item{...}{Other arguments passed to \code{\link[httr]{POST}}.} } -\details{This function retrieves basic details about a user. It can be used as a hello world test after \code{\link{smlogin}}.} -\value{An object of class \code{sm_userdetails}.} -\references{ -\url{https://developer.surveymonkey.com/mashery/get_user_details} +\value{ +An object of class \code{sm_userdetails}. +} +\description{ +Obtains information about SurveyMonkey user. } -\author{Thomas J. Leeper} -%\note{} -%\seealso{} -\examples{ -\dontrun{ -smlogin() -userdetails() +\details{ +This function calls the SurveyMonkey API using the current oauth token and returns +information about the SurveyMonkey user and account associated with the token. It can be used +as a "Hello World" after \code{smlogin} } +\references{ +SurveyMonkey API V3 at \url{https://developer.surveymonkey.com/api/v3/#users-me} } -%\keyword{} + From f6815a0a4d3a011deb5bfc888247fb337519025d Mon Sep 17 00:00:00 2001 From: Sean Fahey Date: Mon, 2 Jan 2017 19:06:21 -0500 Subject: [PATCH 54/76] updated news --- .Rapp.history | 1054 +++++++++++++++++++++++++++++++++++++++++++++++++ NEWS | 11 + 2 files changed, 1065 insertions(+) create mode 100644 .Rapp.history diff --git a/.Rapp.history b/.Rapp.history new file mode 100644 index 0000000..5068548 --- /dev/null +++ b/.Rapp.history @@ -0,0 +1,1054 @@ +q() +install.packages(c('repr','pbdZMQ','devtools')) +devtools::install_github(c('IRkernal/IRdisplay','IRkernal/IRkernal')) +devtools::install_github(c('IRkernel/IRdisplay','IRkernel/IRkernal')) +devtools::install_github(c('IRkernel/IRdisplay','IRkernel/IRkernel')) +q() +# Admit to Net Enroll Model with Caret# +## +# Sean Fahey# +# 2016-08-12# +## +# This script uses the Caret package to make and compare admit to net enroll models# +## +# +################# +## +# CONFIGURE ENVIRONMENT# +## +################## +# +# This is designed to be run in the /Student Lifecycle/Admit to Net Enroll directory# +getwd()# +# +# Load needed libraries# +library(plyr) # this is here to make sure it loads before dplyr# +library(dplyr)# +### BUILD DATASET# +# +# load base dataset# +load("../../data/tidy_data/Inquiry Lifecycle Admits 2014- Tidy.RData")# +# +# join the ESperformance dataset# +load("../../data/tidy_data/ESPerformanceData.RData")# +mdata %>% left_join(inquiriesByOwner) -> mdata# +# +### PREPARE MODLING DATASET# +# +# Select only the variables to be used for the model# +mdata1 <- select(mdata, application_university_name, md_degree_level, application_program_area, gpa__c, application_decision_original, application_has_pushed, application_is_program_switch, has_gpa, vel_inq_to_app, vel_app_to_admit, fa_prob, has_loi, student_age_at_startdate, marital_status__c, inquiry_channel_group, x_is_international, application_is_full_scholarship, scholarship_total__c, FID.monthNumber, ES_pct_admit_to_netenroll, x_is_net_enroll, x_is_cancelled_enroll, sf_app_id)# +# +# Generate factors for variables# +mdata1$application_program_area <- as.factor(mdata1$application_program_area)# +mdata1$application_decision_original <- as.factor(mdata1$application_decision_original)# +mdata1$marital_status__c[mdata1$marital_status__c == '']<- 'Unknown'# +mdata1$marital_status__c[is.na(mdata1$marital_status__c)]<- 'Unknown'# +mdata1$marital_status__c <- as.factor(mdata1$marital_status__c)# +mdata1$FID.monthNumber <- as.factor(mdata1$FID.monthNumber)# +# +# show the number of NAs# +sapply(mdata1, function(x) sum(is.na(x)))# +# +## IMPUTE MISSING DATA# +# +# impute missing GPA data as the mean # +mdata1$gpa__c[is.na(mdata1$gpa__c)]<- mean(mdata1$gpa__c, na.rm=T)# +# +# impute missing ES percent admit to net enroll# +mdata1$ES_pct_admit_to_netenroll[is.na(mdata1$ES_pct_admit_to_netenroll)]<- mean(mdata1$ES_pct_admit_to_netenroll, na.rm=T)# +# +# impute missing app to start data as the mean # +mdata1$inquiry_channel_group <- as.factor(mdata1$inquiry_channel_group)# +mdata1$x_is_international <- ifelse(mdata1$x_is_international== 1, 'International', 'US/Canada') # +mdata1$x_is_international <- as.factor(mdata1$x_is_international)# +# + # create a text outcome variable# +mdata1$outcome <- NA# +mdata1$outcome[mdata1$x_is_net_enroll == 1] <- 'Enrolled'# +mdata1$outcome[mdata1$x_is_cancelled_enroll == 1] <- 'Cancelled'# +mdata1$outcome<-as.factor(mdata1$outcome)# +mdata1$x_is_net_enroll <- NULL # we remove the integer flag since we have the outcome variable# +mdata1$x_is_cancelled_enroll <- NULL # we remove the integer flag since we have the outcome variable# +# show the number of NAs# +sapply(mdata1, function(x) sum(is.na(x)))# +# +mdata1 <- mdata1[complete.cases(mdata1),] # This removes cases with NAs to ensure the caret predictions work# +str(mdata1)# +### CREATE TRAINING AND TEST DATA PARTITIONS# +# +library(caret) # This is a useful ML library we will be using that has a handy function for creating data partitions# +set.seed(1234) # pick a specific random seed so the results can be recreated# +intrain<-createDataPartition(y=mdata1$outcome,p=0.7,list=FALSE)# +training<-mdata1[intrain,]# +testing<-mdata1[-intrain,]# +# +# Set the machine learning cross validation training rules# +# +fitControl_cv <- trainControl(## 5-fold CV, repeated 3 times# + method = "repeatedcv",# + number = 5,# + repeats = 3, # + classProbs = TRUE,# + summaryFunction = twoClassSummary)# +## DECISION TREE MODEL# +# +# Train the model # +rpart_cv <- train(outcome ~ ., data = select(training, -sf_app_id),# + method = "rpart",# + trControl = fitControl_cv,# + metric = "ROC")# +# +# Show how well the model performed on the training data# +confusionMatrix(predict(rpart_cv),training$outcome, positive = "Enrolled")# +# Predict the outcomes for the test data set# +rpart_cv.pred <- predict(rpart_cv, newdata = select(testing, -sf_app_id))# +# +# Show how well the model performed on the testing data# +confusionMatrix(rpart_cv.pred,testing$outcome, positive = "Enrolled")# +## GRADIENT BOOSTING MACHINE# +# +# Train the model # +gbm_cv <- train(outcome ~ ., data = select(training, -sf_app_id),# + method = "gbm",# + trControl = fitControl_cv,# + metric = "ROC")# +# +# Show how well the model performed on the training data# +confusionMatrix(predict(gbm_cv),training$outcome, positive = "Enrolled")# +# Predict the outcomes for the test data set# +gbm_cv.pred <- predict(gbm_cv, newdata = select(testing, -sf_app_id))# +# +# Show how well the model performed on the testing data# +confusionMatrix(gbm_cv.pred,testing$outcome, positive = "Enrolled")# +# +# ## GENERALIZED LINEAR MACHINE# +# +# # Train the model # +# glm_cv_cs <- train(outcome ~ ., data = select(training, -sf_app_id),# + # method = "glm",# + # trControl = fitControl_cv,# + # preProcess = c("center", "scale"),# + # metric = "ROC")# +# +# # Show how well the model performed on the training data# +# confusionMatrix(predict(glm_cv_cs),training$outcome, positive = "Enrolled")# +# # Predict the outcomes for the test data set# +# glm_cv_cs.pred <- predict(glm_cv_cs, newdata = select(testing, -sf_app_id))# +# +# # Show how well the model performed on the testing data# +# confusionMatrix(glm_cv_cs.pred,testing$outcome, positive = "Enrolled")# +# +## GRADIENT BOOSTING MACHINE WITH PREPROCESSING# +# +# Train the model # +gbm_cv_cs <- train(outcome ~ ., select(training, -sf_app_id),# + method = "gbm",# + trControl = fitControl_cv,# + preProcess = c("center", "scale"),# + metric = "ROC")# +# +# Show how well the model performed on the training data# +confusionMatrix(predict(gbm_cv_cs),training$outcome, positive = "Enrolled")# +# Predict the outcomes for the test data set# +gbm_cv_cs.pred <- predict(gbm_cv_cs, newdata = select(testing, -sf_app_id))# +# +# Show how well the model performed on the testing data# +confusionMatrix(gbm_cv_cs.pred,testing$outcome, positive = "Enrolled")# +# +# # SUPPORT VECTOR MACHINE# +# +# Train the model # +# svm_cv <- train(outcome ~ ., data = select(training, -sf_app_id),# + # method = "svmLinear2",# + # trControl = fitControl_cv,# + # metric = "ROC")# +# +# Show how well the model performed on the training data# +# confusionMatrix(predict(svm_cv),training$outcome, positive = "Enrolled")# +# Predict the outcomes for the test data set# +# svm_cv.pred <- predict(svm_cv, newdata = select(testing, -sf_app_id))# +# +# Show how well the model performed on the testing data# +# confusionMatrix(svm_cv.pred,testing$outcome, positive = "Enrolled")# +# +# # NEURAL NETWORK# +# +# Train the model # +# nnet_cv <- train(outcome ~ ., data = select(training, -sf_app_id),# + # method = "nnet",# + # trControl = fitControl_cv,# + # metric = "ROC")# +# +# Show how well the model performed on the training data# +# confusionMatrix(predict(nnet_cv),training$outcome, positive = "Enrolled")# +# Predict the outcomes for the test data set# +# nnet_cv.pred <- predict(nnet_cv, newdata = select(testing, -sf_app_id))# +# +# Show how well the model performed on the testing data# +# confusionMatrix(nnet_cv.pred,testing$outcome, positive = "Enrolled")# +## MODEL COMPARISON# +# +# results <- resamples(list(GBM=gbm_cv, GBM_cs = gbm_cv_cs, RPART=rpart_cv, NNET = nnet_cv, SVM = svm_cv))# +results <- resamples(list(GBM_cs=gbm_cv_cs, GBM = gbm_cv, RPART=rpart_cv))# +summary(results)# +bwplot(results) +q() +? read.csv +q() +ls() +rm(list = ls()) +ls() +q() +ip <- installed.packages() +pkgs.to.remove <- ip[!(ip[,"Priority"] %in% c("base", "recommended")), 1] +sapply(pkgs.to.remove, remove.packages) +q() +update9) +update() +# Inquiry to Net Enroll Model Development# +## +# Sean Fahey# +# 2016-06-16# +## +# This script develops and compares models for predicting the likelihood that an inquiry will net enroll including both internal inquiry lifecycle view data as well# +# as external zip code data# +## +# +################# +## +# CONFIGURE ENVIRONMENT# +## +################## +# set working directory# +getwd()# +# setwd("/Users/sean.fahey/Google Drive/Analytics and Data/Modeling/Inquiry to Enroll/code/")# +# load needed packages# +library(dplyr)# +library(caret)# +library(zipcode)# +library (ROCR)# +source("modelAssess.R")# +################ +## +# GET RAW DATA# +## +################ +# +### Comment out either the Query or Load line# +# +# Option 1 - Query DB for raw data# +# source("../rawData/All Inquiries (De-ID) 2014-.R", echo=TRUE)# +# +# Optiona 1a - Save the raw data for later offline analysis# +# save(data, file="../rawData/All Inquiries (De-ID) with zip 2014- Raw.RData")# +# write.csv(data, file = "../rawData/All Inquiries (De-ID) with zip 2014- Raw.csv")# +# Option 2 - Load saved raw data# +# load(file="../rawData/All Inquiries (De-ID) with zip 2013- Raw.RData")# +################ +## +# GET TIDY DATA# +## +################ +# +# Option 1 - Run Script to prepare raw data for modeling# +# source("../tidyData/Inquiry Lifecycle Query Prep.R", echo=TRUE)# +# +# Option 1a - Save tidy data for later offline analysis# +# save(mdata, file="../tidyData/All Inquiries (De-ID) 2013- Tidy.RData")# +# +# Option 2 - Load saved tidy data# +load("../tidyData/All Inquiries (De-ID) 2014- Tidy.RData")# +# - Add external data from ACS DP02# +# o HC03_VC04 - Percent; HOUSEHOLDS BY TYPE - Total households - Family households (families)# +# o HC03_VC06 - Percent; HOUSEHOLDS BY TYPE - Total households - Family households (families) - Married-couple family# +# o HC03_VC10 - Percent; HOUSEHOLDS BY TYPE - Total households - Family households (families) - Female householder, no husband present, family# +# o HC01_VC21 - Estimate; HOUSEHOLDS BY TYPE - Average household size# +# o HC03_VC81 - Percent; SCHOOL ENROLLMENT - Population 3 years and over enrolled in school - College or graduate school# +# o HC03_VC91 - Percent; EDUCATIONAL ATTAINMENT - Population 25 years and over - Bachelor's degree# +# o HC03_VC92 - Percent; EDUCATIONAL ATTAINMENT - Population 25 years and over - Graduate or professional degree# +# o Create variable (VC92- VC91)# +# o HC03_VC96 - Percent; EDUCATIONAL ATTAINMENT - Percent bachelor's degree or higher# +# o HC03_VC121 - Percent; RESIDENCE 1 YEAR AGO - Population 1 year and over - Different house in the U.S.# +# o HC03_VC125 - Percent; RESIDENCE 1 YEAR AGO - Population 1 year and over - Different house in the U.S. - Different county - Different state# +# - Add external data from ACS DP03# +# o HC01_VC04 - Estimate; EMPLOYMENT STATUS - Population 16 years and over - In labor force# +# o HC03_VC04 - Percent; EMPLOYMENT STATUS - Population 16 years and over - In labor force# +# o HC03_VC07 - Percent; EMPLOYMENT STATUS - Population 16 years and over - In labor force - Civilian labor force – Unemployed# +# o HC01_VC15 - Estimate; EMPLOYMENT STATUS - Females 16 years and over - In labor force# +# o HC03_VC15 - Percent; EMPLOYMENT STATUS - Females 16 years and over - In labor force# +# o HC01_VC59 - Estimate; INDUSTRY - Civilian employed population 16 years and over - Educational services, and health care and social assistance# +# o HC03_VC59 - Percent; INDUSTRY - Civilian employed population 16 years and over - Educational services, and health care and social assistance# +# o HC01_VC85 - Estimate; INCOME AND BENEFITS (IN 2014 INFLATION-ADJUSTED DOLLARS) - Total households - Median household income (dollars)# +# o HC01_VC114 - Estimate; INCOME AND BENEFITS (IN 2014 INFLATION-ADJUSTED DOLLARS) - Families - Median family income (dollars)# +# o HC01_VC118 - Estimate; INCOME AND BENEFITS (IN 2014 INFLATION-ADJUSTED DOLLARS) - Per capita income (dollars)# +# o HC03_VC161 - Percent; PERCENTAGE OF FAMILIES AND PEOPLE WHOSE INCOME IN THE PAST 12 MONTHS IS BELOW THE POVERTY LEVEL - All families# +#### Build ACS Zip Code dataset# +ACS_demo <- read.csv("../external_data/ACS_14_5YR_DP02_selected.csv")# +ACS_demo <- select(ACS_demo, - GEO.id, - GEO.display.label)# +names(ACS_demo)[names(ACS_demo)=='HC03_VC04']<-'DP02_HC03_VC04'# +ACS_econ <- read.csv("../external_data/ACS_14_5YR_DP03_selected.csv", stringsAsFactors=FALSE)# +ACS_econ <- select(ACS_econ, - GEO.id, - GEO.display.label)# +ACS_econ$HC01_VC85 <- as.numeric(ACS_econ$HC01_VC85)# +ACS_econ$HC01_VC114 <- as.numeric(ACS_econ$HC01_VC114)# +ACS <- left_join(ACS_demo, ACS_econ, by = "GEO.id2")# +ACS_scaled<- ACS# +ACS_scaled[,-c(1)] <- scale(ACS_scaled[,-c(1)])# +ACS_scaled$zip_code <- clean.zipcodes(ACS_scaled$GEO.id2)# +#### Load US Economic condition data# +US_econ <- read.csv("../external_data/US Economic Condition by Month.csv")# +US_econ$Year <- as.factor(US_econ$Year)# +# +# load base lifecycle view (LCV) data and select only zip codes# +load("../tidyData/All Inquiries (De-ID) 2014- Tidy.RData")# +LCV <- mdata# +LCV$zip_code <- LCV$student_postal_code# +LCV$zip_code<- clean.zipcodes(LCV$zip_code) # +LCV$zip_code[is.na(LCV$student_postal_code)] <- LCV$inquiry_postal_code[is.na(LCV$student_postal_code)] # +LCV$zip_code<- clean.zipcodes(LCV$zip_code) # +LCV$FID.year <- as.factor(LCV$FID.year)# +LCV$inquiry_age <- Sys.Date() - LCV$date_first_inquiry# +LCV$inquiry_age_log <- log(as.numeric(LCV$inquiry_age))# +# +# join datasets# +LCV <- left_join(LCV, ACS_scaled)# +LCV <- left_join(LCV, US_econ, by = c("FID.month" = "Month", "FID.year" = "Year"))# +# +# show NAs# +sapply(LCV, function(x) sum(is.na(x)))# +################ +## +# PREPARE TIDY DATA FOR MODELING# +## +################ +# +# filter out recent inquiries to give time for enrollment# +# +LCV <- LCV[LCV$date_first_inquiry<"2016-05-01",]# +# set Outcome Variable# +LCV$outcome_var <- LCV$x_is_net_enroll# +LCV$outcome_var <- factor(LCV$outcome_var)# +# +# Create class variables# +LCV$Class[LCV$outcome_var == 0 ] = "Not"# +LCV$Class[LCV$outcome_var == 1] = "Enrolled"# +# +# Build training, validation and testsets# +inTrain <- createDataPartition(y = LCV$outcome_var, p = .75, list = FALSE)# +training <- LCV[inTrain,]# +testing <- LCV[-inTrain,]# +# +# # filter out unused variables# +# LCVdata <- select(LCV, inquiry_postal_code, x_is_net_enroll,inquiry_degree_group, inquiry_channel, FID.month, student_postal_code, FID.year)# +# # remove unneeded variables# +# LCVdata$x_is_net_enroll <- NULL# +# LCVdata$zip_code <- NULL# +# LCVdata$inquiry_postal_code <- NULL# +# LCVdata$student_postal_code <- NULL# +# LCVdata$GEO.id2 <- NULL# +# # Create factors# +# mdata$outcome_var = factor(mdata$outcome_var)# +# mdata$inquiry_channel = factor(mdata$inquiry_channel)# +################ +## +# BUILD MODELS# +## +################ +# +attach(training)# +# +### Model 1 - Inquiry Degree Group and Channel# +m1.logit.fit = glm(outcome_var ~ inquiry_degree_group + inquiry_channel, family= binomial(logit), data = training)# +m1.logit.modelAssess <- modelAssess(m1.logit.fit, testing)# +# +### Model 2 - Inquiry Degree Group, Channel and seasonality# +m2.logit.fit = glm(outcome_var ~ inquiry_degree_group + inquiry_channel + FID.month, family= binomial(logit), data = training)# +m2.logit.modelAssess <- modelAssess(m2.logit.fit, testing)# +# +### Model 3 - Inquiry Degree Group, Channel, seasonality and macroeconomics# +m3.logit.fit = glm(outcome_var ~ inquiry_degree_group + inquiry_channel + FID.month + UnempRate + JobOpenings_EdHealth, family= binomial(logit), data = training)# +m3.logit.modelAssess <- modelAssess(m3.logit.fit, testing)# +# +### Model 4 - Inquiry Degree Group, Channel, seasonality, macroeconomics and zipcode SES# +m4.logit.fit = glm(outcome_var ~ inquiry_degree_group + inquiry_channel + FID.month + UnempRate + JobOpenings_EdHealth + HC03_VC161 + HC01_VC85, family = binomial(logit), data = training)# +m4.logit.modelAssess <- modelAssess(m4.logit.fit, testing)# +# ### Model 4 Caret - GLM - Inquiry Degree Group, Channel and FID Month with 1 pass 10 fold cross validation# +# ctrl <- trainControl(method = "repeatedcv", repeats = 1, number = 3, classProbs = TRUE, summaryFunction = twoClassSummary)# +# m4c.fit <- train(make.names(outcome_var) ~ inquiry_degree_group + inquiry_channel + FID.month + UnempRate + JobOpenings_EdHealth + HC03_VC161 + HC01_VC85, data= training, method = "glm", trControl = ctrl, metric = "Sens")# +# m4c.PredClass <- predict(m4c.fit, select(testing, inquiry_degree_group, inquiry_channel, FID.monthUnempRate, JobOpenings_EdHealth, HC03_VC161, HC01_VC85))# +# confusionMatrix(m4c.PredClass, testing$Class)# +# ### Model 4 - adaBoost - Inquiry Degree Group, Channel and FID Month with 1 pass 10 fold cross validation# +# ctrl <- trainControl(method = "repeatedcv", repeats = 1, classProbs = TRUE, summaryFunction = twoClassSummary)# +# m4.fit <- train(Class ~ inquiry_degree_group + inquiry_channel + FID.month, data= training, method = "adaboost", trControl = ctrl, metric = "ROC")# +# m4.PredClass <- predict(m4.fit, select(testing, -outcome_var))# +# confusionMatrix(m4.PredClass, testing$Class)# +# +################ +## +# PLOT MODEL PERFORMANCE# +## +################ +par(mfrow=c(2,2))# +# +# Plot Persistence/Recall Curve# +plot(m1.logit.modelAssess$precrec, col=1, lwd=2, main="Precision/Recall Curve", xlim=c(0,1), ylim=c(0,1))# +plot(m2.logit.modelAssess$precrec, col=2, lwd=2, add=T)# +plot(m3.logit.modelAssess$precrec, col=3, lwd=2, add=T)# +plot(m4.logit.modelAssess$precrec, col=4, lwd=2, add=T)# +legend("bottomright",col=c(1:7),lwd=2,legend=c("M1","M2","M3","M4"),bty='n')# +# +# Plot F measure vs. Cutoff Curve# +plot(m1.logit.modelAssess$f, col=1, lwd=2, main="F Measure vs. Cutoff Value", xlim=c(0,1), ylim=c(0,1))# +plot(m2.logit.modelAssess$f, col=2, lwd=2, add=T)# +plot(m3.logit.modelAssess$f, col=3, lwd=2, add=T)# +plot(m4.logit.modelAssess$f, col=4, lwd=2, add=T)# +legend("bottomright",col=c(1:7),lwd=2,legend=c("M1","M2", "M3", "M4"),bty='n')# +# +# Plot ROC Curve# +plot(m1.logit.modelAssess$roc, col=1, lwd=2,main="ROC Curve")# +plot(m2.logit.modelAssess$roc, col=2, lwd=2, add=T)# +plot(m3.logit.modelAssess$roc, col=3, lwd=2, add=T)# +plot(m4.logit.modelAssess$roc, col=4, lwd=2, add=T)# +abline(a=0,b=1,lwd=2,lty=2,col="gray")# +legend("bottomright",col=c(1:8),lwd=2,legend=c("M1","M2","M3", "M4"),bty='n')# +###### +# CARET# +##### +# +#### Build Dataset# +# +# Pick the outcome variable and predictor variables# +# +#### Preprocessing# +# +# Create Dummy Variables# +# +# can use the model.matrix base R function here to make a numeric set of factors# +# model.matrix(survived ~ ., data = etitanic)# +# +# can also use dummyVars function# +# dummyVars(survived ~ ., data = etitanic) # note this is full rank and does not have an intercept# +# Remove Near Zero Variance Variables# +# +# can use nearZeroVar# +# +# nzv <- nearZeroVar(mdrrDescr)# +# filteredDescr <- mdrrDescr[, -nzv]# +# dim(filteredDescr)# +# +#### Sampling# +# +# set.seed(998)# +# inTraining <- createDataPartition(Sonar$Class, p = .75, list = FALSE)# +# training <- Sonar[ inTraining,]# +# testing <- Sonar[-inTraining,]# +#### Training# +# +# ctrl <- trainControl(method = "repeatedcv", repeats = 3, classProbs = TRUE, summaryFunction = twoClassSummary)# +# mx.logit.fit <- train(Class ~ inquiry_degree_group + inquiry_channel + FID.month, data= training, method = "glm", trControl = ctrl, metric = "ROC", preProc = c("center", "scale"))# +# +#### Compare Models# +# resamps <- resamples(list(GBM = gbmFit3,# +# SVM = svmFit,# +# RDA = rdaFit))# +# resamps# +# summary(resamps)# +# trellis.par.set(theme1)# +# bwplot(resamps, layout = c(3, 1))# +# trellis.par.set(caretTheme())# +# dotplot(resamps, metric = "ROC")# +# # +# # T-test differences in performance# +# difValues <- diff(resamps)# +# difValues# +# summary(difValues)# +# trellis.par.set(theme1)# +# bwplot(difValues, layout = c(3, 1)) +# Inquiry to Net Enroll Model Development# +## +# Sean Fahey# +# 2016-06-16# +## +# This script develops and compares models for predicting the likelihood that an inquiry will net enroll including both internal inquiry lifecycle view data as well# +# as external zip code data# +## +# +################# +## +# CONFIGURE ENVIRONMENT# +## +################## +# set working directory# +getwd()# +# setwd("/Users/sean.fahey/Google Drive/Analytics and Data/Modeling/Inquiry to Enroll/code/")# +# load needed packages# +library(dplyr)# +library(caret)# +library(zipcode)# +library (ROCR)# +source("modelAssess.R") +q() +library(MASS) +data(cats) +str(cats) +plot (bwt ~ hwt) +plot (cats$bwt ~ cats$hwt) +plot(cats$Bwt, cats$Hwt) +m <- glm(Bwt ~ Hwt, data = cats) +summary(m) +bwt2 <- predict(m,cats$Hwt) +bwt2 <- predict(m,data = cats$Hwt) +with(cats, plot( Bwt, Bwt2, Hgt)) +with(cats, plot( Bwt, Hgt, Bwt2, Hgt)) +plot(cats$Bwt, cats$Hwt, Bwt2, cats$Hwt) +plot(cats$Bwt, cats$Hwt) +abline(m) +q() +a<- c(1,2,NA,3) +b<- c(2,3,4,NA) +plot(a,b) +b<-c(b,3) +plot(a,b) +nrow(a) +nrows(a) +rows(a) +str(a) +len(a) +size(a) +length(a0) +length(a) +help(ave) +attach(warpbreaks)# +ave(breaks, wool)# +ave(breaks, tension)# +ave(breaks, tension, FUN = function(x) mean(x, trim = 0.1))# +plot(breaks, main =# + "ave( Warpbreaks ) for wool x tension combinations")# +lines(ave(breaks, wool, tension ), type = "s", col = "blue")# +lines(ave(breaks, wool, tension, FUN = median), type = "s", col = "green")# +legend(40, 70, c("mean", "median"), lty = 1,# + col = c("blue","green"), bg = "gray90")# +detach() +names(warpbreaks) +head(warpbreaks) +str(warpbreaks) +boxplot(breaks, wool) +boxplot(warpbreaks$breaks, warpbreaks$wool) +table(wool) +table(warpbreakswool) +table(warpbreaks$wool) +q() +help order +order?? +) +order +? order +q() +library(Rmonkey) +smlogin() +options(sm_secret = '247980397240465379297676830494544653711') +options(sm_client_id = 'xNrzuB4PTCaaQM326voPgA') +smlogin() +q() +# RMonkey library demo# +## +# Sean Fahey# +# 2016-12-28# +## +# This program shows how the RMonkey library can be used to access SurveyMonkey data# +# via API V3.# +## +# +# Load the latest library from github# +if(!require("devtools")) {# + install.packages("devtools")# + library("devtools")# +}# +install_github("seanofahey/Rmonkey")# +library("Rmonkey") +# get a long lasting oauth token# +smlogin() +options(sm_secret = '247980397240465379297676830494544653711') +options(sm_client_id = 'xNrzuB4PTCaaQM326voPgA') +smlogin() +userdetails() +userdetails +userdetails <- function(# + oauth_token = getOption('sm_oauth_token'),# + ...# +){# + u <- 'https://api.surveymonkey.net/v3/users/me'# + if(!is.null(oauth_token))# + token <- paste('bearer', oauth_token)# + else# + stop("Must specify 'oauth_token'. Try smlogin() first to get a token.")# + out <- POST(u, config = add_headers(Authorization=token))# + stop_for_status(out)# + content <- parsed_content(out)# + # if(content$status != 0)# + # warning("An error occurred: ",content$errmsg)# + structure(content$data$user_details, class='sm_userdetails')# +} +userdetails +userdetails() +library(httr) +library(curl) +userdetails() +u <- userdetails() +str(u) +u +userdetails <- function(# + oauth_token = getOption('sm_oauth_token'),# + ...# +){# + u <- 'https://api.surveymonkey.net/v3/users/me'# + if(!is.null(oauth_token))# + token <- paste('bearer', oauth_token)# + else# + stop("Must specify 'oauth_token'. Try smlogin() first to get a token.")# + out <- GET(u, config = add_headers(Authorization=token))# + stop_for_status(out)# + content <- parsed_content(out)# + # if(content$status != 0)# + # warning("An error occurred: ",content$errmsg)# + structure(content$data$user_details, class="sm_userdetails")# +} +userdetails() +q() +# RMonkey library demo# +## +# Sean Fahey# +# 2016-12-28# +## +# This program shows how the RMonkey library can be used to access SurveyMonkey data# +# via API V3.# +## +# +# load needed libraries# +library(curl)# +library(httr)# +# +# Load the latest Rmonkey library from github# +if(!require("devtools")) {# + install.packages("devtools")# + library("devtools")# +}# +install_github("seanofahey/Rmonkey")# +library("Rmonkey") +options(sm_secret = '247980397240465379297676830494544653711') +options(sm_client_id = 'xNrzuB4PTCaaQM326voPgA') +smlogin() +userdetails +userdetails() +u1 <- userdetails() +class(u1) +u1 +str(u1) +names(u1) +h <- add_headers(Authorization=token,# + 'Content-Type'='application/json') +oauth_token = getOption('sm_oauth_token') +oauth_token +u <- 'https://api.surveymonkey.net/v3/users/me' +token <- paste('bearer', oauth_token) +token +out <- GET(u, config = add_headers(Authorization=token,# + 'Content-Type'='application/json')) +out +str(out) +content <- parsed_content(out) +str(content) +userdetails <- function(# + oauth_token = getOption('sm_oauth_token'),# + ...# +){# + u <- 'https://api.surveymonkey.net/v3/users/me'# + if(!is.null(oauth_token))# + token <- paste('bearer', oauth_token)# + else# + stop("Must specify 'oauth_token'. Try smlogin() first to get a token.")# + out <- GET(u, config = add_headers(Authorization=token,# + 'Content-Type'='application/json'))# + stop_for_status(out)# + content <- parsed_content(out)# + # if(content$status != 0)# + # warning("An error occurred: ",content$errmsg)# + structure(content$data$user_details, class="sm_userdetails")# +} +userdetails() +u1 <- userdetails() +str(u1) +content +structure(content, class="sm_userdetails") +str(content) +u1 <- userdetails() +str(u1) +u1 +rm(list = ls()) +smlogin() +userdetails <- function(# + oauth_token = getOption('sm_oauth_token'),# + ...# +){# + u <- 'https://api.surveymonkey.net/v3/users/me'# + if(!is.null(oauth_token))# + token <- paste('bearer', oauth_token)# + else# + stop("Must specify 'oauth_token'. Try smlogin() first to get a token.")# + out <- GET(u, config = add_headers(Authorization=token,# + 'Content-Type'='application/json'))# + stop_for_status(out)# + content <- parsed_content(out)# + # if(content$status != 0)# + # warning("An error occurred: ",content$errmsg)# + structure(content, class="sm_userdetails")# +} +u1 <- userdetails() +str(u1) +sl <- surveylist() +sl +# Lookup userdetails to test API# +users <- userdetails()# +# +# Show a list of surveys# +sl <- surveylist() +sl +surveydetails(sl[[1]]) +sd1.q <- surveydetails(sl[[1]], question_details = TRUE) +str(sd1.q) +q() +# RMonkey library demo# +## +# Sean Fahey# +# 2016-12-28# +## +# This program shows how the RMonkey library can be used to access SurveyMonkey data# +# via API V3.# +## +# +# load needed libraries# +library(curl)# +library(httr)# +# +# Load the latest Rmonkey library from github# +if(!require("devtools")) {# + install.packages("devtools")# + library("devtools")# +}# +install_github("seanofahey/Rmonkey")# +library("Rmonkey")# +# +# Create a SurveyMonkey App to enable the API# +# 1) go to https://developer.surveymonkey.com/apps/ to create an app# +# 2) set the OAuth redirect URL as http://localhost:1410# +# 3) set the scope permissions (I used all the view ones but no create ones)# +# 4) note the following values from the App screen: clientID, Secret# +# Enter your app API info into R# +options(sm_client_id = 'YourMasheryDeveloperUsername')# +options(sm_secret = 'YourAPISecret')# +# +# Get a long lasting oauth token. This function completes the OAuth handshake# +# and saves a long lasting token on the computer. It needs to be done only once# +smlogin()# +# +# Lookup userdetails to test API# +users <- userdetails()# +# +# Show a list of surveys# +sl <- surveylist()# +# +# Display the list of surveys# +# (This shows each survey using the print.sm_survey function which overrides the standard# +# print function)# +sl# +# +# Get and display more details for the first survey on the list# +# (This uses the same print.sm_survey function but has more data to display)# +sd1 <- surveydetails(sl[[1]])# +# +# Get and display survey deatils including the details on the survey questions# +sd1.q <- surveydetails(sl[[1]], question_details = TRUE) +options(sm_client_id = 'xNrzuB4PTCaaQM326voPgA') +options(sm_secret = '247980397240465379297676830494544653711') +smlogin() +getOption(sm_oauth_token) +oauth_token = getOption('sm_oauth_token'), +oauth_token = getOption('sm_oauth_token') +oauth_token +# Lookup userdetails to test API# +users <- userdetails()# +# +# Show a list of surveys# +sl <- surveylist()# +# +# Display the list of surveys# +# (This shows each survey using the print.sm_survey function which overrides the standard# +# print function)# +sl# +# +# Get and display more details for the first survey on the list# +# (This uses the same print.sm_survey function but has more data to display)# +sd1 <- surveydetails(sl[[1]])# +# +# Get and display survey deatils including the details on the survey questions# +sd1.q <- surveydetails(sl[[1]], question_details = TRUE) +users +# Get and display more details for the first survey on the list# +# (This uses the same print.sm_survey function but has more data to display)# +sd1 <- surveydetails(sl[[1]])# +sd1# +# +# Get and display survey deatils including the details on the survey questions# +sd1.q <- surveydetails(sl[[1]], question_details = TRUE)# +sd1.q +str(sd1.q) +getresponses <- function(# + survey,# + collector = NULL,# + bulk = FALSE,# + oauth_token = getOption('sm_oauth_token'),# + ...# +){# + if (inherits(survey, 'sm_survey')) {# + survey$id <- survey$id# + } else {# + stop("'survey' is not of class sm_survey")# + }# + if (!is.null(collector)) {# + if (bulk) {# + u <- paste('https://api.surveymonkey.net/v3/collectors/',collector$id,'/responses/bulk?', sep='') # + } else {# + u <- paste('https://api.surveymonkey.net/v3/collectors/',collector$id,'/responses?', sep='') # + }# + } else {# + if (bulk) {# + u <- paste('https://api.surveymonkey.net/v3/surveys/',survey$id,'/responses/bulk?', sep='') # + } else {# + u <- paste('https://api.surveymonkey.net/v3/surveys/',survey$id,'/responses?', sep='') # + }# + }# + if (!is.null(oauth_token)) {# + token <- paste('bearer', oauth_token)# + } else {# + stop("Must specify 'oauth_token'")# + }# + h <- add_headers(Authorization=token,# + 'Content-Type'='application/json')# + out <- GET(u, config = h, ...)# + stop_for_status(out)# + content <- parsed_content(out)# + # if (content$status != 0) {# + # warning("An error occurred: ",content$errmsg)# + # return(content)# + # } else {# + if (!is.null(content$data)) {# + lapply(content$data, `class<-`, "sm_response")# + # content$data <- lapply(content$data, `attr<-`, 'survey_id', survey)# + }# + return(structure(content, class = 'sm_response_list'))# +} +getresponses(sl[[1]]) +sl1.r <- getresponses(sl[[1]]) +sl1.r[[1]] +sl1.r[[2]] +sl1.r$data[[1]] +class(sl1.r$data[[1]]) +class(sl1.r) +str(sl1.r) +lapply(sl1.r$data, `class<-`, "sm_response") +getresponses +getresponses <- function(# + survey,# + collector = NULL,# + bulk = FALSE,# + oauth_token = getOption('sm_oauth_token'),# + ...# +){# + if (inherits(survey, 'sm_survey')) {# + survey$id <- survey$id# + } else {# + stop("'survey' is not of class sm_survey")# + }# + if (!is.null(collector)) {# + if (bulk) {# + u <- paste('https://api.surveymonkey.net/v3/collectors/',collector$id,'/responses/bulk?', sep='') # + } else {# + u <- paste('https://api.surveymonkey.net/v3/collectors/',collector$id,'/responses?', sep='') # + }# + } else {# + if (bulk) {# + u <- paste('https://api.surveymonkey.net/v3/surveys/',survey$id,'/responses/bulk?', sep='') # + } else {# + u <- paste('https://api.surveymonkey.net/v3/surveys/',survey$id,'/responses?', sep='') # + }# + }# + if (!is.null(oauth_token)) {# + token <- paste('bearer', oauth_token)# + } else {# + stop("Must specify 'oauth_token'")# + }# + h <- add_headers(Authorization=token,# + 'Content-Type'='application/json')# + out <- GET(u, config = h, ...)# + stop_for_status(out)# + content <- parsed_content(out)# + # if (content$status != 0) {# + # warning("An error occurred: ",content$errmsg)# + # return(content)# + # } else {# + if (!is.null(content$data)) {# + lapply(content$data, `class<-`, "sm_response")# + }# + structure(content, class = 'sm_response_list')# +} +sl1.r <- getresponses(sl[[1]]) +class(sl1.r) +sl1.r +str(sl1.r) +lapply(sl1.r$data, `class<-`, "sm_response") +is.null(sl1.r$data) +!is.null(sl1.r$data) +getresponses <- function(# + survey,# + collector = NULL,# + bulk = FALSE,# + oauth_token = getOption('sm_oauth_token'),# + ...# +){# + if (inherits(survey, 'sm_survey')) {# + survey$id <- survey$id# + } else {# + stop("'survey' is not of class sm_survey")# + }# + if (!is.null(collector)) {# + if (bulk) {# + u <- paste('https://api.surveymonkey.net/v3/collectors/',collector$id,'/responses/bulk?', sep='') # + } else {# + u <- paste('https://api.surveymonkey.net/v3/collectors/',collector$id,'/responses?', sep='') # + }# + } else {# + if (bulk) {# + u <- paste('https://api.surveymonkey.net/v3/surveys/',survey$id,'/responses/bulk?', sep='') # + } else {# + u <- paste('https://api.surveymonkey.net/v3/surveys/',survey$id,'/responses?', sep='') # + }# + }# + if (!is.null(oauth_token)) {# + token <- paste('bearer', oauth_token)# + } else {# + stop("Must specify 'oauth_token'")# + }# + h <- add_headers(Authorization=token,# + 'Content-Type'='application/json')# + out <- GET(u, config = h, ...)# + stop_for_status(out)# + content <- parsed_content(out)# + if (!is.null(content$data)) {# + lapply(content$data, `class<-`, "sm_response")# + }# + structure(content, class = 'sm_response_list')# +} +getresponses +getresponses(sl[[2]]) +sl2.r <- getresponses(sl[[2]]) +class(sl2.r) +class(sl2.r$data) +class(sl2.r$data[[1]]) +sl2.r$data +sl2.r$data[[1]] +lapply(sl2.r$data, `class<-`, "sm_response") +# Show the responses to a survey# +sl1.r <- getresponses(sl[[1]]) +sl1.r +surveyquestions(sl[[1]]) +sl1.q <- surveyquestions(sl[[1]]) +class(sl1.q) +str(sl1.q) +surveypreview(sl[[1]]) +sd1 +sl1.q <- surveyquestions() +sl1.q <- surveyquestions(sl[[1]]) +sl1.q +sl1.rd <- getresponses(sl[[1]], bulk = TRUE) +sl1.rd +sl1.rd <- getresponses(sl[[1]], bulk = TRUE) +q() +# RMonkey library demo# +## +# Sean Fahey# +# 2016-12-28# +## +# This program shows how the RMonkey library can be used to access SurveyMonkey data# +# via API V3.# +## +# +# load needed libraries# +library(curl)# +library(httr)# +# +# Load the latest Rmonkey library from github# +if(!require("devtools")) {# + install.packages("devtools")# + library("devtools") +} +install_github("seanofahey/Rmonkey")# +library("Rmonkey") +# RMonkey library demo# +## +# Sean Fahey# +# 2016-12-28# +## +# This program shows how the RMonkey library can be used to access SurveyMonkey data# +# via API V3.# +## +# +# load needed libraries# +library(curl)# +library(httr)# +# +# Load the latest Rmonkey library from github# +if(!require("devtools")) {# + install.packages("devtools")# + library("devtools")} +install_github("seanofahey/Rmonkey")# +library("Rmonkey") +smlogin +q() +getwd() +setwd(../) +setwd("../") +dir() +setwd("../") +dir() +setwd("../") +dir() +setwd("Users/") +dir() +setwd("sean.fahey/") +dir() +setwd("Rmonkey/") +dir() +# RMonkey library demo# +## +# Sean Fahey# +# 2016-12-28# +## +# This program shows how the RMonkey library can be used to access SurveyMonkey data# +# via API V3.# +## +# +# load needed libraries# +library(curl)# +library(httr)# +library(jsonlite)# +library(dplyr)# +# +# Load the latest Rmonkey library from github# +if(!require("devtools")) {# + install.packages("devtools")# + library("devtools")# +}# +install_github("seanofahey/Rmonkey")# +library("Rmonkey") +ls(pos = package:"Rmonkey") +ls(pos = "package:Rmonkey") +q() diff --git a/NEWS b/NEWS index 3e87d81..ef264eb 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,14 @@ +# CHANGES TO Rmonkey 0.5 # + +## SIGNIFICANT USER-VISIBLE CHANGES ## +* Rebuilt several functions to work with SurkeyMonkey API V3 (smlogin, userdetails, surveylist, surveydetails) +* + +## BUG FIXES ## + +## DOCUMENTATION ## +* added Roxygen comments to new functions + # CHANGES TO Rmonkey 0.4 # ## SIGNIFICANT USER-VISIBLE CHANGES ## From eb3faff5ad5d6c34dac4b32d626230f5aecb0eb2 Mon Sep 17 00:00:00 2001 From: Sean Fahey Date: Mon, 2 Jan 2017 19:20:25 -0500 Subject: [PATCH 55/76] added roxygen @export tag --- NAMESPACE | 3 +++ R/smlogin.r | 1 + R/surveylist.r | 1 + R/userdetails.r | 1 + 4 files changed, 6 insertions(+) diff --git a/NAMESPACE b/NAMESPACE index 6ae9268..2adfae9 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,2 +1,5 @@ # Generated by roxygen2: do not edit by hand +export(smlogin) +export(surveylist) +export(userdetails) diff --git a/R/smlogin.r b/R/smlogin.r index cf29c63..91431c9 100644 --- a/R/smlogin.r +++ b/R/smlogin.r @@ -13,6 +13,7 @@ #' @param redirect_uri Default value is \url{http://localhost:1410}. No other value is allowed. This must be the redirect URL registered for your application in your Survey Monkey developer account. #' @param response_type Default value is \code{code}. No other values are allowed. #' @return oauth_token +#' @export smlogin smlogin <- function(client_id = getOption('sm_client_id'), secret = getOption('sm_secret'), diff --git a/R/surveylist.r b/R/surveylist.r index 8ba4459..f233a0e 100644 --- a/R/surveylist.r +++ b/R/surveylist.r @@ -16,6 +16,7 @@ #' @param oauth_token Your OAuth 2.0 token, as generated by \code{smlogin}. By default, retrieved from \code{getOption('sm_oauth_token')}. #' @return A list of objects of class \code{sm_survey}. #' @references SurveyMonkey API V3 at \url{https://developer.surveymonkey.com/api/v3/#surveys} +#' @export surveylist surveylist <- function( page = NULL, diff --git a/R/userdetails.r b/R/userdetails.r index 59d896f..da34da1 100644 --- a/R/userdetails.r +++ b/R/userdetails.r @@ -9,6 +9,7 @@ #' @param oauth_token Your OAuth 2.0 token, as generated by \code{\link{smlogin}}. By default, retrieved from \code{getOption('sm_oauth_token')}. #' @return An object of class \code{sm_userdetails}. #' @references SurveyMonkey API V3 at \url{https://developer.surveymonkey.com/api/v3/#users-me} +#' @export userdetails userdetails <- function(oauth_token = getOption('sm_oauth_token'), ...) { From 2672bcdd73d8ed2d050178bc9fed64a196c6fb73 Mon Sep 17 00:00:00 2001 From: Sean Fahey Date: Thu, 5 Jan 2017 11:37:31 -0500 Subject: [PATCH 56/76] updated Roxygen documentation for functions and ran roxygenize to refresh manual pages and NAMESPACE file. Updated function calls in code to explicitly state package::function. Changed internal variable "content" to "parsed_content" to avoid confusion with function "content" --- NAMESPACE | 6 ++++ R/getresponses.r | 41 +++++++++++++++++------- R/smlogin.r | 6 ++-- R/surveydetails.r | 37 ++++++++++++++++++---- R/surveylist.r | 13 ++++---- R/userdetails.r | 10 +++--- RMonkey Demo.R | 1 + man/getresponses.Rd | 74 ++++++++++++++++++++------------------------ man/surveydetails.Rd | 58 ++++++++++++++-------------------- man/surveylist.Rd | 2 +- 10 files changed, 140 insertions(+), 108 deletions(-) diff --git a/NAMESPACE b/NAMESPACE index 2adfae9..863f526 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,5 +1,11 @@ # Generated by roxygen2: do not edit by hand +export(getresponses) +export(print.sm_response) +export(print.sm_survey) export(smlogin) +export(surveydetails) export(surveylist) +export(surveypreview) +export(surveyquestions) export(userdetails) diff --git a/R/getresponses.r b/R/getresponses.r index 465b770..47d788e 100644 --- a/R/getresponses.r +++ b/R/getresponses.r @@ -1,6 +1,23 @@ -# getresponses.r -# -# This function returns details on SurveyMonkey responses +#' getresponses +#' +#' Get responses for a SurveyMonkey survey +#' +#' @param survey A sm_survey object, as retrieved by \code{surveylist()}. +#' @param collector A sm_collector object, as retrieved by \code{collectorlist}. By default = NULL +#' @param bulk A logical variable to indicate if list response should include a list of full expanded responses, including answers to all questions. By default = FALSE +#' @param page Integer number to select which page of resources to return. By default is 1. +#' @param Integer number to set the number of surveys to return per page. By default, is 50 surveys per page. +#' @param start_created_at Date string used to select surveys created after this date. By default is NULL. +#' @param end_created_at Date string used to select surveys modified before this date. By default is NULL. +#' @param start_modified_at Date string used to select surveys last modified after this date. By default is NULL. +#' @param end_modified_at Date string used to select surveys modified before this date. By default is NULL. +#' @param sort_order String used to set the sort order for returned surveys: 'ASC’ or 'DESC’. By default, DESC. +#' @param sort_by String value of field used to sort returned survey list: ‘title’, 'date_modified’, or 'num_responses’. By default, date_modified. +#' @param oauth_token Your OAuth 2.0 token, as generated by \code{smlogin}. By default, retrieved from \code{getOption('sm_oauth_token')}. +#' @return A list of object of class {sm_response} +#' @references SurveyMonkey API V3 at \url{https://developer.surveymonkey.com/api/v3/#survey-responses} +#' @export getresponses +#' @export print.sm_response # # get a set of bulk responses (this will get 50 responses with the following structure: # $per_page : int = total number of responses per page @@ -56,7 +73,7 @@ getresponses <- function( end_created_at = NULL, start_modified_at = NULL, end_modified_at = NULL, - sort_order = 'ASC', + sort_order = 'DESC', sort_by = 'date_modified', oauth_token = getOption('sm_oauth_token'), ... @@ -111,16 +128,16 @@ getresponses <- function( } else { b <- b[!nulls] } - h <- add_headers(Authorization=token, + h <- httr::add_headers(Authorization=token, 'Content-Type'='application/json') - out <- GET(u, config = h, ..., query = b) - stop_for_status(out) - content <- content(out, as = 'parsed') - if (!is.null(content$data)) { - lapply(content$data, `class<-`, "sm_response") + out <- httr::GET(u, config = h, ..., query = b) + httr::stop_for_status(out) + parsed_content <- httr::content(out, as = 'parsed') + if (!is.null(parsed_content$data)) { + lapply(parsed_content$data, `class<-`, "sm_response") } - structure(content, class = 'sm_response_list') - return(content$data) + structure(parsed_content, class = 'sm_response_list') + return(parsed_content$data) } print.sm_response <- function(x, ...){ diff --git a/R/smlogin.r b/R/smlogin.r index 91431c9..cc97fc9 100644 --- a/R/smlogin.r +++ b/R/smlogin.r @@ -27,15 +27,15 @@ smlogin <- function(client_id = getOption('sm_client_id'), redirect_uri = redirect_uri, client_id = client_id) a <- paste(names(a), - curl_escape(a), + curl::curl_escape(a), sep = '=', collapse = '&') e <- structure(list(authorize = 'https://api.surveymonkey.net/oauth/authorize', access = 'https://api.surveymonkey.net/oauth/token'), class = 'oauth_endpoint') e$authorize <- paste(e$authorize, a, sep = '?') - smapp <- oauth_app('surveymonkey', client_id, secret) - token <- oauth2.0_token(e, smapp, use_oob = FALSE, cache = FALSE) + smapp <- httr::oauth_app('surveymonkey', client_id, secret) + token <- httr::oauth2.0_token(e, smapp, use_oob = FALSE, cache = FALSE) if ('error' %in% names(token$credentials)) { warning('OAuth error ', token$credentials$error, ': ', token$credentials$error_description, sep = '') } else diff --git a/R/surveydetails.r b/R/surveydetails.r index ec501fe..bdc2340 100644 --- a/R/surveydetails.r +++ b/R/surveydetails.r @@ -1,4 +1,29 @@ -# surveydetails +#' surveydetails +#' +#' Get detailed information about a survey +#' +#' \code{sureydetails()}This function calls the SurveyMonkey API using the current oauth token and returns +#' details about a survey including the number of pages, questions, answer choices, +#' urls, etc... +#' +#' \code{surveyquestions()}This function extracts a named character vector of question wordings +#' from a \dQuote{sm_survey} object. This can be useful for creating a codebook of responses or for mapping +#' responses (from \code{\link{getresponses}}) to the original question wordings. +#' +#' \code{surveypreview} opens a survey preview url in a web browser via \code{\link[utils]{browseURL}}. +#' +#' @param survey A sm_survey object, as retrieved by \code{surveylist()}. +#' @param question_detail A logical value to indicate whether to include details on questions and answer choices. By default = TRUE. +#' @param oauth_token Your OAuth 2.0 token, as generated by \code{smlogin}. By default, retrieved from \code{getOption('sm_oauth_token')}. +#' +#' @return A list of objects of class \code{sm_survey}. +#' @references SurveyMonkey API V3 at \url{https://developer.surveymonkey.com/api/v3/#surveys} +#' @export surveydetails +#' @export print.sm_survey +#' @export surveyquestions +#' @export surveypreview +#' @keywords +#' # # This function returns details about a SurveyMonkey survey in the list structure based on the # JSON response format @@ -82,12 +107,12 @@ surveydetails <- function( } else stop("Must specify 'oauth_token'. Try using smlogin() first.") - h <- add_headers(Authorization=token, + h <- httr::add_headers(Authorization=token, 'Content-Type'='application/json') - out <- GET(u, config = h, ...) - stop_for_status(out) - content <- content(out, as = 'parsed') - structure(content, class = "sm_survey") + out <- httr::GET(u, config = h, ...) + httr::stop_for_status(out) + parsed_content <- httr::content(out, as = 'parsed') + structure(parsed_content, class = "sm_survey") } surveyquestions <- function(survey){ diff --git a/R/surveylist.r b/R/surveylist.r index f233a0e..4d3293e 100644 --- a/R/surveylist.r +++ b/R/surveylist.r @@ -5,7 +5,7 @@ #' This function calls the SurveyMonkey API using the current oauth token and returns #' a list of surveys filtered by the parameters entered. #' -#' @param page Integer numebr to select which page of resources to return. By default is 1. +#' @param page Integer number to select which page of resources to return. By default is 1. #' @param per_page Integer number to set the number of surveys to return per page. By default, is 50 surveys per page. #' @param sort_by String used to sort returned survey list: ‘title’, 'date_modified’, or 'num_responses’. By default, date_modified. #' @param sort_order String used to set the sort order for returned surveys: 'ASC’ or 'DESC’. By default, DESC. @@ -18,6 +18,7 @@ #' @references SurveyMonkey API V3 at \url{https://developer.surveymonkey.com/api/v3/#surveys} #' @export surveylist + surveylist <- function( page = NULL, per_page = NULL, @@ -53,11 +54,11 @@ surveylist <- function( b <- NULL else b <- b[!nulls] - h <- add_headers(Authorization=token, + h <- httr::add_headers(Authorization=token, 'Content-Type'='application/json') - out <- GET(u, config = h, ..., query = b) - stop_for_status(out) - content <- content(out, as = 'parsed') - sl <- content$data + out <- httr::GET(u, config = h, ..., query = b) + httr::stop_for_status(out) + parsed_content <- httr::content(out, as = 'parsed') + sl <- parsed_content$data lapply(sl, `class<-`, 'sm_survey') } \ No newline at end of file diff --git a/R/userdetails.r b/R/userdetails.r index da34da1..673834f 100644 --- a/R/userdetails.r +++ b/R/userdetails.r @@ -18,10 +18,10 @@ userdetails <- function(oauth_token = getOption('sm_oauth_token'), ...) { token <- paste('bearer', oauth_token) else stop("Must specify 'oauth_token'. Try smlogin() first to get a token.") - out <- GET(u, config = add_headers(Authorization = token, + out <- httr::GET(u, config = httr::add_headers(Authorization = token, 'Content-Type' = 'application/json')) - stop_for_status(out) - content <- content(out, as='parsed') - structure(content, class = "sm_userdetails") - return(content) + httr::stop_for_status(out) + parsed_content <- httr::content(out, as='parsed') + structure(parsed_content, class = "sm_userdetails") + return(parsed_content) } \ No newline at end of file diff --git a/RMonkey Demo.R b/RMonkey Demo.R index c05d1a6..c933025 100644 --- a/RMonkey Demo.R +++ b/RMonkey Demo.R @@ -12,6 +12,7 @@ library(curl) library(httr) library(jsonlite) library(dplyr) +library(httpuv) # Load the latest Rmonkey library from github if(!require("devtools")) { diff --git a/man/getresponses.Rd b/man/getresponses.Rd index 983a212..ac07353 100644 --- a/man/getresponses.Rd +++ b/man/getresponses.Rd @@ -1,52 +1,46 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/getresponses.r \name{getresponses} \alias{getresponses} -\alias{getallresponses} -\alias{print.sm_response} -\title{Get responses} -\description{Get responses for a survey} +\title{getresponses} \usage{ -getresponses(respondents, survey, - api_key = getOption('sm_api_key'), - oauth_token = getOption('sm_oauth_token'), ...) - -getallresponses(survey, api_key, oauth_token, wait = 0, ...) +getresponses(survey, collector = NULL, bulk = FALSE, page = NULL, + per_page = NULL, start_created_at = NULL, end_created_at = NULL, + start_modified_at = NULL, end_modified_at = NULL, sort_order = "DESC", + sort_by = "date_modified", oauth_token = getOption("sm_oauth_token"), ...) } \arguments{ -\item{respondents}{A vector containing up to 100 respondent ID numbers, possibly returned by \code{\link{respondentlist}}.} -\item{survey}{A Survey Monkey survey ID number (or an object of class \dQuote{sm_survey} from which it can be extracted), possibly returned by \code{\link{surveylist}}. If missing, the function will try to find an appropriate value in \code{respondents}.} -\item{api_key}{Your API key. By default, retrieved from \code{getOption('sm_api_key')}.} -\item{oauth_token}{Your OAuth 2.0 token, as generated by \code{\link{smlogin}}. By default, retrieved from \code{getOption('sm_oauth_token')}.} -\item{wait}{A time, in seconds, to wait between API calls. This can be used to throttle API request in order to avoid going over limits.} -\item{...}{Other arguments passed to \code{\link[httr]{POST}}.} -} -\details{Retrieves response data for requested respondents to a specified survey. \code{getresponses()} retrieves a list structure that can be further parsed using an \code{as.data.frame} method. \code{getallresponses()} returns a data.frame of all responses for a survey automatically using just the survey ID. +\item{survey}{A sm_survey object, as retrieved by \code{surveylist()}.} -Note: Text responses returned are truncated after 32,768 characters. +\item{collector}{A sm_collector object, as retrieved by \code{collectorlist}. By default = NULL} -Note: Surveys with over 500,000 responses are not available via the API currently.} -\value{ -For \code{getresponses()}, a list (of class \code{sm_response_list}) containing one or more objects of class \code{sm_response}. +\item{bulk}{A logical variable to indicate if list response should include a list of full expanded responses, including answers to all questions. By default = FALSE} + +\item{page}{Integer number to select which page of resources to return. By default is 1.} + +\item{start_created_at}{Date string used to select surveys created after this date. By default is NULL.} + +\item{end_created_at}{Date string used to select surveys modified before this date. By default is NULL.} + +\item{start_modified_at}{Date string used to select surveys last modified after this date. By default is NULL.} + +\item{end_modified_at}{Date string used to select surveys modified before this date. By default is NULL.} -For \code{getallresponses()}, a data.frame. +\item{sort_order}{String used to set the sort order for returned surveys: 'ASC’ or 'DESC’. By default, DESC.} + +\item{sort_by}{String value of field used to sort returned survey list: ‘title’, 'date_modified’, or 'num_responses’. By default, date_modified.} + +\item{oauth_token}{Your OAuth 2.0 token, as generated by \code{smlogin}. By default, retrieved from \code{getOption('sm_oauth_token')}.} + +\item{Integer}{number to set the number of surveys to return per page. By default, is 50 surveys per page.} } -\references{ -\url{https://developer.surveymonkey.com/mashery/get_responses} +\value{ +A list of object of class {sm_response} } -\author{Thomas J. Leeper} -%\note{} -%\seealso{} -\examples{ -\dontrun{ -smlogin() -s <- surveylist() -r <- respondentlist(s[[1]]) - -# get one response -getresponses(r[[1]]) - -# get all responses (up to 100) -g <- getresponses(r) -as.data.frame(g) # convert to data.frame +\description{ +Get responses for a SurveyMonkey survey } +\references{ +SurveyMonkey API V3 at \url{https://developer.surveymonkey.com/api/v3/#survey-responses} } -%\keyword{} + diff --git a/man/surveydetails.Rd b/man/surveydetails.Rd index 5664151..ed70a54 100644 --- a/man/surveydetails.Rd +++ b/man/surveydetails.Rd @@ -1,50 +1,38 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/surveydetails.r \name{surveydetails} \alias{surveydetails} -\alias{surveyquestions} -\alias{surveypreview} -\title{Get survey details} -\description{Get details about a specific survey} +\title{surveydetails} \usage{ -surveydetails(survey, api_key = getOption('sm_api_key'), - oauth_token = getOption('sm_oauth_token'), ...) +surveydetails(survey, question_details = TRUE, + oauth_token = getOption("sm_oauth_token"), ...) +} +\arguments{ +\item{survey}{A sm_survey object, as retrieved by \code{surveylist()}.} -surveyquestions(survey, details, api_key = getOption('sm_api_key'), - oauth_token = getOption('sm_oauth_token'), ...) +\item{oauth_token}{Your OAuth 2.0 token, as generated by \code{smlogin}. By default, retrieved from \code{getOption('sm_oauth_token')}.} -surveypreview(details) +\item{question_detail}{A logical value to indicate whether to include details on questions and answer choices. By default = TRUE.} } -\arguments{ -\item{survey}{A Survey Monkey survey ID number (or an object of class \dQuote{sm_survey} from which it can be extracted), possibly returned by \code{\link{surveylist}}. For \code{surveyquestions}, either \code{survey} or \code{details} must be supplied.} -\item{details}{For \code{surveyquestions}, either \code{survey} or \code{details} must be supplied. \code{details} must be supplied as an object of class \code{sm_surveydetails}. If missing, a \code{\link{surveydetails}} request will be executed for the survey supplied in the \code{survey} argument.} -\item{api_key}{Your API key. By default, retrieved from \code{getOption('sm_api_key')}.} -\item{oauth_token}{Your OAuth 2.0 token, as generated by \code{\link{smlogin}}. By default, retrieved from \code{getOption('sm_oauth_token')}.} -\item{...}{Other arguments passed to \code{\link[httr]{POST}}.} +\value{ +A list of objects of class \code{sm_survey}. +} +\description{ +Get detailed information about a survey } \details{ -\code{surveydetails} retrieves details of a specified survey (e.g., question metadata). Surveys with over 200 survey pages will not be returned. Surveys with over 200 questions will not be returned. +\code{sureydetails()}This function calls the SurveyMonkey API using the current oauth token and returns +details about a survey including the number of pages, questions, answer choices, +urls, etc... -\code{surveyquestions} extracts a named character vector of question wordings from a \dQuote{sm_surveydetails} object. This can be useful for creating a codebook of responses or for mapping responses (from \code{\link{getresponses}}) to the original question wordings. +\code{surveyquestions()}This function extracts a named character vector of question wordings +from a \dQuote{sm_survey} object. This can be useful for creating a codebook of responses or for mapping +responses (from \code{\link{getresponses}}) to the original question wordings. \code{surveypreview} opens a survey preview url in a web browser via \code{\link[utils]{browseURL}}. } -\value{For \code{surveydetails}, a list of objects of class \code{sm_survey}. For \code{surveyquestions}, a character vector with Survey Monkey question ID values as names.} \references{ -\url{https://developer.surveymonkey.com/mashery/get_survey_details} +SurveyMonkey API V3 at \url{https://developer.surveymonkey.com/api/v3/#surveys} } -\author{Thomas J. Leeper} -%\note{} -%\seealso{} -\examples{ -\dontrun{ -smlogin() -s <- surveylist() +\keyword{} -# retrieve all survey details -d <- surveydetails(s[[1]]$survey_id) -d - -# retrieve question wordings -surveyquestions(d) -} -} -%\keyword{} diff --git a/man/surveylist.Rd b/man/surveylist.Rd index 036266f..8449230 100644 --- a/man/surveylist.Rd +++ b/man/surveylist.Rd @@ -10,7 +10,7 @@ surveylist(page = NULL, per_page = NULL, sort_by = NULL, ...) } \arguments{ -\item{page}{Integer numebr to select which page of resources to return. By default is 1.} +\item{page}{Integer number to select which page of resources to return. By default is 1.} \item{per_page}{Integer number to set the number of surveys to return per page. By default, is 50 surveys per page.} From d5d4258eac4861f463dbe4794466ad973beb25dc Mon Sep 17 00:00:00 2001 From: Sean Fahey Date: Thu, 5 Jan 2017 11:46:35 -0500 Subject: [PATCH 57/76] added Roxygen documentation --- R/surveyquestiondf.R | 11 ++++++++--- man/surveyquestiondf.Rd | 18 ++++++++++++++++++ 2 files changed, 26 insertions(+), 3 deletions(-) create mode 100644 man/surveyquestiondf.Rd diff --git a/R/surveyquestiondf.R b/R/surveyquestiondf.R index 5a8a4f5..3c7e89e 100644 --- a/R/surveyquestiondf.R +++ b/R/surveyquestiondf.R @@ -1,6 +1,11 @@ -# @ surveyquestiondf.r -# -# This program creates a data frame from the survey questions and answers +#' surveyquestiondf +#' +#' Creates a data frame from the survey questions and answers +#' +#' @param survey A sm_survey object, as retrieved by \code{surveylist()}. +#' @return A data frame with one row per question/subquestion/answer choice +#' @export surveyquestiondf +#' surveyquestiondf <- function(survey) { df <- data.frame() sd <- surveydetails(survey, question_details = TRUE) diff --git a/man/surveyquestiondf.Rd b/man/surveyquestiondf.Rd new file mode 100644 index 0000000..7bfbcb0 --- /dev/null +++ b/man/surveyquestiondf.Rd @@ -0,0 +1,18 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/surveyquestiondf.R +\name{surveyquestiondf} +\alias{surveyquestiondf} +\title{surveyquestiondf} +\usage{ +surveyquestiondf(survey) +} +\arguments{ +\item{survey}{A sm_survey object, as retrieved by \code{surveylist()}.} +} +\value{ +A data frame with one row per question/subquestion/answer choice +} +\description{ +Creates a data frame from the survey questions and answers +} + From 736b2d92bce3df478b858667464a27fc2e3b4442 Mon Sep 17 00:00:00 2001 From: Sean Fahey Date: Thu, 5 Jan 2017 11:46:35 -0500 Subject: [PATCH 58/76] added Roxygen documentation --- NAMESPACE | 1 + R/surveyquestiondf.R | 11 ++++++++--- man/surveyquestiondf.Rd | 18 ++++++++++++++++++ 3 files changed, 27 insertions(+), 3 deletions(-) create mode 100644 man/surveyquestiondf.Rd diff --git a/NAMESPACE b/NAMESPACE index 863f526..663f123 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -7,5 +7,6 @@ export(smlogin) export(surveydetails) export(surveylist) export(surveypreview) +export(surveyquestiondf) export(surveyquestions) export(userdetails) diff --git a/R/surveyquestiondf.R b/R/surveyquestiondf.R index 5a8a4f5..3c7e89e 100644 --- a/R/surveyquestiondf.R +++ b/R/surveyquestiondf.R @@ -1,6 +1,11 @@ -# @ surveyquestiondf.r -# -# This program creates a data frame from the survey questions and answers +#' surveyquestiondf +#' +#' Creates a data frame from the survey questions and answers +#' +#' @param survey A sm_survey object, as retrieved by \code{surveylist()}. +#' @return A data frame with one row per question/subquestion/answer choice +#' @export surveyquestiondf +#' surveyquestiondf <- function(survey) { df <- data.frame() sd <- surveydetails(survey, question_details = TRUE) diff --git a/man/surveyquestiondf.Rd b/man/surveyquestiondf.Rd new file mode 100644 index 0000000..7bfbcb0 --- /dev/null +++ b/man/surveyquestiondf.Rd @@ -0,0 +1,18 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/surveyquestiondf.R +\name{surveyquestiondf} +\alias{surveyquestiondf} +\title{surveyquestiondf} +\usage{ +surveyquestiondf(survey) +} +\arguments{ +\item{survey}{A sm_survey object, as retrieved by \code{surveylist()}.} +} +\value{ +A data frame with one row per question/subquestion/answer choice +} +\description{ +Creates a data frame from the survey questions and answers +} + From 12fc34c1f1139cec566bafd5b2d330fc4c179c64 Mon Sep 17 00:00:00 2001 From: Sean Fahey Date: Thu, 5 Jan 2017 11:54:58 -0500 Subject: [PATCH 59/76] updated Roxygen code for as.data.frame.surveyresponses --- NAMESPACE | 1 + R/as.data.frame.surveyresponses.r | 12 ++++++++---- man/as.data.frame.surveyresponses.Rd | 18 ++++++++++++++++++ 3 files changed, 27 insertions(+), 4 deletions(-) create mode 100644 man/as.data.frame.surveyresponses.Rd diff --git a/NAMESPACE b/NAMESPACE index 663f123..7a959ae 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,5 +1,6 @@ # Generated by roxygen2: do not edit by hand +export(as.data.frame.surveyresponses) export(getresponses) export(print.sm_response) export(print.sm_survey) diff --git a/R/as.data.frame.surveyresponses.r b/R/as.data.frame.surveyresponses.r index 5e870be..70fdd9e 100644 --- a/R/as.data.frame.surveyresponses.r +++ b/R/as.data.frame.surveyresponses.r @@ -1,7 +1,11 @@ -# as.data.frame.surveyresponses -# -# This function extracts data from the survey responses data set and formats it as -# a data frame for analysis +#' as.data.frame.surveyresponses +#' +#' Extracts data from the survey responses data set and formats it as a data frame for analysis +#' +#' @param survey A sm_survey object, as retrieved by \code{surveylist()}. +#' @return A data frame with survey responses +#' @export as.data.frame.surveyresponses + as.data.frame.surveyresponses <- function(survey) { df <- data.frame() diff --git a/man/as.data.frame.surveyresponses.Rd b/man/as.data.frame.surveyresponses.Rd new file mode 100644 index 0000000..7dc78e8 --- /dev/null +++ b/man/as.data.frame.surveyresponses.Rd @@ -0,0 +1,18 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/as.data.frame.surveyresponses.r +\name{as.data.frame.surveyresponses} +\alias{as.data.frame.surveyresponses} +\title{as.data.frame.surveyresponses} +\usage{ +\method{as.data.frame}{surveyresponses}(survey) +} +\arguments{ +\item{survey}{A sm_survey object, as retrieved by \code{surveylist()}.} +} +\value{ +A data frame with survey responses +} +\description{ +Extracts data from the survey responses data set and formats it as a data frame for analysis +} + From 8494c735c3aa1959c72f1d9ba52da024d8fba31d Mon Sep 17 00:00:00 2001 From: Sean Fahey Date: Thu, 5 Jan 2017 11:59:15 -0500 Subject: [PATCH 60/76] updated to comment out libraries that should install automatically with package --- RMonkey Demo.R | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/RMonkey Demo.R b/RMonkey Demo.R index c933025..5deda56 100644 --- a/RMonkey Demo.R +++ b/RMonkey Demo.R @@ -8,11 +8,11 @@ # # load needed libraries -library(curl) -library(httr) -library(jsonlite) -library(dplyr) -library(httpuv) +# library(curl) +# library(httr) +# library(jsonlite) +# library(dplyr) +# library(httpuv) # Load the latest Rmonkey library from github if(!require("devtools")) { From dce0e0b10b3966f9d1d66369f4dce7c69d9e4375 Mon Sep 17 00:00:00 2001 From: Sean Fahey Date: Thu, 5 Jan 2017 11:59:15 -0500 Subject: [PATCH 61/76] updated to comment out libraries that should install automatically with package --- RMonkey Demo.R | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/RMonkey Demo.R b/RMonkey Demo.R index c933025..4f4a6b0 100644 --- a/RMonkey Demo.R +++ b/RMonkey Demo.R @@ -8,11 +8,10 @@ # # load needed libraries -library(curl) -library(httr) -library(jsonlite) +# library(curl) +# library(httr) +# library(jsonlite) library(dplyr) -library(httpuv) # Load the latest Rmonkey library from github if(!require("devtools")) { From 59781bb4c1a23edc2053b46a33d0ec2810006825 Mon Sep 17 00:00:00 2001 From: Sean Fahey Date: Sat, 7 Jan 2017 14:57:52 -0500 Subject: [PATCH 62/76] added capability to recurisvely query to get all responses --- R/as.data.frame.surveyresponses.r | 27 +++++++++++++++++++++++++-- R/getresponses.r | 28 ++++++++++++++++++++++++++-- RMonkey Demo.R | 16 +++++++++++++++- 3 files changed, 66 insertions(+), 5 deletions(-) diff --git a/R/as.data.frame.surveyresponses.r b/R/as.data.frame.surveyresponses.r index 70fdd9e..eb3caeb 100644 --- a/R/as.data.frame.surveyresponses.r +++ b/R/as.data.frame.surveyresponses.r @@ -9,7 +9,8 @@ as.data.frame.surveyresponses <- function(survey) { df <- data.frame() - sr <- getresponses(survey, bulk = TRUE) + sr <- getresponses(survey, bulk = TRUE, all_page = TRUE) + sq <- surveyquestiondf(survey) survey_id <- survey$id # Iterate through responses @@ -55,7 +56,29 @@ as.data.frame.surveyresponses <- function(survey) { } } } - return(df) + + # join responses to question data + df <- dplyr::left_join (df, sq) + + # Combine the two question headers to make a single one + df$question_text_full <- + ifelse ( + df$question_type == 'multiple_choice', + paste(df$question_text, "-", df$answerchoice_text), + ifelse( + !is.na(df$subquestion_text), + paste(df$question_text, "-", df$subquestion_text), + paste(df$question_text) + ) + ) + + # Select only the columns for the final dataframe + df <- select(df, response_id, survey_id, collector_id, recipient_id, question_text_full, answerchoice_text) + + # Spread from column to tablular form + df_table <- spread(df, question_text_full, answerchoice_text) + + return(df_table) } # Future work diff --git a/R/getresponses.r b/R/getresponses.r index 16acdc4..4488e0b 100644 --- a/R/getresponses.r +++ b/R/getresponses.r @@ -67,7 +67,8 @@ getresponses <- function( survey, collector = NULL, bulk = FALSE, - page = NULL, + page = 1, + all_pages = FALSE, per_page = NULL, start_created_at = NULL, end_created_at = NULL, @@ -113,6 +114,7 @@ getresponses <- function( if (inherits(end_modified_at, "POSIXct") | inherits(end_modified_at, "Date")) { end_modified_at <- format(end_modified_at, "%Y-%m-%d %H:%M:%S", tz = "UTC") } + # need to add error checking for status b <- list(page = page, per_page = per_page, @@ -130,6 +132,8 @@ getresponses <- function( } h <- httr::add_headers(Authorization=token, 'Content-Type'='application/json') + + out <- httr::GET(u, config = h, ..., query = b) httr::stop_for_status(out) parsed_content <- httr::content(out, as = 'parsed') @@ -137,7 +141,27 @@ getresponses <- function( lapply(parsed_content$data, `class<-`, "sm_response") } structure(parsed_content, class = 'sm_response_list') - return(parsed_content$data) + + # build data frame from reponses + responses <- parsed_content$data + + # recursively get all responses if all_pages = TRUE + if (all_pages == TRUE & (!is.null(parsed_content$links[['next']]))) { + rnext <- getresponses (survey, + collector, + bulk, + page = page + 1, + all_pages, + per_page, + start_created_at, + end_created_at, + start_modified_at, + end_modified_at, + sort_order, + sort_by) + responses <- c(responses, rnext) + } + return (responses) } print.sm_response <- function(x, ...){ diff --git a/RMonkey Demo.R b/RMonkey Demo.R index 4f4a6b0..3eee605 100644 --- a/RMonkey Demo.R +++ b/RMonkey Demo.R @@ -99,5 +99,19 @@ s1.rd <- getresponses(sl[[1]], bulk = TRUE) s1.r_df <- as.data.frame.surveyresponses(sl[[1]]) str(s1.r_df) +### CREATE A CLEAN DATA FRAME (to move into a function) + # Join response data with question data to decode responses -s1.r_decode <- left_join (s1.r_df, s1_df) \ No newline at end of file +s1.r_decode <- left_join (s1.r_df, s1_df) + +# Combine the two question headers to make one +s1.r_decode$question_text_full <- ifelse(!is.na(s1.r_decode$subquestion_text), + paste(s1.r_decode$question_text, " - ", s1.r_decode$subquestion_text), + paste(s1.r_decode$question_text) +) + +# Select only the columns for the final dataframe +s1.r_decode_sm <- select(s1.r_decode, response_id, survey_id, collector_id, recipient_id, question_text_full, answerchoice_text) + +# Spread from column to tablular form +s1.r_table <- spread(s1.r_decode_sm, question_text_full, answerchoice_text) \ No newline at end of file From 331bece507119d2d6fb8fc0cf4ea9d0e5ab34928 Mon Sep 17 00:00:00 2001 From: Sean Fahey Date: Sun, 8 Jan 2017 18:21:46 -0500 Subject: [PATCH 63/76] added tidyr --- RMonkey Demo.R | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/RMonkey Demo.R b/RMonkey Demo.R index 3eee605..560cd29 100644 --- a/RMonkey Demo.R +++ b/RMonkey Demo.R @@ -12,6 +12,7 @@ # library(httr) # library(jsonlite) library(dplyr) +library(tidyr) # Load the latest Rmonkey library from github if(!require("devtools")) { @@ -51,7 +52,7 @@ sl str(sl[[1]]) # Return a specific list of surveys -sl <- surveylist(per_page = 100, sort_by = 'num_responses', sort_order = 'desc') +sl <- surveylist(per_page = 100, include = 'response_count', sort_by = 'num_responses', sort_order = 'desc') sl # Return surveys that have been modified since a certain date From a5d0e93940d02e5114ff0081fc48b12bf428370d Mon Sep 17 00:00:00 2001 From: Sean Fahey Date: Sun, 8 Jan 2017 18:43:42 -0500 Subject: [PATCH 64/76] added code to capture and include text to essay questions. Still need to manage text for "other" responses to multiple choice questions. --- R/as.data.frame.surveyresponses.r | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/R/as.data.frame.surveyresponses.r b/R/as.data.frame.surveyresponses.r index eb3caeb..6b02ec3 100644 --- a/R/as.data.frame.surveyresponses.r +++ b/R/as.data.frame.surveyresponses.r @@ -27,6 +27,7 @@ as.data.frame.surveyresponses <- function(survey) { # use a repeat loop to account for cases where there are no answer rows repeat { j <- j + 1 # increment counter first for array indexing + answertext <- NA if (is.null(i$answers[[j]]$row_id)) { subquestion_id <- NA } else { @@ -34,6 +35,9 @@ as.data.frame.surveyresponses <- function(survey) { } if (is.null(i$answers[[j]]$choice_id)) { answerchoice_id <- NA + if (is.null(i$answers[[j]]$other_id)) { + answertext <- i$answers[[j]]$text + } } else { answerchoice_id <- i$answers[[j]]$choice_id } @@ -46,6 +50,7 @@ as.data.frame.surveyresponses <- function(survey) { question_id, subquestion_id, answerchoice_id, + answertext, stringsAsFactors = FALSE, check.rows = FALSE ) @@ -72,6 +77,12 @@ as.data.frame.surveyresponses <- function(survey) { ) ) + # Remove rows with NA as question_text (these are the 'other' responses that still need to be managed) + df <- df[!is.na(df$question_text_full),] + + # for text responses replace the answerchoice field with the text + df$answerchoice_text[!is.null(df$answertext)] <- df$answertext + # Select only the columns for the final dataframe df <- select(df, response_id, survey_id, collector_id, recipient_id, question_text_full, answerchoice_text) From 94f29469de5c404d4428d7fe8f5d5f16480df2f5 Mon Sep 17 00:00:00 2001 From: Sean Fahey Date: Sun, 8 Jan 2017 18:47:26 -0500 Subject: [PATCH 65/76] renamed function --- R/surveyresponses.r | 98 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 R/surveyresponses.r diff --git a/R/surveyresponses.r b/R/surveyresponses.r new file mode 100644 index 0000000..6df4e2a --- /dev/null +++ b/R/surveyresponses.r @@ -0,0 +1,98 @@ +#' surveyresponses +#' +#' Extracts data from the survey responses data set and formats it as a data frame for analysis +#' +#' @param survey A sm_survey object, as retrieved by \code{surveylist()}. +#' @return A data frame with survey responses +#' @export surveyresponses + + +surveyresponses <- function(survey) { + df <- data.frame() + sr <- getresponses(survey, bulk = TRUE, all_page = TRUE) + sq <- surveyquestiondf(survey) + survey_id <- survey$id + + # Iterate through responses + for (h in sr) { + response_id <- h$id + recipient_id <- h$recipient_id + collector_id <- h$collector_id + questions <- + do.call('c', lapply(h$pages, function(x) + x[['questions']])) + for (i in questions) { + question_id <- i$id + j <- 0 + # use a repeat loop to account for cases where there are no answer rows + repeat { + j <- j + 1 # increment counter first for array indexing + answertext <- NA + if (is.null(i$answers[[j]]$row_id)) { + subquestion_id <- NA + } else { + subquestion_id <- i$answers[[j]]$row_id + } + if (is.null(i$answers[[j]]$choice_id)) { + answerchoice_id <- NA + if (is.null(i$answers[[j]]$other_id)) { + answertext <- i$answers[[j]]$text + } + } else { + answerchoice_id <- i$answers[[j]]$choice_id + } + newrow <- + data.frame( + response_id, + survey_id, + recipient_id, + collector_id, + question_id, + subquestion_id, + answerchoice_id, + answertext, + stringsAsFactors = FALSE, + check.rows = FALSE + ) + df <- rbind(df, newrow) + if (j >= length(i$answers)) { + break + } + } + } + } + + # join responses to question data + df <- dplyr::left_join (df, sq, by = c("survey_id", "question_id", "subquestion_id", "answerchoice_id")) + + # Combine the two question headers to make a single one + df$question_text_full <- + ifelse ( + df$question_type == 'multiple_choice', + paste(df$question_text, "-", df$answerchoice_text), + ifelse( + !is.na(df$subquestion_text), + paste(df$question_text, "-", df$subquestion_text), + paste(df$question_text) + ) + ) + + # Remove rows with NA as question_text (these are the 'other' responses that still need to be managed) + df <- df[!is.na(df$question_text_full),] + + # for text responses replace the answerchoice field with the text + df$answerchoice_text[!is.null(df$answertext)] <- df$answertext + + # Select only the columns for the final dataframe + df <- select(df, response_id, survey_id, collector_id, recipient_id, question_text_full, answerchoice_text) + + # Spread from column to tablular form + df_table <- spread(df, question_text_full, answerchoice_text) + + return(df_table) +} + + # Future work + # + + # do.call(rbind, lapply(i$answers, function(x) data.frame(answerchoice_id = x$choice_id, subquestion_id = x$row_id, stringsAsFactors = FALSE))) \ No newline at end of file From 7179586ddfa4dc00139ebb52eef588b9295ce5fe Mon Sep 17 00:00:00 2001 From: Sean Fahey Date: Sun, 8 Jan 2017 18:47:26 -0500 Subject: [PATCH 66/76] renamed function --- ....data.frame.surveyresponses.r => surveyresponses.r} | 8 ++++---- ...ata.frame.surveyresponses.Rd => surveyresponses.Rd} | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) rename R/{as.data.frame.surveyresponses.r => surveyresponses.r} (93%) rename man/{as.data.frame.surveyresponses.Rd => surveyresponses.Rd} (56%) diff --git a/R/as.data.frame.surveyresponses.r b/R/surveyresponses.r similarity index 93% rename from R/as.data.frame.surveyresponses.r rename to R/surveyresponses.r index 6b02ec3..6df4e2a 100644 --- a/R/as.data.frame.surveyresponses.r +++ b/R/surveyresponses.r @@ -1,13 +1,13 @@ -#' as.data.frame.surveyresponses +#' surveyresponses #' #' Extracts data from the survey responses data set and formats it as a data frame for analysis #' #' @param survey A sm_survey object, as retrieved by \code{surveylist()}. #' @return A data frame with survey responses -#' @export as.data.frame.surveyresponses +#' @export surveyresponses -as.data.frame.surveyresponses <- function(survey) { +surveyresponses <- function(survey) { df <- data.frame() sr <- getresponses(survey, bulk = TRUE, all_page = TRUE) sq <- surveyquestiondf(survey) @@ -63,7 +63,7 @@ as.data.frame.surveyresponses <- function(survey) { } # join responses to question data - df <- dplyr::left_join (df, sq) + df <- dplyr::left_join (df, sq, by = c("survey_id", "question_id", "subquestion_id", "answerchoice_id")) # Combine the two question headers to make a single one df$question_text_full <- diff --git a/man/as.data.frame.surveyresponses.Rd b/man/surveyresponses.Rd similarity index 56% rename from man/as.data.frame.surveyresponses.Rd rename to man/surveyresponses.Rd index 7dc78e8..1fe4141 100644 --- a/man/as.data.frame.surveyresponses.Rd +++ b/man/surveyresponses.Rd @@ -1,10 +1,10 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/as.data.frame.surveyresponses.r -\name{as.data.frame.surveyresponses} -\alias{as.data.frame.surveyresponses} -\title{as.data.frame.surveyresponses} +% Please edit documentation in R/surveyresponses.r +\name{surveyresponses} +\alias{surveyresponses} +\title{surveyresponses} \usage{ -\method{as.data.frame}{surveyresponses}(survey) +surveyresponses(survey) } \arguments{ \item{survey}{A sm_survey object, as retrieved by \code{surveylist()}.} From 1e5d1e7846c425831cabddf4db496d59cd9cd4a0 Mon Sep 17 00:00:00 2001 From: Sean Fahey Date: Sun, 8 Jan 2017 20:37:18 -0500 Subject: [PATCH 67/76] renamed surveyquestiondf to surveyquestions and updated docs --- R/{surveyquestiondf.R => surveyquestions.R} | 6 +++--- R/surveyresponses.r | 4 ++-- man/surveyquestiondf.Rd | 18 ------------------ 3 files changed, 5 insertions(+), 23 deletions(-) rename R/{surveyquestiondf.R => surveyquestions.R} (98%) delete mode 100644 man/surveyquestiondf.Rd diff --git a/R/surveyquestiondf.R b/R/surveyquestions.R similarity index 98% rename from R/surveyquestiondf.R rename to R/surveyquestions.R index 3c7e89e..10b82b7 100644 --- a/R/surveyquestiondf.R +++ b/R/surveyquestions.R @@ -1,12 +1,12 @@ -#' surveyquestiondf +#' surveyquestions #' #' Creates a data frame from the survey questions and answers #' #' @param survey A sm_survey object, as retrieved by \code{surveylist()}. #' @return A data frame with one row per question/subquestion/answer choice -#' @export surveyquestiondf +#' @export surveyquestions #' -surveyquestiondf <- function(survey) { +surveyquestions <- function(survey) { df <- data.frame() sd <- surveydetails(survey, question_details = TRUE) survey_id <- sd$id diff --git a/R/surveyresponses.r b/R/surveyresponses.r index 6df4e2a..8ad632f 100644 --- a/R/surveyresponses.r +++ b/R/surveyresponses.r @@ -10,7 +10,7 @@ surveyresponses <- function(survey) { df <- data.frame() sr <- getresponses(survey, bulk = TRUE, all_page = TRUE) - sq <- surveyquestiondf(survey) + sq <- surveyquestions(survey) survey_id <- survey$id # Iterate through responses @@ -81,7 +81,7 @@ surveyresponses <- function(survey) { df <- df[!is.na(df$question_text_full),] # for text responses replace the answerchoice field with the text - df$answerchoice_text[!is.null(df$answertext)] <- df$answertext + df$answerchoice_text[is.na(df$answerchoice_text)] <- df$answertext # Select only the columns for the final dataframe df <- select(df, response_id, survey_id, collector_id, recipient_id, question_text_full, answerchoice_text) diff --git a/man/surveyquestiondf.Rd b/man/surveyquestiondf.Rd deleted file mode 100644 index 7bfbcb0..0000000 --- a/man/surveyquestiondf.Rd +++ /dev/null @@ -1,18 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/surveyquestiondf.R -\name{surveyquestiondf} -\alias{surveyquestiondf} -\title{surveyquestiondf} -\usage{ -surveyquestiondf(survey) -} -\arguments{ -\item{survey}{A sm_survey object, as retrieved by \code{surveylist()}.} -} -\value{ -A data frame with one row per question/subquestion/answer choice -} -\description{ -Creates a data frame from the survey questions and answers -} - From d18491b06c6e9c7f44eb500851799d8ccf7b49c8 Mon Sep 17 00:00:00 2001 From: Sean Fahey Date: Sun, 8 Jan 2017 20:37:18 -0500 Subject: [PATCH 68/76] renamed surveyquestiondf to surveyquestions and updated docs --- NAMESPACE | 3 +-- R/{surveyquestiondf.R => surveyquestions.R} | 6 +++--- R/surveyresponses.r | 4 ++-- man/{surveyquestiondf.Rd => surveyquestions.Rd} | 8 ++++---- 4 files changed, 10 insertions(+), 11 deletions(-) rename R/{surveyquestiondf.R => surveyquestions.R} (98%) rename man/{surveyquestiondf.Rd => surveyquestions.Rd} (77%) diff --git a/NAMESPACE b/NAMESPACE index 7a959ae..28a1683 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,6 +1,5 @@ # Generated by roxygen2: do not edit by hand -export(as.data.frame.surveyresponses) export(getresponses) export(print.sm_response) export(print.sm_survey) @@ -8,6 +7,6 @@ export(smlogin) export(surveydetails) export(surveylist) export(surveypreview) -export(surveyquestiondf) export(surveyquestions) +export(surveyresponses) export(userdetails) diff --git a/R/surveyquestiondf.R b/R/surveyquestions.R similarity index 98% rename from R/surveyquestiondf.R rename to R/surveyquestions.R index 3c7e89e..10b82b7 100644 --- a/R/surveyquestiondf.R +++ b/R/surveyquestions.R @@ -1,12 +1,12 @@ -#' surveyquestiondf +#' surveyquestions #' #' Creates a data frame from the survey questions and answers #' #' @param survey A sm_survey object, as retrieved by \code{surveylist()}. #' @return A data frame with one row per question/subquestion/answer choice -#' @export surveyquestiondf +#' @export surveyquestions #' -surveyquestiondf <- function(survey) { +surveyquestions <- function(survey) { df <- data.frame() sd <- surveydetails(survey, question_details = TRUE) survey_id <- sd$id diff --git a/R/surveyresponses.r b/R/surveyresponses.r index 6df4e2a..8ad632f 100644 --- a/R/surveyresponses.r +++ b/R/surveyresponses.r @@ -10,7 +10,7 @@ surveyresponses <- function(survey) { df <- data.frame() sr <- getresponses(survey, bulk = TRUE, all_page = TRUE) - sq <- surveyquestiondf(survey) + sq <- surveyquestions(survey) survey_id <- survey$id # Iterate through responses @@ -81,7 +81,7 @@ surveyresponses <- function(survey) { df <- df[!is.na(df$question_text_full),] # for text responses replace the answerchoice field with the text - df$answerchoice_text[!is.null(df$answertext)] <- df$answertext + df$answerchoice_text[is.na(df$answerchoice_text)] <- df$answertext # Select only the columns for the final dataframe df <- select(df, response_id, survey_id, collector_id, recipient_id, question_text_full, answerchoice_text) diff --git a/man/surveyquestiondf.Rd b/man/surveyquestions.Rd similarity index 77% rename from man/surveyquestiondf.Rd rename to man/surveyquestions.Rd index 7bfbcb0..beda092 100644 --- a/man/surveyquestiondf.Rd +++ b/man/surveyquestions.Rd @@ -1,10 +1,10 @@ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/surveyquestiondf.R -\name{surveyquestiondf} -\alias{surveyquestiondf} -\title{surveyquestiondf} +\name{surveyquestions} +\alias{surveyquestions} +\title{surveyquestions} \usage{ -surveyquestiondf(survey) +surveyquestions(survey) } \arguments{ \item{survey}{A sm_survey object, as retrieved by \code{surveylist()}.} From b526ad0c97fd08bccf064902c90466e3f511ef08 Mon Sep 17 00:00:00 2001 From: Sean Fahey Date: Sun, 8 Jan 2017 21:13:56 -0500 Subject: [PATCH 69/76] updated to account for "other" text responses --- R/surveyquestions.R | 25 +++++++++++++++++++++++++ man/surveyquestions.Rd | 2 +- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/R/surveyquestions.R b/R/surveyquestions.R index 10b82b7..a6a7c4f 100644 --- a/R/surveyquestions.R +++ b/R/surveyquestions.R @@ -62,6 +62,31 @@ surveyquestions <- function(survey) { stringsAsFactors = FALSE, check.rows = FALSE ) + + # append a second new row for other options on select questions + if(!is.null(i$answers$other) & k == 1) { + answerchoice_id <- i$answers$other$id + answerchoice_text <- i$answers$other$text + answerchoice_weight <- NA + newrow2 <- + data.frame( + survey_id, + question_id, + subquestion_id, + answerchoice_id, + question_type, + question_subtype, + question_text, + subquestion_text, + answerchoice_text, + answerchoice_weight, + stringsAsFactors = FALSE, + check.rows = FALSE + ) + newrow <- rbind(newrow, newrow2) + } + + # add new row(s) to dataframe df <- rbind(df, newrow) if (k >= length(i$answers$choices)) { break diff --git a/man/surveyquestions.Rd b/man/surveyquestions.Rd index beda092..874c665 100644 --- a/man/surveyquestions.Rd +++ b/man/surveyquestions.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/surveyquestiondf.R +% Please edit documentation in R/surveyquestions.R \name{surveyquestions} \alias{surveyquestions} \title{surveyquestions} From aa27b82b126ea27d2ac7d6e3cad9d8abce1a35e9 Mon Sep 17 00:00:00 2001 From: Sean Fahey Date: Sun, 8 Jan 2017 21:46:14 -0500 Subject: [PATCH 70/76] updated to manage "other" text without warnings --- R/surveyresponses.r | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/R/surveyresponses.r b/R/surveyresponses.r index 8ad632f..31da634 100644 --- a/R/surveyresponses.r +++ b/R/surveyresponses.r @@ -34,8 +34,11 @@ surveyresponses <- function(survey) { subquestion_id <- i$answers[[j]]$row_id } if (is.null(i$answers[[j]]$choice_id)) { - answerchoice_id <- NA if (is.null(i$answers[[j]]$other_id)) { + answerchoice_id <- NA + answertext <- i$answers[[j]]$text + } else { + answerchoice_id <-i$answers[[j]]$other_id answertext <- i$answers[[j]]$text } } else { @@ -81,7 +84,7 @@ surveyresponses <- function(survey) { df <- df[!is.na(df$question_text_full),] # for text responses replace the answerchoice field with the text - df$answerchoice_text[is.na(df$answerchoice_text)] <- df$answertext + df$answerchoice_text[!is.na(df$answertext)] <- df$answertext[!is.na(df$answertext)] # Select only the columns for the final dataframe df <- select(df, response_id, survey_id, collector_id, recipient_id, question_text_full, answerchoice_text) From 7e022727c6d4a1bbe6bdc66f9c83198c8226ad7b Mon Sep 17 00:00:00 2001 From: Sean Fahey Date: Sun, 8 Jan 2017 22:32:39 -0500 Subject: [PATCH 71/76] added parameter to select response format --- R/surveyresponses.r | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/R/surveyresponses.r b/R/surveyresponses.r index 31da634..1a80838 100644 --- a/R/surveyresponses.r +++ b/R/surveyresponses.r @@ -3,11 +3,13 @@ #' Extracts data from the survey responses data set and formats it as a data frame for analysis #' #' @param survey A sm_survey object, as retrieved by \code{surveylist()}. +#' @param response_format A string indicating the desired data frame response format: 'Table' = one survey response per row and one column per question, or 'Column' = a key/value arrangement with each row holding data for a single question response #' @return A data frame with survey responses #' @export surveyresponses -surveyresponses <- function(survey) { +surveyresponses <- function(survey, + response_format = table) { df <- data.frame() sr <- getresponses(survey, bulk = TRUE, all_page = TRUE) sq <- surveyquestions(survey) @@ -80,8 +82,8 @@ surveyresponses <- function(survey) { ) ) - # Remove rows with NA as question_text (these are the 'other' responses that still need to be managed) - df <- df[!is.na(df$question_text_full),] + # # Remove rows with NA as question_text (these are the 'other' responses that still need to be managed) + # df <- df[!is.na(df$question_text_full),] # for text responses replace the answerchoice field with the text df$answerchoice_text[!is.na(df$answertext)] <- df$answertext[!is.na(df$answertext)] @@ -92,7 +94,8 @@ surveyresponses <- function(survey) { # Spread from column to tablular form df_table <- spread(df, question_text_full, answerchoice_text) - return(df_table) + if (tolower(response_format) == 'column') {return(df)} else {return(df_table)} + } # Future work From 19daf824cef98ae06037ac0871a059b422892e25 Mon Sep 17 00:00:00 2001 From: Sean Fahey Date: Sun, 8 Jan 2017 22:32:39 -0500 Subject: [PATCH 72/76] added parameter to select response format --- R/surveyresponses.r | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/R/surveyresponses.r b/R/surveyresponses.r index 31da634..217c1f5 100644 --- a/R/surveyresponses.r +++ b/R/surveyresponses.r @@ -3,11 +3,13 @@ #' Extracts data from the survey responses data set and formats it as a data frame for analysis #' #' @param survey A sm_survey object, as retrieved by \code{surveylist()}. +#' @param response_format A string indicating the desired data frame response format: 'Table' = one survey response per row and one column per question, or 'Column' = a key/value arrangement with each row holding data for a single question response #' @return A data frame with survey responses #' @export surveyresponses -surveyresponses <- function(survey) { +surveyresponses <- function(survey, + response_format = 'table') { df <- data.frame() sr <- getresponses(survey, bulk = TRUE, all_page = TRUE) sq <- surveyquestions(survey) @@ -80,8 +82,8 @@ surveyresponses <- function(survey) { ) ) - # Remove rows with NA as question_text (these are the 'other' responses that still need to be managed) - df <- df[!is.na(df$question_text_full),] + # # Remove rows with NA as question_text (these are the 'other' responses that still need to be managed) + # df <- df[!is.na(df$question_text_full),] # for text responses replace the answerchoice field with the text df$answerchoice_text[!is.na(df$answertext)] <- df$answertext[!is.na(df$answertext)] @@ -92,7 +94,8 @@ surveyresponses <- function(survey) { # Spread from column to tablular form df_table <- spread(df, question_text_full, answerchoice_text) - return(df_table) + if (tolower(response_format) == 'column') {return(df)} else {return(df_table)} + } # Future work From 0ed90f6da337e3a81fba69904cf782a9000b1360 Mon Sep 17 00:00:00 2001 From: Sean Fahey Date: Sun, 15 Jan 2017 19:56:07 -0500 Subject: [PATCH 73/76] moved table spread command into else statement --- R/surveyresponses.r | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/R/surveyresponses.r b/R/surveyresponses.r index 7126a63..98e159a 100644 --- a/R/surveyresponses.r +++ b/R/surveyresponses.r @@ -93,11 +93,13 @@ surveyresponses <- function(survey, # Select only the columns for the final dataframe df <- select(df, response_id, survey_id, collector_id, recipient_id, question_text_full, answerchoice_text) - - # Spread from column to tablular form - df_table <- spread(df, question_text_full, answerchoice_text) - - if (tolower(response_format) == 'column') {return(df)} else {return(df_table)} + + if (tolower(response_format) == 'column') {return(df)} else { + + # Spread from column to tablular form + df_table <- spread(df, question_text_full, answerchoice_text) + + return(df_table)} } From 85d1c8803ee358e40cbafff0185e5fa2d3a57dc7 Mon Sep 17 00:00:00 2001 From: Sean Fahey Date: Mon, 6 Mar 2017 13:25:05 -0500 Subject: [PATCH 74/76] made call to tidyr explicit --- R/surveyresponses.r | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/R/surveyresponses.r b/R/surveyresponses.r index 98e159a..23b249d 100644 --- a/R/surveyresponses.r +++ b/R/surveyresponses.r @@ -96,8 +96,11 @@ surveyresponses <- function(survey, if (tolower(response_format) == 'column') {return(df)} else { + # remove any duplicate rows (need to change questiontext to quesiton ID to avoid this) + df <- df[!duplicated(df),] + # Spread from column to tablular form - df_table <- spread(df, question_text_full, answerchoice_text) + df_table <- tidyr::spread(df, question_text_full, answerchoice_text) return(df_table)} From b3a442260c219ff27116a397a414091ee47d23b5 Mon Sep 17 00:00:00 2001 From: Sean Fahey Date: Thu, 30 Mar 2017 23:53:15 -0400 Subject: [PATCH 75/76] updated README --- R/surveyresponses.r | 2 +- README.Rmd | 125 +++++++++++++++++++++++++++++++++++++ README.md => README_old.md | 0 3 files changed, 126 insertions(+), 1 deletion(-) create mode 100644 README.Rmd rename README.md => README_old.md (100%) diff --git a/R/surveyresponses.r b/R/surveyresponses.r index 23b249d..ab96383 100644 --- a/R/surveyresponses.r +++ b/R/surveyresponses.r @@ -92,7 +92,7 @@ surveyresponses <- function(survey, df$answerchoice_text[!is.na(df$answertext)] <- df$answertext[!is.na(df$answertext)] # Select only the columns for the final dataframe - df <- select(df, response_id, survey_id, collector_id, recipient_id, question_text_full, answerchoice_text) + df <- dplyr::select(df, response_id, survey_id, collector_id, recipient_id, question_text_full, answerchoice_text) if (tolower(response_format) == 'column') {return(df)} else { diff --git a/README.Rmd b/README.Rmd new file mode 100644 index 0000000..4afff4e --- /dev/null +++ b/README.Rmd @@ -0,0 +1,125 @@ +--- +title: "README" +author: "Thomas" +author: "Sean Fahey" +date: "3/30/2017" +output: html_document +--- + +```{r setup, include=FALSE} +knitr::opts_chunk$set(echo = TRUE) +``` + +**Rmonkey** provides access to [Survey Monkey](https://www.surveymonkey.com/), for the complete integration of survey data collection and analysis into a single, easily reproducible workflow. + +## Installation ## + +This version of **Rmonkey** is updated to interface with the SurveyMonkey API v3. The latest development version, available here, can be installed directly using [devtools](http://cran.r-project.org/web/packages/devtools/index.html): + +```{r} +if(!require("devtools")) { + install.packages("devtools") + library("devtools") +} +install_github("seanofahey/Rmonkey") +library("Rmonkey") +``` + +## Setup ## + +To use Rmonkey, the user must first have a Survey Monkey account which can be obtained at https://www.surveymonkey.com/user/sign-in/. Next, within the SurveyMonkey account, the user must create an app that can be used to access data via the api. This can be done at https://developer.surveymonkey.com/apps/. In the app configuration, set OAuth Redirect URL as `http://localhost:1410`. Finally set the user permissions for creating and viewing data within SurveyMonkey with the scopes options. + +Once the app is configured, click on settings to reveal the Client ID and Secret keys. These can be loaded into R using `options`: + +```{r} +options(sm_client_id = 'YourClientID') +options(sm_secret = 'YourAPISecret') +``` + +Rmonkey uses these values inside `smlogin` to initiate an OAuth2.0 login. Calling `smlogin()`, you will redirected to your web browser, where you will login with your regular Survey Monkey account information. `sm_login` will then store a durable OAuth token in `options('sm_oauth_token')`, which is automatically retrieved in subsequent Rmonkey operations. + +This token is currently long-lived (meaning it is valid indefinitely). This means that saving the OAuth token between R sessions will prevent you from having to login each time you load **Rmonkey** and allow you to use the package in non-interactive R sessions. If you have trouble logging in, it is also possible to copy the OAuth access token from the [App Settings](https://developer.surveymonkey.com/apps), which can then be manually stored in `options('sm_oauth_token')`. + +## Code Examples ## + +Below are some code examples showing how to use the package. + +### Establish and Test the API Connection ### + +To establish a connection between R and SurveyMonkey use the `smlogin()` function. This will open an interactive session in your browser to present the API permissions and request authorization. This function completes the OAuth handshake and saves a long lasting token on the computer. + +```{r} +smlogin() +``` + +To verify that the connection is functional you can retrieve information about the user with the `userdetails()` function. + +```{r} +userdetails() +``` + +## Get a list of Surveys ### + +**RMonkey** provides several options for retrieving information about the surveys in the account. + +One can retrieve a list of surveys using the `surveylist()` command. This will return a list with details of each survey. + +```{r} +sl <- surveylist() +head(sl) +``` + +To retrieve a list of surveys that have been modified since a certain date one can use the `start_modified_at` parameter within the `surveylist()` function. + +```{r} +sl <- surveylist(start_modified_at = '2017-03-25') +head(sl) +``` + +Additional parameters can be used to change the number of responses, add fields to the survey list response, and sort the responses. + +```{r} +sl <- surveylist(per_page = 100, include = 'response_count', sort_by = 'num_responses', sort_order = 'desc') +head(sl) +``` + +## Get Details about a survey ## + +To see details about a single survey use the `surveydetails()` function. This will return basic information about the survey including the title, nickname, ID, number of questions, number of respondents, etc... + +```{r} +s1.d <- surveydetails(sl[[1]]) +s1.d +``` + +## Preview a Survey in the Browser ## + +To see a preview of a survey use the `surveypreview()` function. In the function, pass a survey object retrieved using the survey list function. This will open a tab in your browser to display the survey preview. + +```{r} +surveypreview(sl[[1]]) +``` + +## Retrieve Survey Responses ## + +To get a list of responses for a survey use the `surveyresponses()` function. In the function, pass a survey object retrieved using the survey list function. This will return a data frame with one row per response and one column per question. + +```{r} +s1.r <- surveyresponses(sl[[5]]) +head(s1.r) +``` + +To get the results into a columnar format use the response_format = 'column' parameter. (This can be useful if exporting the data to systems that ingest data in this format.) + +```{r} +s1.r <- surveyresponses(sl[[5]], response_format = 'column') +head(s1.r) +``` + +## Future Work ## + +The following known issues are on the docket for future work: +* enable retrieval by collector +* enable passing of survey ID in addition to a survey object +* update functions to allow creation of surveys +* improve the code in the getresponses() function to remove loops and make it much faster \ No newline at end of file diff --git a/README.md b/README_old.md similarity index 100% rename from README.md rename to README_old.md From f64ad0e6cac01a3bae346a925f8fd2c81af2034b Mon Sep 17 00:00:00 2001 From: Sean Fahey Date: Fri, 31 Mar 2017 00:04:09 -0400 Subject: [PATCH 76/76] small changes to README --- README.Rmd | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/README.Rmd b/README.Rmd index 4afff4e..27b0bf8 100644 --- a/README.Rmd +++ b/README.Rmd @@ -102,24 +102,17 @@ surveypreview(sl[[1]]) ## Retrieve Survey Responses ## -To get a list of responses for a survey use the `surveyresponses()` function. In the function, pass a survey object retrieved using the survey list function. This will return a data frame with one row per response and one column per question. +To get a list of responses for a survey use the `surveyresponses()` function. In the function, pass a survey object retrieved using the survey list function. This will return a data frame with one row per response and one column per question. (NOTE: This can take a long time to run.) ```{r} s1.r <- surveyresponses(sl[[5]]) head(s1.r) ``` -To get the results into a columnar format use the response_format = 'column' parameter. (This can be useful if exporting the data to systems that ingest data in this format.) +To get the survey results into a columnar format use the response_format = 'column' parameter. (This can be useful if exporting the data to systems that ingest data in this format.) ```{r} s1.r <- surveyresponses(sl[[5]], response_format = 'column') head(s1.r) ``` -## Future Work ## - -The following known issues are on the docket for future work: -* enable retrieval by collector -* enable passing of survey ID in addition to a survey object -* update functions to allow creation of surveys -* improve the code in the getresponses() function to remove loops and make it much faster \ No newline at end of file