diff --git a/.github/workflows/R-CMD-check.yaml b/.github/workflows/R-CMD-check.yaml new file mode 100644 index 0000000..e7392d3 --- /dev/null +++ b/.github/workflows/R-CMD-check.yaml @@ -0,0 +1,54 @@ +# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples +# Need help debugging build failures? +# Start at https://github.com/r-lib/actions#where-to-find-help +on: + push: + branches: [main, master] + pull_request: + branches: [main, master] + +name: R-CMD-check + +jobs: + R-CMD-check: + runs-on: ${{ matrix.config.os }} + + name: ${{ matrix.config.os }} (${{ matrix.config.r }}) + + strategy: + fail-fast: false + matrix: + config: + - {os: macos-latest, r: 'release'} + - {os: windows-latest, r: 'release'} + - {os: ubuntu-latest, r: 'devel', http-user-agent: 'release'} + - {os: ubuntu-latest, r: 'release'} + # - {os: ubuntu-latest, r: 'oldrel-1'} + + env: + GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} + R_KEEP_PKG_SOURCE: yes + R_REMOTES_NO_ERRORS_FROM_WARNINGS: true # This is because there are + # warnings that I cannot circumvent because they are triggered by + # oTree's file names + + steps: + - uses: actions/checkout@v3 + + - uses: r-lib/actions/setup-pandoc@v2 + + - uses: r-lib/actions/setup-r@v2 + with: + r-version: ${{ matrix.config.r }} + http-user-agent: ${{ matrix.config.http-user-agent }} + use-public-rspm: true + + - uses: r-lib/actions/setup-r-dependencies@v2 + with: + extra-packages: any::rcmdcheck + needs: check + + - uses: r-lib/actions/check-r-package@v2 + with: + upload-snapshots: true + error-on: '"error"' diff --git a/DESCRIPTION b/DESCRIPTION new file mode 100644 index 0000000..b327fc8 --- /dev/null +++ b/DESCRIPTION @@ -0,0 +1,35 @@ +Package: gmoTree +Title: Get and Modify oTree Data +Version: 0.0.1 +Date: 2023-08-24 +Authors@R: + person("Patricia F.", "Zauchner", , "patricia.zauchner@gmx.at", role = c("aut", "trl", "cre", "cph"), + comment = c(ORCID = "https://orcid.org/0000-0002-5938-1683")) +Description: Import, merge, and manage data from oTree experiments. +License: GPL (>= 3) +URL: https://zauchnerp.github.io/gmoTree/, + https://github.com/ZauchnerP/gmoTree +BugReports: https://github.com/ZauchnerP/gmoTree/issues +Depends: + R (>= 4.3.0) +Imports: + data.table (>= 1.14.8), + dplyr (>= 1.1.2), + openxlsx (>= 4.2.5.2), + plyr (>= 1.8.8), + rlang (>= 1.1.1), + rlist (>= 0.4.6.2), + stats (>= 4.3.0), + stringr (>= 1.5.0) +Suggests: + knitr (>= 1.43), + rmarkdown (>= 2.22), + testthat (>= 3.1.9), + withr (>= 2.5.0) +VignetteBuilder: + knitr +BuildVignettes: true +Config/testthat/edition: 3 +Encoding: UTF-8 +LazyData: true +RoxygenNote: 7.2.3 diff --git a/NAMESPACE b/NAMESPACE new file mode 100644 index 0000000..debae1d --- /dev/null +++ b/NAMESPACE @@ -0,0 +1,18 @@ +# Generated by roxygen2: do not edit by hand + +export(apptime) +export(assignv) +export(assignv_to_aaw) +export(delete_cases) +export(delete_dropouts) +export(delete_duplicate) +export(delete_plabels) +export(delete_sessions) +export(extime) +export(import_otree) +export(make_ids) +export(messy_chat) +export(messy_time) +export(pagesec) +export(show_constant) +export(show_dropouts) diff --git a/NEWS.md b/NEWS.md new file mode 100644 index 0000000..958e788 --- /dev/null +++ b/NEWS.md @@ -0,0 +1,3 @@ +# gmoTree 0.0.1 + +* Beta version of gmoTree published (formerly known as "ioTree") diff --git a/R/apptime.R b/R/apptime.R new file mode 100644 index 0000000..268227f --- /dev/null +++ b/R/apptime.R @@ -0,0 +1,772 @@ +#' Calculate the time that was spent on an app +#' @description +#' Calculate the time spent on one app or several apps. +#' @keywords oTree +#' @param oTree A list of data frames that were created by import_otree(). +#' @param apps Name(s) of the app(s) for which the time +#' should be calculated. +#' @param pcode Character. The value of the participant.code variable if the +#' time should only be calculated for one specified participant. +#' @param plabel Character. The value of the participant.label variable if the +#' time should only be calculated for one specified participant. +#' @param group_id Integer. The value of the group_id variable if the +#' time should only be calculated for one specified group. The group_id +#' variable can be created with make_ids(). +#' @param seconds Logical. +#' TRUE if the output should be in seconds instead of minutes. +#' @param rounded Logical. +#' TRUE if the output should be rounded. +#' @param digits Integer. +#' The number of digits to which the output should be rounded. +#' This parameter has no effect unless rounded = TRUE. +#' @param sinfo Character. +#' "session_id" to use session ID for additional information in the data frame +#' of single durations, "session_code" to use session codes, or NULL if no +#' session column should be shown. +#' @param combine Logical. +#' TRUE if all variables relating to epoch time should be merged, and +#' all variables relating to participant code should be merged +#' when data from multiple versions of oTree are used. +#' @returns This function returns a list for each app containing +#' information on the mean, the minimum, and maximum time the participants +#' spent on the app, a data frame with information on the time +#' each participant spent on the app, and eventually, +#' vectors of background information on these numbers. +#' +#' If the experiment's duration is only calculated for one participant, +#' the output returns an NA (per app) if the person did not make +#' it to the app(s). +#' @examples +#' # Use package-internal list of oTree data frames +#' oTree <- gmoTree::oTree +#' +#' # Show how much time all participants spent on app "survey" +#' apptime(oTree, "survey") +#' +#' # Show how much time the participant "y8rbzcju" spent on +#' # the app "survey" +#' apptime(oTree, pcode = "y8rbzcju", "survey") +#' +#' # Show how much time the participants in group 4 spent on +#' # the app "survey" +#' oTree <- make_ids(oTree, gmake = TRUE, +#' from_var = "dictator.1.group.id_in_subsession") +#' apptime(oTree, group_id = 4, apps = "survey") + + +#' @export +apptime <- function(oTree, + apps = NULL, + pcode = NULL, + plabel = NULL, + group_id = NULL, + seconds = FALSE, + rounded = TRUE, + digits = 2, + sinfo = "session_code", + combine = FALSE) { + + output <- list() + participant_code_name <- NULL + message_vector <- c() + duplicate_participants <- c() + firststageproblemparticipants <- c() + warningparticipants <- c() + + # Create list of apps if argument apps is empty #### + if (is.null(apps)) { + apps <- names(oTree) + apps <- apps[apps != "info"] + apps <- apps[apps != "all_apps_wide"] + apps <- apps[apps != "Time"] + apps <- apps[apps != "Chats"] + + } else { + # If apps are defined, check if they are there + if (length(apps[apps %in% names(oTree)]) != length(apps)) { + if (length(apps[apps %in% names(oTree)]) > 0) { + warning( + paste0("The following app(s) is/are not in ", + "the list of oTree data frames: ", + paste(collapse = ", ", + apps[!(apps %in% names(oTree))]))) + } else { + stop( + paste0("The apps specified in the argument apps are not in the ", + "oTree list of data frames!")) + } + apps <- apps[apps %in% names(oTree)] + } + } + + # Seconds or minutes #### + if (seconds == TRUE) { + divsec <- 1 + } else { + divsec <- 60 # Divide seconds by 60 to get minutes + } + + # Error messages #### + if (!("Time" %in% names(oTree))) { + stop("There is no \"Time\" data frame.") + } + + if (nrow(oTree$Time) == 0) { + stop("Your \"Time\" data frame is empty.") + } + + if (!is.null(pcode) && !is.null(group_id)) { + stop("Please enter only pcode or group_id") + } + + if (!is.null(plabel) && !is.null(group_id)) { + stop("Please enter only plabel or group_id") + } + + if (!is.null(pcode) && !is.null(plabel)) { + stop("Please enter only pcode or plabel") + } + + if (length(pcode) > 1) { + stop("Please enter only one participant code!") + } + + if (length(plabel) > 1) { + stop("Please enter only one participant label!") + } + + if (!is.null(group_id) && is.null(oTree$Time$group_id)) { + stop(paste0("Variable group_id is not in \"Time\" data frame!\n", + "Run make_ids first!")) + } + + if (!is.null(group_id) && + length(oTree$Time$group_id[oTree$Time$group_id == group_id]) == 0) { + stop("group_id is not in \"Time\" data frame!") + } + + if (is.null(oTree$all_apps_wide) && !is.null(plabel)) { + stop(paste0("You can only use the argument plabel ", + "if there is an all_apps_wide-data frame in your oTree list")) + } + + # Check if there are too many epoch times and participant code variables + withCallingHandlers({ + # Call messy_time() + oTree <- messy_time(oTree, combine, info = TRUE) + }, error = function(e) { + # Stop if there is an error + stop(e) + }, warning = function(w) { + # Catch warning, but continue with messy_time() + warning(w) + invokeRestart("muffleWarning") + }) + + # Set time variable name + if ("epoch_time" %in% colnames(oTree$Time)) { + timestamp_var_name <- "epoch_time" + } else if ("epoch_time_completed" %in% colnames(oTree$Time)) { + timestamp_var_name <- "epoch_time_completed" + } else if ("time_stamp" %in% colnames(oTree$Time)) { + timestamp_var_name <- "time_stamp" + } else { + stop("No variable referring to the epoch time tamp ", + "in your Time data frame. ", + "This should be a variable called either \"epoch time,\" ", + "\"epoch_time_completed,\" or ", + "\"time stamp.\"") + } + + # Set participant code variable + if ("participant_code" %in% colnames(oTree$Time)) { + participant_code_name <- "participant_code" + } else if ("participant__code" %in% colnames(oTree$Time)) { + participant_code_name <- "participant__code" + } else { + stop("No variable referring to the participant code ", + "in your Time data frame. ", + "This should be a variable called either \"participant_code,\" or", + "\"participant__code.\"") + } + + if (!is.null(sinfo) && + !(sinfo %in% c("session_code", "session_id"))) { + stop("Please specify a valid sinfo! Possibilities are ", + "\"session_code\" or \"session_id\"") + } + + if (!is.null(sinfo) && + sinfo == "session_id" && + is.null(oTree$Time$session_id)) { + stop("There is no session_id in the Time data frame") + } + + if (!is.null(sinfo) && + sinfo == "session_code" && + is.null(oTree$Time$session_code) && + is.null(oTree$Time$session__code)) { + + # Does this possibility even exist? + stop("There is no session_code or session__code in the Time data frame.\n", + "This might be because you are using an ", + "old oTree version that does not ", + "contain this information. Choose sinfo = NULL to avoid this ", + "error and omit session information.") + } + + # Check for several session_code information in Time data frame + if (!is.null(sinfo)) { + + # Check if there are old and new session_code variables + length_session_code_variables <- sum( + c("session_code", + "session__code", + "participant__session__code") %in% colnames(oTree$Time)) + + if (length_session_code_variables > 1) { + # Does this possibility even exist? + # Are there old oTree versions where this could be relevant? + stop("More than one variable referred to the session code ", + "in your Time data frame. This could be because ", + "you mixed data of different ", + "versions of oTree in your data frame. ", + "Before using this function, please integrate ", + "both variables and ensure ", + "you only have one of them.") + } + } + + # First app warning + errormax1min1 <- paste0( + "Warning: If the first app only has one page, ", + "the indices for the first and the last page are the same ", + "- Duration = NA!!", + " This applies to all participants listed in $first_app_one_page.") + + duplicatewarning <- paste0( + "Some participants have duplicate data and are not ", + "used in the analyses. ", + "See $dulicate_participants!") + + # Transform plabel to pcode identifier #### + if (!is.null(plabel)) { + if (length(unique(oTree$all_apps_wide$participant.label)) == + length(oTree$all_apps_wide$participant.label)) { + + pcode <- oTree$all_apps_wide$participant.code[ + oTree$all_apps_wide$participant.label == plabel] + } else { + stop("You do not have unique participant labels in your ", + "all_apps_wide data frame! The argument plabel is ", + "not working in such a case!") + } + } + + # Sub functions 1 - indices #### + # Make a vector of all indices within an app + calc_pages_per_app_indices <- function(participant_code_name, + who, + appname) { + app_indices <- oTree$Time$page_index[ + !is.na(oTree$Time[[participant_code_name]]) & + oTree$Time[[participant_code_name]] == who & + !is.na(oTree$Time$app_name) & + oTree$Time$app_name == appname] + return(app_indices) + } + + # Make a vector of all app indices for a person + calc_all_indices <- function(participant_code_name, who) { + all_indices <- + oTree$Time$page_index[oTree$Time[[participant_code_name]] == who] + all_indices <- all_indices[!is.na(all_indices)] + return(all_indices) + } + + # Get the minimum page index of an app (step 1) + calc_minpageindex1 <- function(app_indices, who) { + # Minimum index in the App (Measures time at the end of the first page) + + if (!anyNA(app_indices) && length(app_indices)) { + minpageindex <- min(app_indices) + } else { + minpageindex <- NA + } + + # if (!is.na(minpageindex) && minpageindex == 1) { + # Is done in calc_minpageindex2() + # } + return(minpageindex) + } + + # Get the minimum page index of an app (step 2) + calc_minpageindex2 <- function(all_indices, app_indices, + minpageindex, who + ) { + + # Adjust min and max page index + # min page index should jump to the next lower page_index + # or stay at 1 if it was 1 and used in the old oTree version + + if (minpageindex != 1) { + minpageindex <- max(all_indices[all_indices < minpageindex]) + } else if (minpageindex == 1 && min(all_indices) == 0) { + minpageindex <- 0 + } + + maxpageindex <- if (!anyNA(app_indices) && length(app_indices)) { + max(app_indices) + } else { + NA + } + + # Warning: If there is only one page in the first app + if (maxpageindex == 1 && minpageindex == 1) { + + firststageproblemparticipants <<- c(firststageproblemparticipants, who) + message_vector <<- c(message_vector, errormax1min1) + + } + output <- list(min = minpageindex, + max = maxpageindex) + + return(output) + } + + # Get time stamp for the minimum page index of an app + min_max_stamps_dur <- function( + participant_code_name, who, + minpageindex, maxpageindex) { + + # Get time stamps and duration + mintimestamp <- oTree$Time[[timestamp_var_name]][ + !is.na(oTree$Time[[participant_code_name]]) & + oTree$Time[[participant_code_name]] == who & + oTree$Time$page_index == minpageindex] + + maxtimestamp <- oTree$Time[[timestamp_var_name]][ + !is.na(oTree$Time[[participant_code_name]]) & + oTree$Time[[participant_code_name]] == who & + oTree$Time$page_index == maxpageindex] + + duration <- (maxtimestamp - mintimestamp) / divsec + + if (length(mintimestamp) > 1 || length(maxtimestamp) > 1) { + duplicate_participants <<- c(duplicate_participants, + who) + message_vector <<- c(duplicatewarning, message_vector) + } + + return(duration) + } + + # Calculate duration (is called by specified_time) + specified_duration <- function(participant_code_name, who, appname) { + + # Calculate time for a specific individual - returns duration + + # Calculate indices + app_indices <- calc_pages_per_app_indices( + participant_code_name = participant_code_name, + who = who, + appname = appname) + + all_indices <- calc_all_indices( + participant_code_name = participant_code_name, + who = who) + + minpageindex <- calc_minpageindex1(app_indices = app_indices, + who = who) + + # If indices exist calculate time + if (!is.na(minpageindex)) { + # Get page indices + newminmax <- calc_minpageindex2( + all_indices = all_indices, + app_indices = app_indices, + minpageindex = minpageindex, + who = who) + + minpageindex <- newminmax$min + maxpageindex <- newminmax$max + + # Get time stamps and duration + duration <- min_max_stamps_dur( + participant_code_name = participant_code_name, + who = who, + minpageindex = minpageindex, + maxpageindex = maxpageindex) + + # Round duration + if (rounded == TRUE) { + duration <- round(duration, digits = digits) + } + } else { + duration <- NA + message_vector <<- unique(message_vector) + message_vector <<- c(message_vector, paste0( + "Duration could not be calculated for person ", + who, "in app ", appname, + ". Did they make it to this app? ")) + } + return(duration) + } + + # Make sub functions 2 - time #### + + # Calculate time for a specified individual + specified_time <- function() { + # Calls time calculation for (a) specific individual(s) + + # Duration #### + if (pcode %in% unique(oTree$Time$participant__code) || + pcode %in% unique(oTree$Time$participant_code)) { + + duration <- specified_duration(participant_code_name, + pcode, + appname) + + } else if (!(pcode %in% unique(oTree$Time$participant__code)) && + !(pcode %in% unique(oTree$Time$participant_code)) + ) { + # Participant not there + # This is not a stop, because if you calculate the time in a loop, + # this would stop the loop + duration <- NA + } + + if (length(duration) > 1) { + stop("This person has duplicate data in their Time data frame.") + } + + # Make output for specified individuals #### + if (length(apps) == 1) { + output <- duration + } else { + output[[appname]] <- duration + # Do not return yet because the other apps must be added too! + } + + return(output) + } + + # Function for all individuals for specified app names + # appname is set before this function is called + all_time <- function() { + + # Create variables for all participants (all_time) + singledurations <- data.frame() + firststageproblemparticipants <<- c() + warningparticipants <<- c() + message_vector <<- c() + + # Make list of all participants for all participants (all_time) + if (is.null(group_id)) { + # For all groups + listallparticipants <- unique(oTree$Time[[participant_code_name]]) + } else { + # Only for special groups + listallparticipants <- unique(oTree$Time[[participant_code_name]][ + oTree$Time$group_id == group_id]) + } + + # Calculate time for all participants (all_time) #### + for (i in listallparticipants) { + # a) Get indices #### + # Page indices + app_indices <- calc_pages_per_app_indices( + participant_code_name = participant_code_name, + who = i, + appname = appname) + + all_indices <- calc_all_indices( + participant_code_name = participant_code_name, + who = i) + + # b) Check for duplicate pages #### + # for one participant of all (all_time) + if (any(duplicated(all_indices))) { + + duplicate_participants <<- c(duplicate_participants, i) + message_vector <<- c(duplicatewarning, message_vector) + next + + # Do not throw a warning here, because the handling of + # duplicate cases is handled a level above. + } + + # c) Minimum index in the App #### + # (Measures time at the end of the page) + minpageindex <- calc_minpageindex1(app_indices = app_indices, + who = i) + + # d) Adjust indices and get time stamps #### + if (!is.na(minpageindex)) { + + # Adjust min and max page index + newminmax <- calc_minpageindex2( + all_indices = all_indices, + app_indices = app_indices, + minpageindex = minpageindex, + who = i) + + minpageindex <- newminmax$min + maxpageindex <- newminmax$max + + if (minpageindex != maxpageindex) { + + # Get time stamps and duration + duration <- min_max_stamps_dur( + participant_code_name = participant_code_name, + who = i, + minpageindex = minpageindex, + maxpageindex = maxpageindex) + + } else { + duration <- NA + } + + } else { + message_vector <<- unique(message_vector) + message_vector <<- + c(message_vector, + paste0("For some participants, no duration could be ", + "calculated. See list in $warnings. Did they ", + "make it to the app(s)?")) + warningparticipants <- c(warningparticipants, i) + + duration <- NA + } + + # e) Add to data frame #### + + if (!is.null(duration) && !is.na(duration)) { + + session <- get_session(who = i) + + singledurations <- plyr::rbind.fill( + singledurations, + data.frame( + participant = i, + session = ifelse(!is.null(sinfo), session, NA), + duration = duration + ) + ) + + if (is.null(sinfo)) { + singledurations <- singledurations[, c("participant", + "duration")] + } + } + } + + # Single durations data frame is empty - dealing with the reasons #### + if (nrow(singledurations) == 0) { + + if (!is.null(duplicate_participants) && + length(duplicate_participants) > 1) { + + output[[appname]]$messages <- + paste0("Durations not calculated. ", + "There are duplicate data in your ", + "Time data frame.") + + return(output) + } else { + + output[[appname]]$first_app_one_page <- firststageproblemparticipants + message_vector <<- unique(message_vector) + output[[appname]]$message <- c(paste0("Durations not calculated. ", + "Check your data before rerunning ", + "the function. ", message_vector)) + + # Return from all_time() + return(output) + } + } + + # Make output for all participants #### + return(call_output_all_participants(singledurations, + message_vector, + firststageproblemparticipants, + warningparticipants)) + } + + + # Make sub functions 3 - output #### + + # Make output for a specific app if there is only 1 app in the final output + # Get min, max, mean, and single durations + output_oneapp <- function(singledurations, + message_vector, + firststageproblemparticipants, + warningparticipants) { + + output[["mean_duration"]] <- + ifelse(rounded == TRUE, + round(mean(singledurations$duration, + na.rm = TRUE), + digits = digits), + mean(singledurations$duration, + na.rm = TRUE)) + + output[["min_duration"]] <- + ifelse(rounded == TRUE, + round(min(singledurations$duration, + na.rm = TRUE), + digits = digits), + min(singledurations$duration, + na.rm = TRUE)) + + output[["max_duration"]] <- + ifelse(rounded == TRUE, + round(max(singledurations$duration, + na.rm = TRUE), + digits = digits), + max(singledurations$duration, + na.rm = TRUE)) + + output[["single_durations"]] <- singledurations + + if (rounded == TRUE) { + output[["single_durations"]]$duration <- + round(output[["single_durations"]]$duration, digits = digits) + } + + output[["messages"]] <- unique(message_vector) + output[["first_app_one_page"]] <- firststageproblemparticipants + + if (length(warningparticipants > 0)) { + output[["warnings"]] <- unique(warningparticipants) + } + + if (length(duplicate_participants) > 0) { + output[["duplicate_participants"]] <- unique(duplicate_participants) + } + + return(output) + } + + # Make output for a specific app if there are more apps in the final output + # Get min, max, mean, and single durations + output_moreapps <- function(singledurations, + message_vector, + firststageproblemparticipants, + warningparticipants) { + + if (nrow(singledurations) > 0) { + + output[[appname]][["mean_duration"]] <- + ifelse(rounded == TRUE, + round(mean(singledurations$duration, + na.rm = TRUE), + digits = digits), + mean(singledurations$duration, + na.rm = TRUE)) + + output[[appname]][["min_duration"]] <- + ifelse(rounded == TRUE, + round(min(singledurations$duration, + na.rm = TRUE), + digits = digits), + min(singledurations$duration, + na.rm = TRUE)) + + output[[appname]][["max_duration"]] <- + ifelse(rounded == TRUE, + round(max(singledurations$duration, + na.rm = TRUE), + digits = digits), + max(singledurations$duration, + na.rm = TRUE)) + + output[[appname]]$single_durations <- + singledurations[order(singledurations$duration), ] + + if (rounded == TRUE) { + output[[appname]]$single_durations$duration <- + round(output[[appname]]$single_durations$duration, digits = digits) + } + + output[[appname]]$messages <- unique(message_vector) + + output[[appname]]$first_app_one_page <- firststageproblemparticipants + + if (length(warningparticipants) > 0) { + output[[appname]]$warnings <- unique(warningparticipants) + } + + } # Else: + # If single durations are not there + # This was already dealt with at another level + + return(output) + } + + # Call output_oneapp or output_moreapps + call_output_all_participants <- function(singledurations, message_vector, + firststageproblemparticipants, + warningparticipants) { + + # Output for all participants or several + if (length(apps) == 1) { + return(output_oneapp(singledurations, message_vector, + firststageproblemparticipants, + warningparticipants)) + } else { + message_vector <<- unique(message_vector) + + return(output_moreapps(singledurations, message_vector, + firststageproblemparticipants, + warningparticipants)) + } + } + + get_session <- function(who) { + if (is.null(sinfo)) { + session <- NA + } else { + if (sinfo == "session_id") { + session <- + unique(oTree$Time$session_id[ + oTree$Time[[participant_code_name]] == who]) + } else if (sinfo == "session_code") { + if (!is.null(oTree$Time$session_code)) { + session <- + unique(oTree$Time$session_code[ + oTree$Time[[participant_code_name]] == who]) + + } else if (!is.null(oTree$Time$session__code)) { + # Does this even exist? + # I don't have session__code in my current data + session <- + unique(oTree$Time$session__code[ + oTree$Time[[participant_code_name]] == who]) + } + } + } + return(session) + } + + # Call functions #### + for (appname in apps) { + + + if (!is.null(pcode)) { + # Time for app for specified individuals #### + output <- specified_time() + } else { + # Time for app for all participants #### + output <- all_time() + + if (length(output) == 1 && + grepl("Durations not calculated", output)) { + next + } + } + } + + # Return #### + return(output) +} diff --git a/R/assignv.R b/R/assignv.R new file mode 100644 index 0000000..681ad95 --- /dev/null +++ b/R/assignv.R @@ -0,0 +1,92 @@ +#' Assign a variable from all_apps_wide +#' @description +#' Assign a variable from all_apps_wide to the other app data frames. +#' @param oTree A list of data frames that were created by import_otree(). +#' @param variable Character. The variable in the all_apps_wide data frame that +#' should be assigned to all other apps. +#' @param newvar Character. The name of the newly created variable. +#' @returns This function returns a duplicate of the +#' original oTree list of data frames +#' but with an additional column in all data frames. The additional column +#' contains data from the specified variable found in all_apps_wide. +#' @examples +#' # Use package-internal list of oTree data frames +#' oTree <- gmoTree::oTree +#' +#' # Assign variable "survey.1.player.gender" and name it "gender" +#' oTree <- assignv(oTree = oTree, +#' variable = "survey.1.player.gender", +#' newvar = "gender") +#' +#' # Show the new variable in some of the other app data frames +#' oTree$dictator$gender +#' oTree$chatapp$gender +#' +#' # The variable is now duplicated in app "survey" because it is obtained from +#' # there (This can be avoided by naming the new variable the same as the old +#' # variable) +#' oTree$survey$gender +#' oTree$survey$player.gender +#' +#' # In app "all_apps_wide," the variable is also there twice (This can be +#' # avoided by naming the new variable the same as the old variable) +#' oTree$all_apps_wide$gender +#' oTree$all_apps_wide$survey.1.player.gender + +#' @export +assignv <- function(oTree, + variable, + newvar) { + + # Check #### + if (!("all_apps_wide" %in% names(oTree))) { + stop(paste0("There is no \"all_apps_wide\" in your oTree list of ", + "data frames!")) + } + + if (length(variable) > 1) { + stop("Plase enter only one variable name!") + } + + if (length(newvar) > 1) { + stop("Plase enter only one new variable name!") + } + + if (!(variable %in% colnames(oTree[["all_apps_wide"]]))) { + stop(paste0("The variable does not exist in \"all_apps_wide\"!")) + } + + # Create list of apps #### + appnames <- names(oTree) + appnames <- appnames[appnames != "info"] + + # Assign variable #### + for (i in unique(oTree$all_apps_wide$participant.code)) { + + for (app in appnames) { + + if (app != "Time" && app != "Chats") { + # Exclude custom exports + if ("participant.code" %in% colnames(oTree[[app]])) { + # Assign variable + oTree[[app]][[newvar]][oTree[[app]]$participant.code == i] <- + oTree[["all_apps_wide"]][[variable]][ + oTree[["all_apps_wide"]]$participant.code == i] + } + } else { + # Old / new differently + if (!is.null(oTree[[app]]$participant__code)) { + oTree[[app]][[newvar]][oTree[[app]]$participant__code == i] <- + oTree[["all_apps_wide"]][[variable]][ + oTree[["all_apps_wide"]]$participant.code == i] + + } else { + oTree[[app]][[newvar]][oTree[[app]]$participant_code == i] <- + oTree[["all_apps_wide"]][[variable]][ + oTree[["all_apps_wide"]]$participant.code == i] + } + } + } + } + return(oTree) +} diff --git a/R/assignv_to_aaw.R b/R/assignv_to_aaw.R new file mode 100644 index 0000000..4194d53 --- /dev/null +++ b/R/assignv_to_aaw.R @@ -0,0 +1,126 @@ +#' Assign a variable to all_apps_wide +#' @description +#' Assign a variable from one of the app data frames to all_apps_wide. +#' @param oTree A list of data frames that were created by import_otree(). +#' @param app Character. The data frame from which the variable is taken. +#' @param variable Character. +#' The name of the variable that should be assigned to all_apps_wide. +#' @param newvar Character. +#' The name of the newly created variable in the all_apps_wide data frame. +#' @param resafter Character. +#' The name of the variable that precedes the new variable. +#' If NULL, the new variable will be placed at the end of the data frame. +#' @returns This function returns a duplicate of the original oTree list of +#' data frames but with an additional column in the all_apps_wide data frame +#' that contains the variable in question. +#' @examples +#' # Use package-internal list of oTree data frames +#' oTree <- gmoTree::oTree +#' +#' # Create a new variable +#' oTree$survey$younger30 <- ifelse(oTree$survey$player.age < 30, 0, 1) +#' +#' # Assign the variable younger30 to all_apps_wide +#' oTree2 <- assignv_to_aaw( +#' oTree = oTree, +#' app = "survey", +#' variable = "younger30", +#' newvar = "younger30") +#' +#'# Show the new variable in the all_apps_wide data frame +#'oTree2$all_apps_wide$younger30 +#' +#'# Check the position of the new variable +#'match("younger30",names(oTree2$all_apps_wide)) +#' +#'# Place the new variable immediately after the "survey.1.player.age" variable +#'oTree2 <- assignv_to_aaw(oTree, +#' app = "survey", +#' variable = "younger30", +#' newvar = "younger30", +#' resafter = "survey.1.player.age") +#' +#'# Show the new variable in the all_apps_wide data frame +#'oTree2$all_apps_wide$younger30 +#' +#'# Show the position of the new variable +#'match("younger30", names(oTree2$all_apps_wide)) + +#' @export +assignv_to_aaw <- function(oTree, + app, + variable, + newvar, + resafter = NULL) { + + # Error messages #### + if (app == "Chats" || + app == "Time" || + app == "info" || + !("participant.code" %in% colnames(oTree[[app]]))) { + stop(paste0("This function does not work with ", + app, "!")) + } + + # Check if all_apps_wide is there + if ("all_apps_wide" %in% names(oTree)) { + if (nrow(oTree[[app]]) != nrow(oTree$all_apps_wide)) { + warning( + paste0("New variable is created. However, there is an unequal ", + "number of participants in \"all_apps_wide\" (", + nrow(oTree$all_apps_wide), + ") and app \"", app, + "\" (", + nrow(oTree[[app]]), + "). Did you forget to delete dropouts and empty cases ", + "or did you forget to import app data? Sometimes, this can ", + "happen if you import data from within a session or room ", + "where you can only import \"all_apps_wide\" but not the ", + "separate app data, time data or chat data.")) + } + } else { + stop(paste0("There is no \"all_apps_wide\" in your oTree list of ", + "data frames!")) + } + + # Check if there is only one variable/new variable + if (length(variable) > 1) { + stop("Plase enter only one variable name!") + } + + if (length(newvar) > 1) { + stop("Plase enter only one new variable name!") + } + + # Check if variable is there + if (is.null(oTree[[app]][[variable]])) { + stop("The variable does not exist in the app.") + } + + # Assign variable #### + for (i in oTree$all_apps_wide$participant.code) { + if (i %in% oTree[[app]]$participant.code) { + oTree$all_apps_wide[[newvar]][ + oTree$all_apps_wide$participant.code == i] <- + unique(oTree[[app]][[variable]][oTree[[app]]$participant.code == i]) + } + } + + # Rearrange #### + if (!is.null(resafter)) { + + # Make indices + indices <- c( + 1:which(names(oTree$all_apps_wide) == resafter), + ncol(oTree$all_apps_wide), # Put the new variable here + (which(names(oTree$all_apps_wide) == resafter) + 1): + (ncol(oTree$all_apps_wide) - 1) + ) + + # Apply indices + oTree$all_apps_wide <- oTree$all_apps_wide[, indices] + } + + # Return #### + return(oTree) +} diff --git a/R/constant_col.R b/R/constant_col.R new file mode 100644 index 0000000..cb4c940 --- /dev/null +++ b/R/constant_col.R @@ -0,0 +1,33 @@ +#' Show columns that have no variation +#' @description +#' This function is called by show_constant(). The app in question is already +#' specified there. I must admit that I found the idea to this code somewhere +#' on stackoverflow but cannot remember where. +#' @param df Data frame. +#' @param value The value that should be constant within a column. +#' @returns This function returns a vector of names of variables +#' that are constant. +#' @noRd + +constant_col <- function( + df, + value = NULL) { + + # Check all columns and create a named logical vector + if (!is.na(value)) { + + # Check for NA values + logi_vec <- sapply(df, function(df) all(!is.na(df) & df == value)) + + } else if (is.na(value)) { + + # Check for NA + logi_vec <- sapply(df, function(df) all(is.na(df))) + } + + # Get the names of all constant columns + const_vec <- names(df[!is.na(logi_vec) & logi_vec]) + + # Return + return(const_vec) +} diff --git a/R/delete_cases.R b/R/delete_cases.R new file mode 100644 index 0000000..aad721c --- /dev/null +++ b/R/delete_cases.R @@ -0,0 +1,395 @@ +#' Delete specific cases +#' @description +#' Delete specific cases from all data frames in the oTree list. +#' +#' Caution 1: This function does not delete cases from the original +#' CSV and Excel files! +#' +#' Caution 2: This function does not delete cases from custom exports +#' and custom data frames if these data frames do not have a variable +#' named participant.code! +#' +#' Caution 3: This function does not delete any data from the Chats data frame! +#' (As the interpretation of chat data depends on how participants +#' engage with each other, the data must be deleted +#' with more care than deleting data in other apps. +#' Hence, this function does not delete data in this data frame. +#' Please do this manually if necessary!) +#' @keywords oTree +#' @param oTree A list of data frames that were created by import_otree(). +#' @param pcodes Character. The value(s) of the participant.code variable of +#' the participants whose data should be removed. +#' @param plabels Character. The value(s) of the participant.label variable of +#' the participants whose data should be removed. +#' @param saved_vars Character. The name(s) of variable(s) that need(s) to be +#' stored in the list of information on deleted cases in $info$deleted_cases. +#' @param reason Character. The reason for deletion that should be stored in +#' the list of information on deleted cases in $info$deleted_cases. +#' @param omit Logical. TRUE if the deleted cases should not be added to +#' the information on deleted cases in $info$deleted_cases. +#' @param info Logical. TRUE if a brief information on the case deletion +#' process should be printed. +#' @returns This function returns a duplicate of the original oTree list +#' of data frames that do not include the deleted cases. +#' +#' It adds information on the deleted cases to $info$deleted_cases. (This +#' list is also filled by other functions.) +#' +#' In this list, you can find the following information: +#' +#' $codes = A vector with the participant codes of all deleted cases. +#' +#' $count = The number of participants in $codes. +#' +#' $full and $unique = The data frames $full and $unique contain information +#' on each deleted participant and the reason why they were +#' deleted. The entries to the $full and the $unique data frames are the same. +#' Columns "end_app" and "end_page" are left empty intentionally +#' because they are only filled by the delete_dropouts() function. +#' +#' @examples +#' # Use package-internal list of oTree data frames +#' oTree <- gmoTree::oTree +#' +#' # First, show some row numbers +#' print(paste(nrow(oTree$all_apps_wide), nrow(oTree$survey), +#' nrow(oTree$Time), nrow(oTree$Chats))) +#' +#' # Delete only one case +#' oTree2 <- delete_cases(oTree, +#' pcodes = "xmxl46rm", +#' reason = "requested") +#' +#' # Show row numbers again +#' print(paste(nrow(oTree2$all_apps_wide), nrow(oTree2$survey), +#' nrow(oTree2$Time), nrow(oTree2$Chats))) +#' +#' # Delete several cases +#' deletionlist <- c("4zhzdmzo", "xmxl46rm") +#' oTree2 <- delete_cases(oTree, +#' pcodes = deletionlist, +#' reason = "requested") +#' +#' # Show row numbers again +#' print(paste(nrow(oTree2$all_apps_wide), nrow(oTree2$survey), +#' nrow(oTree2$Time), nrow(oTree2$Chats))) +#' +#' # Show information on all deleted cases (also dropouts): +#' oTree2$info$deleted_cases$full +#' +#' # Save one variable +#' oTree2 <- delete_cases(oTree, +#' pcodes = deletionlist, +#' reason = "requested", +#' saved_vars = "participant._index_in_pages") +#' +#' # Show row numbers again +#' print(paste(nrow(oTree2$all_apps_wide), nrow(oTree2$survey), +#' nrow(oTree2$Time), nrow(oTree2$Chats))) +#' +#' # Save some variables +#' oTree2 <- delete_cases(oTree, +#' pcodes = deletionlist, +#' reason = "requested", +#' saved_vars = c( +#' "participant._index_in_pages", +#' "participant._max_page_index")) +#' +#' # Show row numbers again +#' print(paste(nrow(oTree2$all_apps_wide), nrow(oTree2$survey), +#' nrow(oTree2$Time), nrow(oTree2$Chats))) +#' +#' # Get a list of all deleted cases +#' # (If there is already a list, the new list is added to it) +#' oTree2$info$deleted_cases$codes +#' +#' # Show number of all deleted cases +#' length(oTree2$info$deleted_cases$codes) +#' oTree2$info$deleted_cases$count + +#' @export +delete_cases <- function(oTree, + pcodes = NULL, + plabels = NULL, + saved_vars = NULL, + reason, + omit = FALSE, + info = FALSE) { + + all_deleted <- c() + deletion_frame <- data.frame() + time_messed <- FALSE + chat_messed <- FALSE + messed_message <- c() + + # Create list of apps #### + appnames <- names(oTree) + appnames <- appnames[appnames != "info" & appnames != "Chats"] + + # Check if oTree is a list of data frames + if (!is.list(oTree) || + !(length(oTree) > 1)) { + stop("Your oTree is not a list of oTree data frames.") + } + + for (app in appnames) { + if (!(is.data.frame(oTree[[app]]))) { + stop("Your oTree is not a list of oTree data frames.") + } + } + + # Check mixed Time data + tryCatch({ + messy_time(oTree, combine = FALSE) + }, error = function(e) { + time_messed <<- TRUE + messed_message <<- paste0("Please run messy_time() with the argument ", + "combine=TRUE before running this function.") + }) + + # Check mixed Chat data + tryCatch({ + messy_chat(oTree, combine = FALSE) + }, error = function(e) { + chat_messed <<- TRUE + + if (time_messed == TRUE) { + + # Combine messy chat message with messy time message + messed_message <<- + paste0(messed_message, + " AND: Please run messy_chat() with the argument ", + "combine=TRUE before running this function.") + } else { + + # Make messy chat message + messed_message <<- + paste0("Please run messy_chat() with the argument ", + "combine=TRUE before running this function.") + } + }) + + # Stop if messy time and/or chat variables should not be merged + if (time_messed == TRUE || chat_messed == TRUE) { + stop(paste0("You combined data from old and new oTree versions. ", + messed_message)) + } + + # Warnings #### + my_messages <- c() + + # Stopping rules #### + if (is.null(plabels) && is.null(pcodes)) { + stop("Please specify pcodes or plabels!") + } + + if (!is.null(plabels) && !is.null(pcodes)) { + stop("Please only specify either pcodes or plabels!") + } + + if (!("all_apps_wide" %in% names(oTree)) && !is.null(saved_vars)) { + stop("The argument \"saved_vars\" only works when ", + "you have \"all_apps_wide\" in your ", + "oTree list of data frames.") + } + + if (!(is.null(saved_vars)) && + any(!(saved_vars %in% colnames(oTree$all_apps_wide)))) { + stop("saved_vars not in \"all_apps_wide\" data frame!") + } + + # Translate labels to codes #### + + # If pcodes was chosen #### + if (!is.null(pcodes)) { + + # Error messages + if (anyNA(pcodes)) { + stop("At least one element in pcodes is NA") + } + + del_participant_code_aaw <- + oTree$all_apps_wide$participant.code[ + oTree$all_apps_wide$participant.code %in% pcodes] + delete <- pcodes + } + + # If plabels was chosen #### + if (!is.null(plabels)) { + + if (anyNA(plabels)) { + stop("At least one element in plabel is NA") + } + + if (is.null(oTree$all_apps_wide$participant.code)) { + stop("Even though you chose option \"plabels\", ", + "this function needs the variable ", + "$all_apps_wide$participant.code to work. Did you delete it?" + ) + } + del_participant_code_aaw <- + oTree$all_apps_wide$participant.code[ + oTree$all_apps_wide$participant.label %in% plabels] + + delete <- del_participant_code_aaw + } + + # Get list of all deletion participants that really #### + # exist in the data frames #### + for (app in appnames) { + if (app != "Time" && app != "info" && app != "Chats") { + + # Exclude custom exports + if ("participant.code" %in% colnames(oTree[[app]])) { + + # Make vector + all_deleted <- c(all_deleted, + oTree[[app]]$participant.code[ + which(oTree[[app]]$participant.code %in% delete)]) + } + + } else if (app == "Time" || app == "Chats") { + # Old / new differently + if (!is.null(oTree[[app]]$participant__code)) { + all_deleted <- + c(all_deleted, + oTree[[app]]$participant__code[ + oTree[[app]]$participant__code %in% delete]) + + } else if (!is.null(oTree[[app]]$participant_code)) { + all_deleted <- + c(all_deleted, + oTree[[app]]$participant_code[ + oTree[[app]]$participant_code %in% delete]) + } + } + } + + if (length(all_deleted) == 0) { + stop("Participant(s) not in data frames.") + } + + # Create data frame of deletions #### + if (omit == FALSE && length(del_participant_code_aaw) > 0) { + + deletion_frame <- as.data.frame(oTree$all_apps_wide[ + oTree$all_apps_wide$participant.code %in% del_participant_code_aaw, + c("participant.code", "session.code", saved_vars)]) + + colnames(deletion_frame) <- c("participant.code", "session", saved_vars) + deletion_frame <- cbind(deletion_frame, + end_app = "", + end_page = "", + reason = reason) + + # Rearrange + deletion_frame <- deletion_frame[, c(c("participant.code", "session", + "end_app", "end_page", + "reason"), saved_vars)] + + oTree[["info"]][["deleted_cases"]][["full"]] <- plyr::rbind.fill( + oTree[["info"]][["deleted_cases"]][["full"]], + deletion_frame + ) + + # "unique" is the same as "full" because it is based on all_apps_wide! + oTree[["info"]][["deleted_cases"]][["unique"]] <- plyr::rbind.fill( + oTree[["info"]][["deleted_cases"]][["unique"]], + deletion_frame + ) + } else if (omit == FALSE && length(del_participant_code_aaw) == 0) { + + # Retrieve information on session.code in the next apps that contain the + # session code and the participant code + for (app_name in appnames) { + + if (any(pcodes %in% oTree[[app_name]]$participant.code) && + "session.code" %in% colnames(oTree[[app_name]])) { + + deletion_frame <- + plyr::rbind.fill( + deletion_frame, + as.data.frame(oTree[[app_name]][ + oTree[[app_name]]$participant.code %in% delete, + c("participant.code", "session.code") + ])) + } + } + + # Add reason + deletion_frame <- unique(deletion_frame) + deletion_frame <- cbind(deletion_frame, + end_app = NA, + end_page = NA, + reason = reason) + + # Add data frames to the data frames of deleted cases + oTree[["info"]][["deleted_cases"]][["full"]] <- plyr::rbind.fill( + oTree[["info"]][["deleted_cases"]][["full"]], + deletion_frame) + + oTree[["info"]][["deleted_cases"]][["unique"]] <- plyr::rbind.fill( + oTree[["info"]][["deleted_cases"]][["unique"]], + deletion_frame) + } + + # Check if chats are there + # This is the same in delete_dropouts + if ("Chats" %in% names(oTree)) { + my_messages <- c(my_messages, + paste0("Cases are deleted from all data frames. ", + "Except: ", + "The list of oTree data frames includes a chat. ", + "As the interpretation of chat data depends on ", + "how participants engage ", + "with each other, the data must be deleted with more care than ", + "deleting data in other apps. ", + "Hence, this function does not delete ", + "data in this data frame. Please do this manually if necessary!")) + } + + # Delete participant in all apps #### + for (app in appnames) { + if (app != "Time") { + # Exclude custom exports + if ("participant.code" %in% colnames(oTree[[app]])) { + + # Delete + oTree[[app]] <- + oTree[[app]][which(!(oTree[[app]]$participant.code %in% delete)), ] + } + + } else { + # Old / new differently + if (!is.null(oTree[["Time"]]$participant_code)) { + oTree[["Time"]] <- + oTree[["Time"]][ + !(oTree[["Time"]]$participant_code %in% delete), ] + } else { + oTree[["Time"]] <- + oTree[["Time"]][ + !(oTree[["Time"]]$participant__code %in% delete), ] + } + } + } + + # Message on deleted cases #### + my_messages <- c(paste(length(unique(all_deleted)), + "case(s) deleted. "), + my_messages) + + # Number of deleted cases + oTree[["info"]][["deleted_cases"]][["codes"]] <- + unique(c(unique(all_deleted), + oTree[["info"]][["deleted_cases"]][["unique"]]$participant.code)) + + oTree[["info"]][["deleted_cases"]][["count"]] <- + length(unique(oTree[["info"]][["deleted_cases"]][["codes"]])) + + # Return and warnings #### + if (info == TRUE) { + message(my_messages) + } + + return(oTree) +} diff --git a/R/delete_dropouts.R b/R/delete_dropouts.R new file mode 100644 index 0000000..0bb52de --- /dev/null +++ b/R/delete_dropouts.R @@ -0,0 +1,400 @@ +#' Delete dropouts +#' @description +#' Delete the data of all participants who did not end the experiment at (a) +#' certain page(s) and/or app(s). +#' +#' Caution 1: This function does not delete cases from the original CSV and +#' Excel files! +#' +#' Caution 2: This function does not delete cases from custom exports if the +#' custom exports do not have a variable named participant.code and a variable +#' named session.code! +#' +#' Caution 3: This function does not delete any data from the Chats data frame! +#' (As the interpretation of chat data depends on how participants engage with +#' each other, the data must be deleted with more care than deleting data in +#' other apps. Hence, this function does not delete data in this data frame. +#' Please do this manually if necessary!) +#' @keywords oTree +#' @param oTree A list of data frames that were created by import_otree(). +#' @param final_apps Character. +#' The name(s) of the app(s) at which the participants have to finish the +#' experiment. +#' @param final_pages Character. +#' The name(s) of the page(s) at which the participants have to finish the +#' experiment. +#' @param saved_vars Character. The name(s) of variable(s) that need(s) to be +#' stored in the list of information on deleted cases in $info$deleted_cases. +#' @param reason Character. The reason for deletion that should be stored in +#' the list of information on deleted cases in $info$deleted_cases. +#' @param inconsistent Character. Should the function continue or be stopped if +#' at least one participant has inconsistent end_pages, inconsistent end_apps, +#' or both? To continue, type "yes," +#' to stop the function, type "no." +#' @param info Logical. TRUE if a brief information on the dropout deletion +#' process should be printed. +#' @returns +#' This function returns a duplicate of the original oTree list of data frames +#' but without the deleted cases. +#' +#' It adds information on the deleted cases to $info$deleted_cases. (This +#' list is also filled by other functions.) +#' +#' In this list, you can find the following information: +#' +#' $full = A data frame that contains information +#' on all participants who did not finish the study; +#' it shows their participant codes, the names of the apps in which they +#' left the experiment, +#' the names of the pages in which they left the experiment, +#' the names of the app data frames in which this information was found, and +#' the dropout reason ("ENC," experiment not completed, combined +#' with the name of the data frame in which the dropout was observed). +#' Because participants usually appear in multiple app data frames, +#' the $info$deleted_cases$full data frame may contain several entries for +#' each person. +#' +#' $unique = A data frame that contains similar information as the $full data +#' frame but with only one row per participant and no information on the data +#' frame in which the dropout was observed. +#' +#' $all_end = A table that provides information on the app and page combinations +#' where participants ended the experiment. This table also includes +#' information for participants who did not drop out of the experiment. +#' The $all_end table is only shown if an all_apps_wide data frame exists. +#' +#' $codes = A vector containing the participant codes of +#' all deleted participants. +#' +#' $count = The number of all deleted participants. +#' +#' It is important to note that if only the argument final_pages is set, +#' this function does not distinguish between page names that reoccur in +#' different apps. +#' +#' If the columns end_app and end_page in the output are empty, +#' these variables were not saved by oTree for the specific participants. +#' This could be because empty rows were not deleted. This can be done +#' by using the argument "del_empty = TRUE" when using import_otree(). +#' @examples +#' # Use package-internal list of oTree data frames +#' oTree <- gmoTree::oTree +#' +#' # First, show some row numbers +#' print(paste(nrow(oTree$all_apps_wide), nrow(oTree$survey), +#' nrow(oTree$Time), nrow(oTree$Chats))) +#' +#' # Delete all cases that didn't end the experiment on the page "Demographics" +#' # within the app "survey" +#' oTree2 <- delete_dropouts(oTree, +#' final_apps = c("survey"), +#' final_pages = c("Demographics")) +#' +#' # Show row numbers again +#' print(paste(nrow(oTree2$all_apps_wide), nrow(oTree2$survey), +#' nrow(oTree2$Time), nrow(oTree2$Chats))) +#' +#' # Delete all cases that didn't end the experiment on the page "Demographics" +#' # This page can be in any app +#' oTree2 <- delete_dropouts(oTree, final_pages = "Demographics") +#' +#' # Show row numbers again +#' print(paste(nrow(oTree2$all_apps_wide), nrow(oTree2$survey), +#' nrow(oTree2$Time), nrow(oTree2$Chats))) +#' +#' # Delete all cases that didn't end the experiment on +#' # any page in the app "survey" +#' oTree <- delete_dropouts(oTree, final_apps = "survey") +#' +#' # Show row numbers again +#' print(paste(nrow(oTree2$all_apps_wide), nrow(oTree2$survey), +#' nrow(oTree2$Time), nrow(oTree2$Chats))) +#' +#' # Get list of information on all deleted cases +#' # (If there is already a list, the new list is added to it!) +#' oTree2$info$deleted_cases + +#' @export +delete_dropouts <- function(oTree, + final_apps = NULL, + final_pages = NULL, + saved_vars = NULL, + inconsistent = NULL, + reason = "ENC", + info = FALSE) { + keep_these_participants <- c() + delete_these_participants <- c() + dropout_data <- data.frame() + messages <- c() + + # Making sure the arguments are not empty #### + if (is.null(final_apps) && is.null(final_pages)) { + stop("Please specify final_apps or final_pages!") + } + + # Elements in oTree that are not apps #### + nonappelements <- c("Chats", "Time", "info", "deleted_cases") + + # Check if all apps wide and saved_vars work #### + if (!("all_apps_wide" %in% names(oTree)) && !is.null(saved_vars)) { + stop("The argument \"saved_vars\" only works when you ", + "have \"all_apps_wide\" in your ", + "oTree list of data frames.") + } else if ("all_apps_wide" %in% names(oTree) && !is.null(saved_vars)) { + # Check if saved_vars is in all_apps_wide + if (!(all(saved_vars %in% colnames(oTree$all_apps_wide)))) { + stop("\"saved_vars\" not in all_apps_wide.") + } + } + + # Inconsistency action #### + incons_function <- function(inconsistent = inconsistent) { + # Ask user whether they want to stop function + while (is.null(inconsistent) || + (inconsistent != "yes" && inconsistent != "no")) { + cat( + "At least one participant in the dropout list ", + "has inconsistent end pages,\n", + "inconsistent end apps, or both.\n", + "Do you still want to continue with the deletion of the cases?\n", + "Enter \"no\" to stop the function.\n", + "If you want to delete all cases that are marked as ", + "dropouts in at least one app, please enter \"yes\".\n", + "Input:\n") + + inconsistent <- readLines( + con = getOption("mypkg.connection"), + n = 1) + } + + # Stop if user requests it + if (inconsistent == "no") { + stop(paste0( + "At least one participant in the dropout list has ", + "inconsistent end pages,\n", + "inconsistent end apps, or both.\n", + "The user requested termination, hence no cases were deleted." + )) + } else if (inconsistent == "yes") { + messages <- c(paste0( + "At least one participant in the dropout list has ", + "inconsistent end pages,\n", + "inconsistent end apps, or both.\n", + "The user requested no termination of the function. " + ), messages) + return(messages) + } + } + + # Create list of included and excluded participants #### + for (i in seq_along(oTree)) { + + # Every app except ... + if (!(rlist::list.names(oTree[i]) %in% nonappelements)) { + + # Except user defined data frames + if ("participant._current_app_name" %in% colnames(oTree[[i]])) { + + # Check current apps + if (!is.null(final_apps)) { + appif <- oTree[[i]]$participant._current_app_name %in% final_apps + } else { + appif <- TRUE + } + + # Check current pages + if (!is.null(final_pages)) { + pageif <- oTree[[i]]$participant._current_page_name %in% final_pages + } else { + pageif <- TRUE + } + + # Add to the list of "keep" and "delete" people + keep_these_participants <- c(oTree[[i]]$participant.code[ + appif & pageif], keep_these_participants) + + delete_these_participants <- c(oTree[[i]]$participant.code[ + !(appif) | !(pageif)], delete_these_participants) + + # Make data frame of people who were excluded + dropout_data_app <- data.frame( + participant.code = oTree[[i]]$participant.code[ + !(appif) | !(pageif)], + session.code = oTree[[i]]$session.code[ + !(appif) | !(pageif)], + end_app = oTree[[i]]$participant._current_app_name[ + !(appif) | !(pageif)], + end_page = oTree[[i]]$participant._current_page_name[ + !(appif) | !(pageif)] + ) + + # Add reason + if (nrow(dropout_data_app) >= 1) { + for (j in seq_len(nrow(dropout_data_app))) { + dropout_data_app$reason[j] <- + paste0("ENC. ", + "Noticed at: ", rlist::list.names(oTree[i])) + } + dropout_data <- plyr::rbind.fill(dropout_data_app, dropout_data) + } + } else { + # User-made data frames are not tackled! + } + } + } + + keep_these_participants <- unique(keep_these_participants) + delete_these_participants <- unique(delete_these_participants) + + # Test if no one in "keep" is in "delete" #### + newlist <- c() + for (element in keep_these_participants) { + if (element %in% delete_these_participants) { + newlist <- append(element, newlist) + } + } + + if (length(newlist) > 0) { + messages <- incons_function(inconsistent) + } + + # Make output data frames of people deleted #### + if (nrow(dropout_data) >= 1) { + # Save variables for people who were excluded + if ("all_apps_wide" %in% names(oTree)) { + saved_vars_frame <- oTree$all_apps_wide[ + oTree$all_apps_wide$participant.code %in% delete_these_participants, + c( + "participant.code", + saved_vars + ) + ] + saved_vars_frame <- as.data.frame(saved_vars_frame) + colnames(saved_vars_frame) <- c("participant.code", saved_vars) + + # Info: "full" could have been defined in delete_cases, too + dropout_data <- unique(dropout_data) + + # Add saved variables + if (ncol(saved_vars_frame) > 0) { + dropout_data <- merge( + x = dropout_data, + y = saved_vars_frame, + by.x = "participant.code", + by.y = "participant.code", + all.x = TRUE, + all.y = TRUE + ) + } + } + + # Add to the existing full list (because of other deletions) + oTree[["info"]][["deleted_cases"]][["full"]] <- plyr::rbind.fill( + oTree[["info"]][["deleted_cases"]][["full"]], + dropout_data + ) + + # Unique + uniquelist <- c(c("participant.code", + "session.code", + "end_app", + "end_page"), + saved_vars) + dropout_data2 <- cbind(unique(dropout_data[uniquelist]), + "reason" = reason + ) + + oTree[["info"]][["deleted_cases"]][["unique"]] <- plyr::rbind.fill( + oTree[["info"]][["deleted_cases"]][["unique"]], + dropout_data2 + ) + } + + + # Make table of all ending apps #### + if ("all_apps_wide" %in% names(oTree)) { + # This is the only assignment of this table! + oTree[["info"]][["deleted_cases"]][["all_end"]] <- table( + oTree$all_apps_wide$participant._current_app_name, + oTree$all_apps_wide$participant._current_page_name + ) + } else { + warning("No \"all_apps_wide\" to make the table of end pages.") + } + + # Delete excluded participants from data frames #### + for (i in seq_along(oTree)) { + + # Every app except ... + if (!(rlist::list.names(oTree[i]) %in% nonappelements)) { + + # Except user defined data frames + if ("participant._current_app_name" %in% colnames(oTree[[i]])) { + + # Delete participants + oTree[[i]] <- + oTree[[i]][ + !(oTree[[i]]$participant.code %in% delete_these_participants), ] + } + } + } + + # For Time #### + # Not "keep these people" because of inconsistent end pages/apps + if (!is.null(oTree$Time$participant_code) && + !is.null(oTree$Time$participant__code)) { + oTree[["Time"]] <- + oTree[["Time"]][!( + (oTree$Time$participant_code %in% c(delete_these_participants)) | + (oTree$Time$participant__code %in% c(delete_these_participants))), ] + + } else if (!is.null(oTree$Time$participant_code) && + is.null(oTree$Time$participant__code)) { + oTree[["Time"]] <- + oTree[["Time"]][ + !(oTree$Time$participant_code %in% c(delete_these_participants)), ] + + } else if (is.null(oTree$Time$participant_code) && + !is.null(oTree$Time$participant__code)) { + oTree[["Time"]] <- + oTree[["Time"]][ + !(oTree$Time$participant__code %in% c(delete_these_participants)), ] + } + + # Message on deleted cases #### + messages <- c(paste(length(unique(delete_these_participants)), + "case(s) deleted\n"), + messages) + + # Check if chats are there + # This is the same in delete_cases + if ("Chats" %in% names(oTree)) { + messages <- + c(messages, + (paste0("Dropouts are deleted from all data frames. Except: ", + "The list of oTree data frames includes a chat. ", + "As the interpretation of chat data depends ", + "on how participants engage ", + "with each other, the data must be deleted ", + "with more care than ", + "deleting data in other apps. ", + "Hence, this function does not delete ", + "data in this data frame. Please do this ", + "manually if necessary!"))) + } + + # Codes and number of deleted cases #### + oTree[["info"]][["deleted_cases"]][["codes"]] <- + unique(c(oTree[["info"]][["deleted_cases"]][["codes"]], + oTree[["info"]][["deleted_cases"]][["unique"]]$participant.code)) + + oTree[["info"]][["deleted_cases"]][["count"]] <- + nrow(oTree[["info"]][["deleted_cases"]][["unique"]]) + + # Return and messages #### + if (info == TRUE) { + message(messages) + } + + return(oTree) +} diff --git a/R/delete_duplicate.R b/R/delete_duplicate.R new file mode 100644 index 0000000..3703556 --- /dev/null +++ b/R/delete_duplicate.R @@ -0,0 +1,72 @@ +#' Delete duplicate data +#' @description +#' Delete duplicate rows from all oTree app data frames and all_apps_wide. +#' @keywords oTree +#' @param oTree A list of data frames that were created by import_otree(). +#' @returns This function returns a duplicate of the original oTree +#' list of data frames but without duplicate rows in all app data +#' frames and all_apps_wide. This function has no effect on the data +#' frames Time and Chats. +#' +#' This function does NOT add information to $info$deleted_cases, +#' because it does not delete any important information but only +#' cleans up a messy data import. +#' +#' However, the function adjusts info$initial_n, if an all_apps_wide +#' data frame exists. +#' @examplesIf rlang::is_installed("withr") +#' # Set data folder first +#' withr::with_dir(system.file("extdata", package = "gmoTree"), { +#' +#' # Import all oTree files in this folder and its subfolders +#' oTree <- import_otree() +#' }) +#' +#' # First, show some row numbers +#' print(paste(nrow(oTree$all_apps_wide), nrow(oTree$survey), +#' nrow(oTree$Time), nrow(oTree$Chats))) +#' +#' # Delete duplicate rows +#' oTree <- delete_duplicate(oTree) +#' +#' # Show row numbers again +#' print(paste(nrow(oTree$all_apps_wide), nrow(oTree$survey), +#' nrow(oTree$Time), nrow(oTree$Chats))) + + +#' @export +delete_duplicate <- function(oTree) { + + appnames <- names(oTree) + appnames <- appnames[appnames != "info"] + appnames <- appnames[appnames != "Time"] + appnames <- appnames[appnames != "Chats"] + + for (app in appnames) { + columns <- names(oTree[[app]]) + columns <- columns[columns != "participant.label"] + + oTree[[app]] <- + dplyr::distinct(oTree[[app]], .keep_all = TRUE, !!! rlang::syms(columns)) + } + + if ("all_apps_wide" %in% names(oTree)) { + oTree$info$initial_n <- nrow(oTree$all_apps_wide) + # message(paste0("Any duplicate rows are deleted. ", + # "Information on deleted rows is not added to ", + # "the list of deleted ", + # "cases because this list might be used for analyses, and ", + # "this function only accounts for a messy data import. ", + # "info$initial_n is adjusted.")) + } + # else { + # message(paste0( + # "Any duplicate rows are deleted. ", + # "Information on deleted rows is not added to + # "the list of deleted ", + # "cases because this list might be used for analyses, and ", + # "this function only accounts for a messy data import.")) + # } + + return(oTree) +} diff --git a/R/delete_plabels.R b/R/delete_plabels.R new file mode 100644 index 0000000..9687f83 --- /dev/null +++ b/R/delete_plabels.R @@ -0,0 +1,59 @@ +#' Delete participant labels in all apps +#' @description +#' If you work with MTurk, the MTurk IDs will be stored in the +#' participant labels variable. +#' This function deletes this variable in all_apps_wide and every app data frame +#' in the list of data frames that was created by import_otree() and/or all +#' variables referring to MTurk, such as participant.mturk_worker_id. +#' @param oTree A list of data frames that were created by import_otree(). +#' @param del_plabel Logical. +#' TRUE if all participant labels should be deleted. +#' @param del_mturk Logical. +#' TRUE if all MTurk variables should be deleted. +#' @returns This function returns a duplicate of the original oTree list of +#' data frames that do not include the participant labels and/or the MTurk +#' variables. +#' @examples +#' # Use package-internal list of oTree data frames +#' oTree <- gmoTree::oTree +#' +#'# Show participant labels +#' oTree$all_apps_wide$participant.label +#' oTree$survey$participant.label +#' +#' # Delete all participant labels +#' oTree2 <- delete_plabels(oTree) +#' +#' # Show participant labels again +#' oTree2$all_apps_wide$participant.label +#' oTree2$survey$participant.label + +#' @export +delete_plabels <- function(oTree, + del_plabel = TRUE, + del_mturk = TRUE) { + + # Create list of apps #### + appnames <- names(oTree) + appnames <- appnames[appnames != "info"] + + # Delete variable #### + if (del_plabel == TRUE) { + for (app in appnames) { + oTree[[app]][["participant.label"]] <- NULL + } + } + + if (del_mturk == TRUE) { + for (app in appnames) { + oTree[[app]][["participant.mturk_worker_id"]] <- NULL + oTree[[app]][["participant.mturk_assignment_id"]] <- NULL + oTree[[app]][["mturk_HITGroupId"]] <- NULL + oTree[[app]][["mturk_HITId"]] <- NULL + oTree[[app]][["session.mturk_HITId"]] <- NULL + oTree[[app]][["session.mturk_HITGroupId"]] <- NULL + } + } + + return(oTree) +} diff --git a/R/delete_sessions.R b/R/delete_sessions.R new file mode 100644 index 0000000..02da28d --- /dev/null +++ b/R/delete_sessions.R @@ -0,0 +1,344 @@ +#' Delete all cases of one session +#' @description +#' Delete cases from specific sessions in all data frames in the +#' oTree list of data frames. +#' +#' Caution 1: This function does not delete cases from the +#' original CSV and Excel files! +#' +#' Caution 2: This function does not delete cases from custom exports if the +#' custom exports do not have a variable named participant.code and a variable +#' named session.code! +#' @keywords oTree +#' @param oTree A list of data frames that were created by import_otree(). +#' @param scodes Character. The session.code(s) of the +#' session(s) whose data should be removed. +#' @param saved_vars Character. The name(s) of variable(s) that need(s) to be +#' stored in the list of information on deleted cases in $info$deleted_cases. +#' @param reason Character. The reason for deletion that should be stored in +#' the list of information on deleted cases in $info$deleted_cases. +#' @param info Logical. TRUE if a brief information on the session +#' deletion process should be printed. +#' @returns This function returns a duplicate of the original oTree list of +#' data frames that do not include the deleted sessions. +#' +#' It adds information on the deleted cases to $info$deleted_cases. (This +#' list is also filled by other functions.) +#' +#' In this list, you can find the following information: +#' +#' $full and $unique = The data frames $full and $unique contain +#' information on all participants +#' whose data were deleted. The entries to the $full and the $unique data +#' frames in this list are the same. Columns "end_app" and "end_page" are left +#' empty intentionally because they are only filled by the delete_dropouts() +#' function. Columns "participant.code" and "reason" are filled. +#' +#' $codes = A vector containing the participant codes of +#' all deleted participants. +#' +#' $count = The number of all deleted participants. +#' @examples +#' # Use package-internal list of oTree data frames +#' oTree <- gmoTree::oTree +#' +#' # First, show some row numbers +#' print(paste(nrow(oTree$all_apps_wide), nrow(oTree$survey), +#' nrow(oTree$Time), nrow(oTree$Chats))) +#' +#' # Delete one session +#' oTree2 <- delete_sessions(oTree, +#' scodes = "7bfqtokx", +#' reason = "Only tests") +#' +#' # Show row numbers +#' print(paste(nrow(oTree2$all_apps_wide), nrow(oTree2$survey), +#' nrow(oTree2$Time), nrow(oTree2$Chats))) +#' +#' # Delete two sessions +#' oTree2 <- delete_sessions(oTree, +#' scodes = c("7bfqtokx", "vd1h01iv"), +#' reason = "Only tests") +#' +#' # Show row numbers again +#' print(paste(nrow(oTree2$all_apps_wide), nrow(oTree2$survey), +#' nrow(oTree2$Time), nrow(oTree2$Chats))) + +#' @export +delete_sessions <- function(oTree, + scodes, + saved_vars = NULL, + reason, + info = FALSE) { + + messages <- c() + deleted_participants <- c() + deletion_frame <- data.frame() + time_messed <- FALSE + chat_messed <- FALSE + messed_message <- c() + + # Create list of apps #### + appnames <- names(oTree) + appnames <- appnames[appnames != "info"] + + # Check if oTree is a list of data frames + if (!is.list(oTree) || + !(length(oTree) > 1)) { + stop("Your oTree is not a list of oTree data frames.") + } + + for (app in appnames) { + if (!(is.data.frame(oTree[[app]]))) { + stop("Your oTree is not a list of oTree data frames.") + } + } + + # Check mixed Time data + tryCatch({ + messy_time(oTree, combine = FALSE) + }, error = function(e) { + time_messed <<- TRUE + messed_message <<- paste0("Please run messy_time() with the argument ", + "combine=TRUE before running this function.") + }) + + # Check mixed Chat data + tryCatch({ + messy_chat(oTree, combine = FALSE) + }, error = function(e) { + chat_messed <<- TRUE + + if (time_messed == TRUE) { + messed_message <<- + paste0(messed_message, + " AND: Please run messy_chat() with the argument ", + "combine=TRUE before running this function.") + } else { + messed_message <<- + paste0("Please run messy_chat() with the argument ", + "combine=TRUE before running this function.") + } + }) + + if (time_messed == TRUE || chat_messed == TRUE) { + stop(paste0("You combined data from old and new oTree versions. ", + messed_message)) + } + + # Set background function: chat function #### + # The Time data frame is special because old sessions + # are not deleted from the data frame + + delete_chats_sessions <- function() { + # Old / new differently + if (!is.null(oTree[["Chats"]]$session_code)) { + oTree[["Chats"]] <- + oTree[["Chats"]][ + !(oTree[["Chats"]]$session_code %in% scodes), ] + + } else if (!is.null(oTree[["Chats"]]$session__code)) { + # Not sure if that's needed + oTree[["Chats"]] <- + oTree[["Chats"]][ + !(oTree[["Chats"]]$session__code %in% scodes), ] + + } else if (!is.null(oTree[["Chats"]]$participant__session__code)) { + oTree[["Chats"]] <- + oTree[["Chats"]][ + !(oTree[["Chats"]]$participant__session__code %in% scodes), ] + + } else { + + if (!is.null(oTree[["Chats"]]$participant_code)) { + # Not sure if that's needed because session_code is there anyway + oTree[["Chats"]] <- + oTree[["Chats"]][ + !oTree[["Chats"]]$participant_code %in% deleted_participants, ] + + } else if (!is.null(oTree[["Chats"]]$participant__code)) { + + oTree[["Chats"]] <- + oTree[["Chats"]][ + !oTree[["Chats"]]$participant__code %in% deleted_participants, ] + } + } + return(oTree) + } + + # Get list of all participants to be deleted that really exist in the DF #### + for (app in appnames) { + + if (app != "Time" && app != "info" && app != "Chats") { + + if (all(c("participant.code", "session.code") %in% + names(oTree[[app]]))) { # Exclude custom exports + + deleted_participants <- + c(deleted_participants, + oTree[[app]]$participant.code[ + (oTree[[app]]$session.code %in% scodes)]) + } + + } else if (app == "Time") { + + # Old / new differently + if (!is.null(oTree[["Time"]]$session__code)) { + # Not sure if needed + deleted_participants <- + c(deleted_participants, + oTree[["Time"]]$participant__code[ + oTree[["Time"]]$session__code %in% scodes]) + + } else if (!is.null(oTree[["Time"]]$session_code)) { + deleted_participants <- + c(deleted_participants, + oTree[["Time"]]$participant_code[ + (oTree[["Time"]]$session_code %in% scodes)]) + } else { + warning(paste0("No variable called \"session code\" in ", + "the \"Time\" data frame. ", + "Session information is taken from the ", + "data frames of the ", + "other apps and/or \"all_apps_wide\".")) + } + + } else if (app == "Chats") { + if (!is.null(oTree[[app]]$session_code)) { + deleted_participants <- + c(deleted_participants, + oTree[[app]]$participant_code[ + oTree[[app]]$session_code %in% scodes]) + + } else if (!is.null(oTree[[app]]$session__code)) { + # Not sure if needed + deleted_participants <- + c(deleted_participants, + oTree[[app]]$participant__code[ + (oTree[[app]]$session__code %in% scodes)]) + + } else if (!is.null(oTree[[app]]$participant__session__code)) { + deleted_participants <- + c(deleted_participants, + oTree[[app]]$participant__code[ + oTree[["Chats"]]$participant__session__code %in% + scodes]) + + } else { + warning( + paste0("No variable called \"session code\" ", + "in the Chats data frame. ", + "Session information is taken from the ", + "data frames of the ", + "other apps and/or \"all_apps_wide\".")) + } + } + } + + #################################### + if (length(deleted_participants) == 0) { + warning(paste0("The session can not be found in any of the data frames.")) + return(oTree) + } + + # Create data frame of deletions #### + if ("all_apps_wide" %in% names(oTree)) { + deletion_frame <- as.data.frame(oTree$all_apps_wide[ + oTree$all_apps_wide$participant.code %in% deleted_participants, + c("participant.code", "session.code", saved_vars)]) + + colnames(deletion_frame) <- c("participant.code", + "session.code", + saved_vars) + + deletion_frame <- cbind(deletion_frame, + end_app = "", + end_page = "", + reason = reason) + + oTree[["info"]][["deleted_cases"]][["full"]] <- plyr::rbind.fill( + oTree[["info"]][["deleted_cases"]][["full"]], + deletion_frame) + + oTree[["info"]][["deleted_cases"]][["unique"]] <- plyr::rbind.fill( + oTree[["info"]][["deleted_cases"]][["unique"]], + deletion_frame) # Deletion frame is already unique! + + } else { + # Retrieve information on session.code in the next apps that contain the + # session code and the participant code + + for (app_name in appnames) { + if (!(app_name %in% c("Chats", "Time", "info"))) { + + if (all(c("participant.code", "session.code") %in% + colnames(oTree[[app_name]]))) { # Exclude custom exports + + deletion_frame <- plyr::rbind.fill( + deletion_frame, + as.data.frame(oTree[[app_name]][ + oTree[[app_name]]$participant.code %in% deleted_participants, + c("participant.code", "session.code")])) + } + } + } + + # Add reason + deletion_frame <- unique(deletion_frame) + deletion_frame <- cbind(deletion_frame, + end_app = NA, + end_page = NA, + reason = reason) + + # Add data frames to the data frames of deleted cases + oTree[["info"]][["deleted_cases"]][["full"]] <- plyr::rbind.fill( + oTree[["info"]][["deleted_cases"]][["full"]], + deletion_frame) + + oTree[["info"]][["deleted_cases"]][["unique"]] <- plyr::rbind.fill( + oTree[["info"]][["deleted_cases"]][["unique"]], + deletion_frame) + } + + # Delete participant in all apps #### + for (app in appnames) { + if (app != "Time" && app != "Chats") { + if (all(c("participant.code", "session.code") %in% + colnames(oTree[[app]]))) { # Exclude custom exports + + oTree[[app]] <- oTree[[app]][which(!(oTree[[app]]$session.code %in% + scodes)), ] + } + } else if (app == "Time") { + # Old / new differently + if (!is.null(oTree[["Time"]]$session_code)) { + oTree[["Time"]] <- oTree[["Time"]][!(oTree[["Time"]]$session_code %in% + scodes), ] + } else { + oTree[["Time"]] <- oTree[["Time"]][!(oTree[["Time"]]$session__code %in% + scodes), ] + # I'm not sure if it was saved like that in the old versions + } + } else if (app == "Chats") { + oTree <- delete_chats_sessions() + } + } + + # Message on deleted cases #### + messages <- c(paste(length(unique(deleted_participants)), "case(s) deleted"), + messages) + + # Number of deleted cases #### + oTree[["info"]][["deleted_cases"]][["codes"]] <- unique( + c(unique(deleted_participants), + oTree[["info"]][["deleted_cases"]][["unique"]]$participant.code)) + oTree[["info"]][["deleted_cases"]][["count"]] <- length(unique( + oTree[["info"]][["deleted_cases"]][["codes"]])) + + # Return and print messages #### + if (info == TRUE) { + message(messages) + } + + return(oTree) +} diff --git a/R/extime.R b/R/extime.R new file mode 100644 index 0000000..6d2a0b3 --- /dev/null +++ b/R/extime.R @@ -0,0 +1,602 @@ +#' Calculate the time that was spent on the whole experiment +#' @description +#' Calculate the time spent on the experiment. +#' If not stated otherwise, the calculation only starts at the end of +#' the first page! +#' @param oTree A list of data frames that were created by import_otree(). +#' @param pcode Character. The value of the participant.code variable if the +#' time should only be calculated for one specified participant. +#' @param plabel Character. The value of the participant.label variable if the +#' time should only be calculated for one specified participant. +#' @param group_id Integer. The value of the group_id variable if the +#' time should only be calculated for one specified group. The group_id +#' variable can be created with make_ids(). +#' @param seconds Logical. +#' TRUE if the output should be in seconds instead of minutes. +#' @param rounded Logical. TRUE if the output should be rounded. +#' @param digits Integer. The number of digits to which the output +#' should be rounded. +#' This parameter has no effect unless rounded = TRUE. +#' @param startat Integer or character string "real". +#' Whether the start of the experiment should be taken from the time at +#' a certain index of each person's vector of page_indexes in the +#' Time data frame or from the "time_started" +#' variable in all_apps_wide ("real"). Important: If integer, +#' it represents the position within the page index sequence, +#' not the numeric value of the index. +#' @param tz Character. Time zone. +#' @param sinfo Character. +#' "session_id" to use session ID for additional information in the data frame +#' of single durations, "session_code" to use session codes, or NULL if no +#' session column should be shown. +#' @param combine Logical. TRUE if all variables referring to epoch time should +#' be merged, and all variables referring to participant code should +#' be merged in case data of several versions of oTree are used. If FALSE, +#' the function returns an error if several oTree versions' data are present. +#' @returns +#' This function returns either a single value if only the data of one person +#' is calculated or a list of information on the time several participants +#' spent on the experiment. +#' +#' In this list, you can find the following information: +#' +#' $mean_duration = The experiment's average duration. +#' +#' $min_duration = The experiment's minimum duration. +#' +#' $max_duration = The experiment's maximum duration. +#' +#' $single_durations = A data frame of all durations that +#' are used for calculating the min, max, and mean duration. +#' +#' $messages = All important notes to the calculations. +#' +#' $only_one_page = A vector of all individuals who only have one time stamp. +#' @keywords oTree +#' @examples +#' # Use package-internal list of oTree data frames +#' oTree <- gmoTree::oTree +#' +#' # Make a data frame of durations +#' extime(oTree) +#' +#' # Show time for one participant +#' extime(oTree, pcode = "wk247s9w") + +#' @export +extime <- function( + oTree, + pcode = NULL, + plabel = NULL, + group_id = NULL, + seconds = FALSE, + rounded = TRUE, + digits = 2, + startat = 1, + tz = "UTC", + sinfo = "session_code", + combine = TRUE) { + + # Info: epoch_time is called epoch_time_completed in the new oTree version. + # The code works nevertheless. + # Old Version of oTree (time_stamp & participant__code) + # New Version of oTree (epoch_time & participant_code) + + firststageproblemparticipants <- c() + messages <- c() + + # Define error and warning messages #### + errormax1min1 <- paste0( + "Warning: For at least one participant, the experiment only has one page. ", + "I.e., the indices for the first and the last page are the same. ", + "See $only_one_page for information on this participant", + "/these participants! Participants in this list are not included in the ", + "output." + ) + + errormax1min1_specific <- paste0( + "Warning: For this participant, the experiment only has one page. ", + "I.e., the indices for the first and the last page are the same. " + ) + + indextoohigh <- FALSE + indextoohigh_message <- + paste0("The chosen starting value startat is higher than the ", + "total number of all indices (for at least one case if more participants ", + "are chosen). Please select a valid starting value.") + + indextoolow <- FALSE + indextoolow_message <- + paste0("The chosen starting value startat is lower than ", + "the lowest number of all indices (for at least one case if ", + "more participants are chosen). Please select a valid starting value.") + + + # Error handling #### + if (is.null(oTree$Time)) { + stop("There is no \"Time\" data frame.") + } + + if (nrow(oTree$Time) == 0) { + stop("Your \"Time\" data frame is empty") + } + + if (startat == "real" && is.null(oTree$all_apps_wide)) { + stop("The argument \"startat = real\" only works if there is a ", + "\"all apps wide\" data frame in your oTree list of data frames!") + } + + if (startat != "real" && startat < 1) { + stop("Please choose a valid \"startat\"!") + } + + # Check if there are too many epoch times and participant code variables + withCallingHandlers({ + oTree <- messy_time(oTree, combine = combine) + }, error = function(e) { + stop("It seems as if you are using data from different oTree versions. ", + "Please combine the participant and time stamp variables manually ", + "or use combine=TRUE.") + }, warning = function(w) { + # Don't show any warnings, because the oTree list of data frames + # does not change due to this function! + invokeRestart("muffleWarning") + }) + + # Set time variable + if ("epoch_time" %in% colnames(oTree$Time)) { + timestamp_var_name <- "epoch_time" + } else if ("epoch_time_completed" %in% colnames(oTree$Time)) { + timestamp_var_name <- "epoch_time_completed" + } else if ("time_stamp" %in% colnames(oTree$Time)) { + timestamp_var_name <- "time_stamp" + } else { + stop("There is no variable referring to the epoch time tamp ", + "in your Time data frame. ", + "This should be a variable called either \"epoch time,\" ", + "\"epoch_time_completed,\" or ", + "\"time stamp.\"") + } + + # Set participant code variable + if ("participant_code" %in% colnames(oTree$Time)) { + participant_code_name <- "participant_code" + } else if ("participant__code" %in% colnames(oTree$Time)) { + participant_code_name <- "participant__code" + } else { + stop("There is no variable referring to the ", + "participant code in your Time data frame. ", + "This should be a variable called either \"participant_code,\" or", + "\"participant__code.\"") + } + + # Other errors #### + if (length(pcode) > 1) { + stop("Please enter only one participant!") + } + + if (!is.null(sinfo) && + !(sinfo %in% c("session_code", "session_id"))) { + stop("Please specify a valid sinfo! Possibilities are ", + "\"session_code\" or \"session_id\"") + } + + if (!is.null(pcode) && !is.null(group_id)) { + stop("Please specify either the pcode or the group_id, ", + "but not both together.") + } + + if (!is.null(pcode) && + !(pcode %in% oTree$Time[[participant_code_name]])) { + stop("The participant is not in the \"Time\" data frame.") + + } + + if (!is.null(plabel) && !is.null(group_id)) { + stop("Please enter only plabel or group_id") + } + + if (!is.null(pcode) && !is.null(plabel)) { + stop("Please enter only pcode or plabel") + } + + if (length(plabel) > 1) { + stop("Please enter only one participant label!") + } + + if (is.null(oTree$all_apps_wide) && !is.null(plabel)) { + stop(paste0("You can only use the argument plabel ", + "if there is an all_apps_wide-data frame in your oTree list")) + } + + if (!is.null(group_id) && + !is.null(oTree$Time) && + is.null(oTree$Time$group_id)) { + stop(paste0("There is no variable called group_id in your ", + "\"Time\" data frame. \n", + "Please run make_ids first before using this function. ", + "(Use argument gmake = TRUE.)")) + } + + if (!is.null(group_id) && + !is.null(oTree$Time$group_id) && + !(group_id %in% oTree$Time$group_id)) { + stop(paste0("group_id ", + group_id, + "is not in your \"Time\" data frame.")) + } + + if (!is.null(sinfo) && + sinfo == "session_id" && + is.null(oTree$Time$session_id)) { + stop("There is no session_id in the \"Time\" data frame") + } + + if (!is.null(sinfo) && + sinfo == "session_code" && + is.null(oTree$Time$session_code) && + is.null(oTree$Time$session__code)) { + stop( + paste0("There is no variable called session_code or session__code ", + "in the \"Time\" ", + "data frame.\n Try sinfo=\"session_id,\" ", + "or use ", + "argument sinfo = NULL if you do not need session information." + )) + } + + # Check for several session_code infos in Time data frame + if (!is.null(sinfo)) { + + # Check if there are old and new session_code variables + length_session_code_variables <- sum( + c("session_code", + "session__code", + "participant__session__code") %in% colnames(oTree$Time)) + + if (length_session_code_variables > 1) { + # Are there old oTree versions where this could be relevant? + # I did not test for multiple session codes in messy_time() + stop("Multiple variables referring to the session code were ", + "detected in your \"Time\" data frame. ", + "This issue may arise if data from different versions of ", + "oTree are combined within the same data frame. ", + "Before using this function, please combine these variables ", + "into a single one.") + } + } + + # Seconds #### + if (seconds == TRUE) { + divsec <- 1 + } else { + divsec <- 60 # Divide seconds by 60 to get minutes + } + + # Transform plabel to pcode identifier #### + if (!is.null(plabel)) { + if (length(unique(oTree$all_apps_wide$participant.label)) == + length(oTree$all_apps_wide$participant.label)) { + + pcode <- oTree$all_apps_wide$participant.code[ + oTree$all_apps_wide$participant.label == plabel] + } else { + stop("You do not have unique participant labels in your ", + "all_apps_wide data frame! The argument plabel is ", + "not working in such a case!") + } + } + + # Make sub functions 1 - indices and time stamps and durations #### + calc_max_index <- function(allindices) { + max_index <- if (length(allindices)) { + max(allindices) + } else { + NA + } + return(max_index) # Returns to higher level function + } + + min_max_stamps_dur_spec <- function(allindices, + who, + max_index = max_index) { + + # First time stamp for specific individuals + if (startat == "real") { + mintimestamp <- as.numeric( + as.POSIXct(oTree$all_apps_wide$participant.time_started[ + oTree$all_apps_wide$participant.code == who + ], tz = tz)) + + } else { + # Check if startat is valid + if (startat > length(allindices)) { + indextoohigh <<- TRUE + stop(indextoohigh_message) + + } else if (startat < min(allindices)) { + indextoolow <<- TRUE + stop(indextoolow_message) + } + + # Assign minimum time stamp + mintimestamp <- oTree$Time[[timestamp_var_name]][ + !is.na(oTree$Time[[participant_code_name]]) & + oTree$Time[[participant_code_name]] == who & + oTree$Time$page_index == allindices[[startat]]] + } + + # Last time stamp for specific individuals + maxtimestamp <- oTree$Time[[timestamp_var_name]][ + !is.na(oTree$Time[[participant_code_name]]) & + oTree$Time[[participant_code_name]] == who & + oTree$Time$page_index == max_index] + + # Duration of the whole experiment + duration <- (maxtimestamp - mintimestamp) / divsec + + return(duration) + } + + # Minimum time stamp + mintimestamp_all <- function(allindices) { + # First stamp for all individuals + + # Check if startat is valid + if (startat == "real") { + mintimestamp <- as.numeric( + as.POSIXct(oTree$all_apps_wide$participant.time_started[ + oTree$all_apps_wide$participant.code == i + ], tz = tz)) + } else { + if (startat > length(allindices)) { + indextoohigh <<- TRUE + stop() + } else if (startat < min(allindices)) { + indextoolow <<- TRUE + stop() + } + + # Assign minimum time stamp + mintimestamp <- oTree$Time[[timestamp_var_name]][ + !is.na(oTree$Time[[participant_code_name]]) & + oTree$Time[[participant_code_name]] == i & + oTree$Time$page_index == allindices[[startat]]] + + } + return(mintimestamp) # Returns to next higher level + } + + # Make sub functions 2 - duration calculation #### + duration_specific <- function() { + # Duration for one person + # Info: Existence of this person in the Time data frame was already checked + # at the beginning of the extime function! + + # Get indices - specific + allindices <- + oTree$Time$page_index[ + oTree$Time[[participant_code_name]] == pcode] + allindices <- allindices[!is.na(allindices)] + max_index <- calc_max_index(allindices) + + # Calculate time - specific + if ((max_index == 1 && min(allindices) == 1) || + max_index == 0) { + + # Warning: If there is only one page in the experiment + firststageproblemparticipants <<- c(firststageproblemparticipants, pcode) + messages <<- c(messages, errormax1min1_specific) + duration <- NA + + } else { + # Get time stamps and duration - specific + duration <- min_max_stamps_dur_spec(allindices = allindices, + who = pcode, + max_index = max_index) + } + + # Return output - specific to next higher level + return(duration) + } + + duration_all <- function() { + # Duration for several individuals + # Info: List of participants is from Time data frame itself + # so there is no need to control for empty indices vectors + + allindices <- + oTree$Time$page_index[oTree$Time[[participant_code_name]] == i] + allindices <- allindices[!is.na(allindices)] + max_index <- calc_max_index(allindices) + + if (max_index == 0 || + (max_index == 1 && min(allindices) == 1)) { + # Warning: If there is only one page in the experiment + firststageproblemparticipants <<- c(firststageproblemparticipants, i) + messages <<- c(messages, errormax1min1) + duration <- NA + + } else { + # Get time stamps and duration + mintimestamp <- mintimestamp_all(allindices) + maxtimestamp <- oTree$Time[[timestamp_var_name]][ + !is.na(oTree$Time[[participant_code_name]]) & + oTree$Time[[participant_code_name]] == i & + oTree$Time$page_index == max_index] + duration <- (maxtimestamp - mintimestamp) / divsec + } + + # Returns duration_all to next higher level + return(duration) + } + + # Get session information for singledurations table + get_session <- function(who) { + if (is.null(sinfo)) { + session <- NA + } else { + if (sinfo == "session_id") { + session <- unique(oTree$Time$session_id[ + !is.na(oTree$Time[[participant_code_name]]) & + oTree$Time[[participant_code_name]] == who]) + + } else if (sinfo == "session_code") { + if (!is.null(oTree$Time$session_code)) { + session <- unique(oTree$Time$session_code[ + !is.na(oTree$Time[[participant_code_name]]) & + oTree$Time[[participant_code_name]] == who]) + + } else if (!is.null(oTree$Time$session__code)) { + # Is that even happening? I don't have such data yet. + session <- unique(oTree$Time$session__code[ + !is.na(oTree$Time[[participant_code_name]]) & + oTree$Time[[participant_code_name]] == who]) + } + } + } + return(session) + } + + # Make output for several/all individuals + output_all <- function() { + output <- list() + + output[["mean_duration"]] <- ifelse( + rounded == TRUE, + round(mean(singledurations[, "duration"]), + digits = digits), + mean(singledurations[, "duration"]) + ) + + output[["min_duration"]] <- ifelse( + rounded == TRUE, + round(min(singledurations[, "duration"]), + digits = digits), + min(singledurations[, "duration"]) + ) + + output[["max_duration"]] <- ifelse( + rounded == TRUE, + round(max(singledurations[, "duration"]), + digits = digits), + max(singledurations[, "duration"]) + ) + + output[["single_durations"]] <- + singledurations[order(singledurations$duration), ] + + if (rounded == TRUE) { + output[["single_durations"]][["duration"]] <- + round(output[["single_durations"]][["duration"]], digits = digits) + } + + if (length(unique(messages) > 0)) { + output[["messages"]] <- unique(messages) + } + + output[["only_one_page"]] <- firststageproblemparticipants + + if (length(warningparticipants) > 0) { + output[["warnings"]] <- unique(warningparticipants) + + output[["messages"]] <- + c(output[["messages"]], + paste0("For some participants, no duration could be ", + "calculated. See list in $warnings. Did they ", + "make it to the app(s) or are there data ", + "there twice?")) + } + + # Directly to final return + return(output) + } + + # Calculate time for specified individuals + time_for_specific <- function() { + + # Get time + withCallingHandlers({ + duration <- duration_specific() # Info: Messages are set here + }, error = function(e) { + stop(e) + }, warning = function(w) { + warning(w) + invokeRestart("muffleWarning") + }) + + # Make output + if (rounded == TRUE) { + duration <- round(duration, digits = digits) + } + duration <- duration + if (!is.null(messages)) { + warning(unique(messages)) + } + return(duration) + } + + # Choose between time specific or time for more individuals #### + if (!is.null(pcode)) { + withCallingHandlers({ + return(time_for_specific()) + }, error = function(e) { + stop(e)}, warning = function(w) { + warning(w) + invokeRestart("muffleWarning") + } + ) + } else { # Time for all participants #### + singledurations <- data.frame() + warningparticipants <- c() + + # Make list of all participants for all groups #### + if (is.null(group_id)) { + listallparticipants <- c(unique(oTree$Time[[participant_code_name]])) + } else { + listallparticipants <- unique(oTree$Time[[participant_code_name]][ + oTree$Time$group_id == group_id]) + } + + # Calculate time for all participants #### + for (i in listallparticipants) { + tryCatch( + { + duration <- duration_all() + + if (length(duration) > 1) stop("One participant is there twice") + + session <- get_session(who = i) + + # Make data frame #### + if (!is.na(duration)) { + singledurations <- plyr::rbind.fill( + singledurations, + data.frame( + participant = i, + session = ifelse(!is.null(sinfo), + session, + NA), + duration = duration + ) + ) + + if (is.null(sinfo)) { + singledurations <- singledurations[, c("participant", "duration")] + } + } + }, error = function(e) { + warningparticipants <<- c(warningparticipants, i) + + }, warning = function(w) { + warning(paste("Warning: ", w)) + } + ) + if (indextoohigh == TRUE) stop(indextoohigh_message) + if (indextoolow == TRUE) stop(indextoolow_message) + } + + # Make output #### + return(output_all()) + } +} diff --git a/R/import_otree.R b/R/import_otree.R new file mode 100644 index 0000000..f13a649 --- /dev/null +++ b/R/import_otree.R @@ -0,0 +1,623 @@ +#' Import oTree data +#' @description +#' Import data files that were created by oTree. +#' All files containing the pattern YYYY-MM-DD at the end +#' of their file names are considered oTree files. +#' Bot outputs are saved by oTree without the date included. Hence, to +#' import bot data, you must either rename the original bot files +#' using the YYYY-MM-DD format or use the argument "onlybots = TRUE." +#' By using the second option, only data of bot files are imported. +#' +#' Caution! Data can be downloaded from within the +#' session and globally at the same time. If both files are downloaded, +#' this can lead to the all_apps_wide data being there twice! You can remove +#' duplicate data by using delete_duplicate(). +#' +#' Caution! When importing Excel files, this function does not check +#' for erroneous data structures +#' and will combine all data frames with the same file name patterns. +#' Before using the "CSV = FALSE" argument, clean up your data appropriately. +#' @keywords oTree +#' @param final_apps Character. +#' The name(s) of the app(s) at which the participants have to finish the +#' experiment. If the argument final_apps is left empty, you can still call +#' for deleting the participants who did not finish the experiment with +#' delete_dropouts(). +#' @param final_pages Character. +#' The name(s) of the page(s) at which the participants have to finish the +#' experiment. If the argument final_pages is left empty, you can still +#' call for deleting the participants who did not finish the experiment +#' with delete_dropouts(). +#' @param encoding Character. Encoding of the CSV files that are imported. +#' Default is "UTF-8". +#' @param path Character. The path to the files (default is the +#' working directory). +#' @param recursive Logical. TRUE if the files in the path's +#' subfolders should also be imported. +#' @param file_names Character. The name(s) of the file(s) to be imported. +#' If not specified, all files in the path and subfolders are imported. +#' @param csv Logical. +#' TRUE if only CSV files should be imported. +#' FALSE if only Excel files should be imported. +#' @param onlybots Logical. TRUE if only bot-created files should be imported. +#' @param del_empty Logical. TRUE if all empty cases should be deleted from the +#' all_apps_wide or normal app data frames (not Time or Chats). +#' @param info Logical. TRUE if a brief information on the data import should be +#' printed. +#' @returns +#' Returns a list of data frames (one data frame for each app and +#' all_apps_wide) and a list of information on this list of data frames +#' in $info. +#' +#' See detailed information on the imported files in $info$imported_files. +#' +#' If all_apps_wide is imported, see the number of imported cases +#' in $info$initial_n. In this number, empty rows are +#' already considered. So, if empty rows are deleted with del_empty=TRUE, +#' initial_n counts all rows that are not empty. +#' Cases that are deleted because the participants did not make it to the +#' last page and/or app are not subtracted from this number. +#' +#' Information: Empty rows are rows without the "participant._current_app_name" +#' variable set. Empty rows are deleted from all app data frames and +#' all_apps_wide when using del_empty=TRUE. Empty rows in the Chats and Time +#' data frames are not deleted. +#' +#' If old and new oTree versions are combined, the Time data frame contains +#' variables called "participant_code" and "participant__code" +#' (the difference is in the underscores). +#' Caution! If there is an unusual amount of NAs, +#' check if everything got imported correctly. +#' Sometimes, the CSV or Excel file may be corrupted, and all information is +#' only found in one column. +#' @examplesIf rlang::is_installed("withr") +#' # Set data folder first +#' withr::with_dir(system.file("extdata", package = "gmoTree"), { +#' +#' # Import all oTree files in this folder and its subfolders +#' oTree <- import_otree() +#' +#' # Show the structure of the import +#' str(oTree, max.level = 1) +#' +#' # Show the names of all imported files +#' oTree$info$imported_files +#' +#' # Delete empty cases and delete every case of a person +#' # who didn't end the experiment in the app "survey" +#' oTree <- import_otree( +#' del_empty = TRUE, +#' final_apps = "survey", +#' info = TRUE) +#' +#' # Show the structure of the import +#' str(oTree, max.level = 1) +#' +#' # Import bot files +#' import_otree( +#' path = "./bot_data", +#' onlybots = TRUE, +#' csv = TRUE, +#' info = TRUE) +#' +#' # Show the structure of the import +#' str(oTree, max.level = 1) +#' +#' # Import with file names (path separately) +#' oTree2 <- import_otree( +#' del_empty = TRUE, +#' path = "./exp_data", +#' file_names = c("all_apps_wide-2023-03-27.csv", +#' "ChatMessages-2023-03-27.csv", +#' "PageTimes-2023-03-27.csv"), +#' onlybots = FALSE, +#' csv = TRUE, +#' info = TRUE) +#' +#' # Show the structure of the import +#' str(oTree, max.level = 1) +#' +#' # Import with file names (without path separately) +#' oTree2 <- import_otree( +#' del_empty = TRUE, +#' file_names = c("exp_data/all_apps_wide-2023-03-27.csv", +#' "exp_data/ChatMessages-2023-03-27.csv", +#' "exp_data/PageTimes-2023-03-27.csv"), +#' onlybots = FALSE, +#' csv = TRUE, +#' info = TRUE) +#' +#' # Show the structure of the import +#' str(oTree, max.level = 1) +#' }) + +# Info: New oTree versions (at least 5.10.3) don't save +# their data with Excel files anymore. +# It does not matter whether you download files with +# the "Excel" or "CSV" version, +# you get CSV files in each case. It does not seem as if +# there are not any differences between the downloaded csv-files. + +#' @export +import_otree <- function( + path = ".", + file_names = NULL, + final_apps = NULL, + final_pages = NULL, + recursive = TRUE, + csv = TRUE, + onlybots = FALSE, + del_empty = TRUE, + info = FALSE, + encoding = "UTF-8" + ) { + + + # Make oTree list + oTree <- list() + + # Specify type of files + if (onlybots == TRUE) { + csv <- TRUE + } + + # Make messages + errorfiles <- data.frame(file = character(0), content = character(0)) + warningfiles <- data.frame(file = character(0), content = character(0)) + time_message <- c() + chat_message <- c() + other_messages <- c() + + # Define path + if (!is.null(path)) { + # Change Windows paths to paths that can be read by Ubuntu + path2 <- gsub("\\\\", "/", path) + } else { + stop("Path must not be NULL!") + } + + # If path in file names: + # Change Windows paths to paths that can be read by Ubuntu + if (!is.null(file_names)) { + file_names <- gsub("\\\\", "/", file_names) + } + + # Check if path(s) exist(s) + for (i in path2) { + if (!dir.exists(i)) { + stop(paste0("This path does not exist: ", i)) + } + } + + # oTree pattern handling + if (onlybots == TRUE) { + pattern_definer <- "" # For regex search later + } else { + if (csv == TRUE) { + # For regex search later + # The second part refers to Chat and Time and is always csv + pattern_definer <- + "[0-9]{4}-[0-9]{2}-[0-9]{2}\\.csv|[0-9]{4}-[0-9]{2}-[0-9]{2}\\)\\.csv" + } else { + pattern_definer <- + "[0-9]{4}-[0-9]{2}-[0-9]{2}\\.xlsx|[0-9]{4}-[0-9]{2}-[0-9]{2}\\)\\.csv" + } + } + + # List all file names if none are specified #### + if (is.null(file_names)) { + + # Get all file names + all_file_names <- list.files( + path = path2, + pattern = pattern_definer, + full.names = TRUE, + recursive = recursive + ) + } else if (!is.null(file_names)) { + # List all file names if they are specified #### + all_file_names <- paste0(path2, "/", file_names) + } + + # Stop if there are no files #### + if (length(all_file_names) == 0 || is.null(all_file_names)) { + stop(paste0("No files to import! ", + "Did you specify the CSV argument correctly? ", + "Is the directory correctly specified? ?\n", + "The directory is: ", path2 + )) + } + + # Make app-names to file names (= all file names without path and time) #### + app_filedf <- data.frame(app = all_file_names, + file = all_file_names) + + # Take path away + app_filedf$app <- gsub(".*/", "", app_filedf$app) + app_filedf$app <- gsub(".*\\\\", "", app_filedf$app) + + # Delete dates from file names to get app names + if (pattern_definer != "") { + app_filedf$app <- stringr::str_remove(app_filedf$app, + pattern_definer) + } + + # Special all apps wide definer + app_filedf$app <- stringr::str_remove(app_filedf$app, + "-[0-9]{4}-[0-9]{2}-[0-9]{2}") + app_filedf$app <- stringr::str_remove(app_filedf$app, + ".xlsx") + app_filedf$app <- stringr::str_remove(app_filedf$app, + ".csv") + app_filedf$app <- + stringr::str_remove(app_filedf$app, + "\\s*\\(accessed [0-9]{4}-[0-9]{2}-[0-9]{2}\\)") + + app_filedf$app <- stringr::str_remove(app_filedf$app, "_$") + + app_filedf$app <- stringr::str_remove(app_filedf$app, "-$") + + # Special handling of Time and Chats + app_filedf$app <- gsub("ChatMessages.*", "Chats", app_filedf$app) + app_filedf$app <- gsub("PageTimes.*", "Time", app_filedf$app) + app_filedf$app <- gsub("Chat messages.*", "Chats", app_filedf$app) + app_filedf$app <- gsub("TimeSpent.*", "Time", app_filedf$app) + + # Sort app-names + appnames <- unique(app_filedf$app) + appnames <- appnames[order(appnames)] + + ########################################################## + + # Import all data except time and chat #### + + # Import normal apps and all apps wide #### + app_list <- unique(app_filedf$app) + + for (App in app_list) { + + # Import files #### + if (App != "Chats" && + App != "Time") { + + # Get file names #### + allAppsFilesWP <- app_filedf$file[app_filedf$app == App] + + # Import files #### + if (csv == FALSE) { + + # Import all Excel files for the App #### + + # Caution: Error management does not work that well. + # If an excel file is empty or faulty, + # it is still added to the data frame. Reason: The read.xlsx + # function works that way. + rbind.fill adds NA to all empty cells. + + for (i in seq_along(allAppsFilesWP)) { + new <- NULL # Future file data frame + + tryCatch({ + withCallingHandlers({ + + # Read data + new <- openxlsx::read.xlsx(file.path(allAppsFilesWP[i]), + sheet = 1) + + # If data is there: Add data to data frame + info about it + + if (!is.null(new) & nrow(new) > 0) { + + oTree[[App]] <- plyr::rbind.fill(new, oTree[[App]]) + + oTree[["info"]][["imported_files"]] <- c( + toString(allAppsFilesWP[i]), + oTree[["info"]][["imported_files"]] + ) + } + }, warning = function(w) { + + # Append error message + warningfiles <<- rbind( + warningfiles, + data.frame(file = allAppsFilesWP[i], + content = as.character(w))) + + invokeRestart("muffleWarning") + + })}, error = function(e) { + # If the data frame is empty, there is no + # error shown! + + # Append error message + errorfiles <<- + rbind(errorfiles, + data.frame(file = allAppsFilesWP[i], + content = as.character(e))) + } + ) + } + # Info: That's so complicated, because tryCatch does not + # continue after warnings and withCallingHandlers throws errors + + } else if (csv == TRUE) { + + # Import all CSV files for the App #### + for (i in seq_along(allAppsFilesWP)) { + new <- NULL # Temporary file data frame + + tryCatch({ + withCallingHandlers( + { + # Read data + new <- utils::read.csv( + allAppsFilesWP[i], + encoding = encoding, + header = TRUE) + + # If data is there: Add data to data frame + info about it + + if (!is.null(new) && nrow(new) > 0) { + + oTree[[App]] <- plyr::rbind.fill(new, oTree[[App]]) + + oTree[["info"]][["imported_files"]] <- c( + toString(allAppsFilesWP[i]), + oTree[["info"]][["imported_files"]] + ) + } + }, warning = function(w) { + + # Append warning message + warningfiles <<- rbind(warningfiles, + data.frame(file = allAppsFilesWP[i], + content = as.character(w))) + invokeRestart("muffleWarning") + } + )}, error = function(e) { + + # Append error message + errorfiles <<- rbind(errorfiles, + data.frame(file = allAppsFilesWP[i], + content = as.character(e))) + }) + } + } + + # Delete empty #### + if (del_empty == TRUE) { + oTree[[App]] <- oTree[[App]][ + !(is.na(oTree[[App]]$participant._current_app_name) | + oTree[[App]]$participant._current_app_name == "" | + oTree[[App]]$participant._current_app_name == ""), ] + } + } + } + + # All apps wide handling #### + # Get warning message if AAW is saved room-specific and globally + if (("All apps - wide" %in% names(oTree) && + "all_apps_wide" %in% names(oTree)) || + (any(grepl("all_apps_wide-", oTree[["info"]][["imported_files"]])) && + any(grepl("all_apps_wide_", oTree[["info"]][["imported_files"]])) + )) { + + warning(paste0( + "You have stored all_apps_wide ", + "globally but also room-specific. ", + "This function will import both of them. ", + "(Globally, the files are saved as \"all_apps_wide_.\" ", + "Room-specific, the files are saved as \"All apps - wide-\" or ", + "\"all_apps_wide-.\") ", + "After importing the data, ", + "make sure nothing is there twice! ", + "(Advice: You may use delete_duplicate() to ", + "remove duplicate rows of all oTree data frames." + )) + } + + # Combine possible AAWs (will be NULL if none are there) + oTree[["all_apps_wide"]] <- plyr::rbind.fill( + oTree[["all_apps_wide"]], + oTree[["All apps - wide"]] + ) + oTree[["All apps - wide"]] <- NULL + + # Import time #### + + # List all time files + time_files <- app_filedf$file[app_filedf$app == "Time"] + + # Sort it + time_files <- sort(time_files) + + # Import time data + if (length(time_files) != 0) { + + for (i in seq_along(time_files)) { + new <- NULL # Future file data frame + + tryCatch({ + withCallingHandlers( + { + # Read data + new <- utils::read.csv(time_files[i], + sep = ",", + header = TRUE, + encoding = encoding) + + # If data is there: Add data to data frame + info about it + + if (!is.null(new) && nrow(new) > 0) { + oTree[["Time"]] <- plyr::rbind.fill(new, oTree[["Time"]]) + + oTree[["info"]][["imported_files"]] <- c( + toString(time_files[i]), + oTree[["info"]][["imported_files"]]) + } + }, warning = function(w) { + # Append warning message + warningfiles <<- rbind(warningfiles, + data.frame(file = time_files[i], + content = as.character(w))) + invokeRestart("muffleWarning") + }) + }, error = function(e) { + + # Append error message + errorfiles <<- rbind(errorfiles, + data.frame(file = time_files[i], + content = as.character(e))) + }) + } + } + + # Import chat data #### + + # When importing data from Excel, be aware that if a participant uses + # special characters, their data in one row might be split and also shown + # on the next line. This can cause the information on the next line to be + # overwritten by new information, which can lead to issues like missing + # time stamps for certain entries. + + chat_files <- app_filedf$file[app_filedf$app == "Chats"] + chat_files <- sort(chat_files) + + # Import/reading data: "Chats" + if (length(chat_files) != 0) { + + for (i in seq_along(chat_files)) { + new <- NULL # Future file data frame + + tryCatch({ + withCallingHandlers( + { + # Read data + new <- utils::read.csv(chat_files[i], + sep = ",", + header = TRUE, + encoding = encoding) + + # If data is there: Add data to data frame + info about it + if (!is.null(new) & nrow(new) > 0) { + oTree[["Chats"]] <- plyr::rbind.fill(new, oTree[["Chats"]]) + + + oTree[["info"]][["imported_files"]] <- c( + toString(chat_files[i]), + oTree[["info"]][["imported_files"]]) + } + + }, warning = function(w) { + warningfiles <<- rbind(warningfiles, + data.frame(file = chat_files[i], + content = as.character(w))) + invokeRestart("muffleWarning") + }) + + }, error = function(e) { + errorfiles <<- rbind(errorfiles, + data.frame(file = chat_files[i], + content = as.character(e))) + }) + # Info: That's so complicated, because tryCatch does not + # continue after warnings and withCallingHandlers throws errors + } + } + + # Initial N #### + if ("all_apps_wide" %in% names(oTree)) { + oTree$info$initial_n <- nrow(oTree$all_apps_wide) + + } else { + my_messages <- paste0("Import successful, but all_apps_wide is not there. ", + "This might affect other functions in this package.") + # e.g. make_ids + } + + # Delete dropouts #### + if (!(is.null(final_apps) && is.null(final_pages))) { + + # Run delete_dropouts with withCallingHandlers to catch the message + oTree <- withCallingHandlers({ + delete_dropouts(oTree, + final_apps = final_apps, + final_pages = final_pages, + info = TRUE)}, + message = function(c) { + other_messages <<- c$message + invokeRestart("muffleMessage") + } + ) + } + + # Messages #### + if (info == TRUE) { + + numapps <- length(oTree) + numapps <- ifelse("Time" %in% names(oTree), numapps - 1, numapps) + numapps <- ifelse("Chats" %in% names(oTree), numapps - 1, numapps) + numapps <- ifelse("info" %in% names(oTree), numapps - 1, numapps) + + my_messages <- c(paste0("Imported: ", + numapps, + " app(s) and/or all_apps_wide")) + + + if (!is.null(errorfiles) && !nrow(errorfiles) == 0) { + + # Make error messages + errorfiles$pasteresult <- paste0("File: ", + errorfiles$file, + ": ", + errorfiles$content) + + errormessages <- paste0("Errors when importing these files:\n", + paste(collapse = "\n", errorfiles$pasteresult)) + + # Throw an error if there is nothing else in the oTree list + if (length(oTree) == 0) { + stop(errormessages) + } + + # Combine with other messages + other_messages <- c(other_messages, errormessages) + } + + # First check if the file is not already in errorfiles + warningfiles <- warningfiles[!(warningfiles$file %in% errorfiles$file), ] + + if (!is.null(warningfiles) && !(nrow(warningfiles) == 0)) { + # Make warning message + warningfiles$pasteresult <- paste0("File: ", warningfiles$file, + ": ", warningfiles$content) + + # Combine with other messages + other_messages <- c( + paste0( + "Warnings when importing these files (and other warnings):\n", + paste(collapse = "\n", warningfiles$pasteresult), + other_messages)) + } + + if ("Time" %in% names(oTree)) { + time_message <- paste0("Imported: Time file(s)") + } else { + time_message <- "No Time files available" + } + + if ("Chats" %in% names(oTree)) { + chat_message <- paste0("Imported: Chat file(s)") + } else { + chat_message <- "No chat files available" + } + + my_messages <- paste0(my_messages, "\n", + time_message, "\n", + chat_message, "\n", + paste(other_messages, collapse = "\n")) + message(my_messages) + } + + # Return ##### + return(oTree) +} diff --git a/R/make_ids.R b/R/make_ids.R new file mode 100644 index 0000000..8427b57 --- /dev/null +++ b/R/make_ids.R @@ -0,0 +1,761 @@ +#' Make IDs +#' @description +#' Make session IDs and, optionally, group IDs and participant IDs +#' that span across all data frames created by +#' import_otree(). Information for these IDs is taken from all_apps_wide +#' but can be defined otherwise. +#' +#' Note: Older versions of oTree may already contain a +#' variable called session_id in their Time data frames. +#' This variable is overwritten by this function! +#' +#' Important: Combine duplicate data before running this function! +#' @keywords oTree +#' @param oTree A list of data frames that were created by import_otree(). +#' @param gmake Logical. TRUE if a variable called group_id should be made. +#' If from_var is not NULL, gmake is automatically set to TRUE. +#' @param pmake Logical. TRUE if a variable called participant_id +#' should be made. +#' @param from_app Character. Name of the data frame from which the session, +#' group, and participant information should be taken. +#' All normal app data frames and all_apps_wide are allowed. +#' @param from_var Character. Name of the variable from which the group +#' information should be taken. This argument is only relevant when +#' all_apps_wide is used as from_app and has group information that contradicts +#' each other. +#' @param sstart Integer. +#' The number that serves as a starting point for session IDs. +#' @param gstart Integer. +#' The number that serves as a starting point for group IDs. +#' @param pstart Integer. +#' The number that serves as a starting point for participant IDs. +#' @param emptyrows Character. "no" if the function should stop if there are +#' empty rows in from_app. "yes" if the function should continue to make IDs. +#' @param icw Logical. TRUE if the warning message should be +#' ignored that states that IDs cannot be made because of an oTree bug. +#' @returns ID variables are made in all_apps_wide, all app data frames, +#' the Time data frame, and the Chats data frame. +#' See list of the additional ID variables in $info$additional_variables. +#' @examples +#' # Use package-internal list of oTree data frames +#' oTree <- gmoTree::oTree +#' +#' # Make session IDs only +#' oTree2 <- make_ids(oTree) +#' +#' # Show new variables +#' oTree2$all_apps_wide$session_id +#' +#' # Make session IDs and group IDs # +#' # Not working with this data set because group ID is not the same in all apps +#' # oTree2 <- make_ids(oTree, gmake = TRUE) +#' +#' # Show new variables +#' # oTree2$all_apps_wide$session_id +#' # oTree2$all_apps_wide$group_id +#' +#' # Get IDs from variable "dictator.1.group.id_in_subsession" +#' # in the data frame "all_apps_wide" +#' oTree2 <- make_ids(oTree, +#' gmake = TRUE, +#' from_var = "dictator.1.group.id_in_subsession") +#' +#' # Show new variables +#' oTree2$all_apps_wide$session_id +#' oTree2$all_apps_wide$group_id +#' +#' # Get IDs from another app than all_apps_wide +#' oTree2 <- make_ids(oTree, gmake = TRUE, from_app = "dictator") +#' +#' # Show new variables +#' oTree2$all_apps_wide$session_id +#' oTree2$all_apps_wide$group_id + +#' @export +make_ids <- function(oTree, + gmake = FALSE, + pmake = TRUE, + from_app = "all_apps_wide", + from_var = NULL, + sstart = 1, + gstart = 1, + pstart = 1, + emptyrows = NULL, + icw = FALSE) { + + my_warnings <- c() + time_messed <- FALSE + chat_messed <- FALSE + messed_message <- c() + + # Before start: Error messages #### + + if (from_app %in% c("info", "Chats", "Time")) { + stop(paste0( + "You are not supposed to use \"Chats,\" or \"Time,\" or \"info\" as ", + "from_app! Choose another app!")) + } + + if (is.null(oTree[[from_app]])) { + stop(paste0("from_app \"", + from_app, + "\" not found. Please select another from_app.")) + } + + + if (!(is.data.frame(oTree[[from_app]]))) { + stop("Your from_app is not a data frame!") + } + + if (!(any(grepl("subsession.round_number", colnames(oTree[[from_app]]))))) { + stop("Your from_app is not a normal oTree all_apps_wide or apps data ", + "frame. Choose another from_app!") + } + + if (!is.null(from_var)) { + + if (from_app != "all_apps_wide") { + stop("Please only use from_app (all except all_apps_wide) ", + "or from_var!") + + } else if (from_app == "all_apps_wide") { + if (is.null(oTree[[from_app]][[from_var]])) { + stop(paste0("from_var \"", + from_var, + "\" not found. ", + "Please select another one.")) + } + } + + # gmake should be automatically true if from_var is set + gmake <- TRUE + } + + if (inherits(oTree[[from_app]], "data.frame") == FALSE) { + stop(paste0("from_app \"", from_app, "\" is not a data frame.")) + } + + if (inherits(oTree[[from_app]], "data.frame") == TRUE && + nrow(oTree[[from_app]]) == 0) { + stop("from_app \"", from_app, "\" data frame has no entries.") + } + + # Check mixed Time data + tryCatch({ + messy_time(oTree, combine = FALSE) + }, error = function(e) { + time_messed <<- TRUE + messed_message <<- paste0("Please run messy_time() with the argument ", + "combine=TRUE before running this function.") + }) + + # Check mixed Chat data + tryCatch({ + messy_chat(oTree, combine = FALSE) + }, error = function(e) { + chat_messed <<- TRUE + + if (time_messed == TRUE) { + + # Combine messy chat message with messy time message + messed_message <<- + paste0(messed_message, + " AND: Run messy_chat() with the argument ", + "combine=TRUE before running this function!") + } else { + + # Make messy chat message + messed_message <<- + paste0("Run messy_chat() with the argument ", + "combine=TRUE before running this function!") + } + }) + + # Stop if messy time and/or chat variables should not be merged + if (time_messed == TRUE || chat_messed == TRUE) { + stop(paste0("You combined data from old and new oTree versions. ", + messed_message)) + } + + # Check for NAs in the relevant variables + if (any(is.na(oTree[[from_app]]$participant.code))) { + stop(paste0("There are NAs in your participant.code variable in your ", + "from_app! Clean your data or assign ", + "participant.code values by hand ", + "before running this function!")) + } + + if (any(is.na(oTree$Chats$participant_code))) { + stop("There are NAs in your participant_code variable in ", + "the oTree$Chats data frame.") + } + + if (any(is.na(oTree$Chats$participant__code))) { + stop("There are NAs in your participant__code variable in ", + "the oTree$Chats data frame.") + } + + if (from_app == "all_apps_wide") { + + if (length(oTree[[from_app]]$participant.code) != + length(unique(oTree[[from_app]]$participant.code))) { + + stop(paste0( + from_app, + ": The length of participant codes is not equal the length of ", + "unique participant codes. Please check your data for ", + "duplicates or empty rows! ", + "(Advice: You may use delete_duplicate() to ", + "remove duplicate rows of all oTree data frames.")) + } + } else { + if (length(unique(oTree[[from_app]]$participant.code)) != + length(oTree[[from_app]]$participant.code) / + max(oTree[[from_app]]$subsession.round_number)) { + + stop(paste0( + from_app, + ": The length of participant codes is not equal the length of ", + "unique participant codes. Please check your data for ", + "duplicates or empty rows! ", + "(Advice: You may use delete_duplicate() to ", + "remove duplicate rows of all oTree data frames.")) + } + } + + # Caution. Participant-code in chat in oTree version 5 is faulty (all 1) #### + messymessage <- paste0( + "Caution. All participant_codes in at least one ", + "session of the chat are the same. ", + "This might be because the participant code in the chat is faulty ", + "because of an oTree bug; however, there could also be another ", + "problem with your data. Maybe really only one person ", + "within a session submitted text to the chat. ", + "In any way: Check your Chat data and calculate IDs by hand or ", + "run the function with icw = TRUE! ", + "(For example, if really only one person submitted text to the chat.)") + + for (code in c(unique(oTree$Chats$session_code), + unique(oTree$Chats$session__code), + unique(oTree$Chats$participant__session__code) + )) { + + if (length(unique(oTree$Chats$participant_code[ + oTree$Chats$session_code == code])) == 1) { + + if (icw == FALSE) { + stop(messymessage) + } + + } else if (length(unique( + oTree$Chats$participant__code[ + oTree$Chats$session__code == code])) == 1) { + + if (icw == FALSE) { + stop(messymessage) # Can this even happen? + } + + } else if (length(unique( + oTree$Chats$participant__code[ + oTree$Chats$participant__session__code == code])) == 1) { + + if (icw == FALSE) { + stop(messymessage) # Can this even happen? + } + } + } + + # Check if group numbers are the same in all variables + # if app and round is not specified + if (gmake == TRUE && + from_app == "all_apps_wide" && + is.null(from_var)) { + + checkdata <- oTree[[from_app]][, endsWith(names(oTree[[from_app]]), + "group.id_in_subsession")] + + if (ncol(checkdata) == 0) { + stop("No variable that ends with \"group.id_in_subsession\"") + } + + if (inherits(checkdata, "data.frame") == TRUE) { + if (!(all(checkdata == checkdata[, 1]))) { + # Not all the same + stop( + "group_id can not be calculated. ", + "You don't have the same group.id_in_subsession in every app. ", + "Therefore, there are several group IDs in all_apps_wide. ", + "You must either enter the exact variable that defines the ", + "group numbers in all apps wide (from_var) or the app from ", + "which the group numbers should be taken (from_app)." + ) + } + } + } + + # Record original from_app order #### + oTree[[from_app]]$initial_order <- seq_len(nrow(oTree[[from_app]])) + + # Sub functions #### + ids_fromvariable <- function(oTree) { + + # Get group IDs from a certain variable + + if (!is.null(oTree[[from_app]][[from_var]])) { + + oTree[[from_app]]$GroupSessionID <- paste( + as.character(oTree[[from_app]]$session_id), + as.character(oTree[[from_app]][[from_var]])) + + oTree[[from_app]] <- dplyr::arrange( + oTree[[from_app]], + oTree[[from_app]]$session_id, + oTree[[from_app]]$GroupSessionID) + + oTree[[from_app]]$group_id <- + data.table::rleidv(oTree[[from_app]]$GroupSessionID) + + oTree[[from_app]]$group_id <- + oTree[[from_app]]$group_id + (gstart - 1) + + + if (length(unique(oTree[[from_app]][[from_var]])) == 1) { + my_warnings <<- c(my_warnings, paste0( + "The group variable values are constant. ", + "Group IDs now correspond to session IDs.")) + } + + return(oTree) + } # Else statement is already checked for at the start of the function + } + + ids_notfromvariable <- function(oTree) { + + # 1) Assign group number in subsession + + # Check if there are more than one columns with a group_id in it + # Info: It was already tested before if those variables exist + all_group_ids <- oTree[[from_app]][, grep("group.id_in_subsession", + colnames(oTree[[from_app]]))] + + if (inherits(all_group_ids, "data.frame") == TRUE && + ncol(all_group_ids) > 0) { + + # Make a helping variable GroupSessionID + oTree <- group_session_id_df(oTree) + + } else { + # Make a helping variable GroupSessionID + oTree <- group_session_id_vector(oTree) + } + + # 2) Arrange group numbers, too (I took the first occurrence) + oTree[[from_app]] <- + dplyr::arrange(oTree[[from_app]], + oTree[[from_app]]$session_id, + oTree[[from_app]]$GroupSessionID) + + # 3) Assign session wide group number + oTree[[from_app]]$group_id <- + data.table::rleidv(oTree[[from_app]]$GroupSessionID) + (gstart - 1) + + return(oTree) + } + + group_session_id_df <- function(oTree) { + # Here several variables are called group.id_in_subsession. + # Take the first one. + + # Add session ID so there are no group IDs twice + oTree[[from_app]]$GroupSessionID <- + paste( + oTree[[from_app]]$session_id, + oTree[[from_app]][, grep("group.id_in_subsession", + colnames(oTree[[from_app]]))][, 1]) + + if (length( + unique(oTree[[from_app]][, + grep("group.id_in_subsession", + colnames(oTree[[from_app]]))][, 1])) == 1) { + + my_warnings <<- c(my_warnings, paste0( + "The group variable values (of the first group variable) ", + "are constant. ", + "Group IDs now correspond to session IDs.")) + } + return(oTree) + } + + group_session_id_vector <- function(oTree) { + # Here only one variable is called group.id_in_subsession + + # Add session ID so there are no group IDs twice + oTree[[from_app]]$GroupSessionID <- paste( + oTree[[from_app]]$session_id, + oTree[[from_app]][, + grep("group.id_in_subsession", + colnames(oTree[[from_app]]))]) + + if (length(unique(oTree[[from_app]][ + , grep("group.id_in_subsession", + colnames(oTree[[from_app]]))])) == 1) { + + my_warnings <<- c(my_warnings, paste0( + "The group variable values are constant. ", + "Group IDs now correspond to session IDs.")) + } + return(oTree) + } + + # Assign session, group, and participant IDs to a specific data frame + ids_in_all_normal_apps <- function(oTree, df_group_in_date, i) { + for (participant in unique(df_group_in_date$participant.code)) { + + # Session ID + oTree[[i]]$session_id[oTree[[i]]$participant.code == participant] <- + df_group_in_date$session_id[ + df_group_in_date$participant.code == participant][1] + + # Group ID + if (group_size_info == TRUE) { + oTree[[i]]$group_id[oTree[[i]]$participant.code == participant] <- + df_group_in_date$group_id[ + df_group_in_date$participant.code == participant][1] + } + + # Participant ID + if (pmake == TRUE) { + oTree[[i]]$participant_id[oTree[[i]]$participant.code == participant] <- + df_group_in_date$participant_id[ + df_group_in_date$participant.code == participant][1] + } + } + return(oTree) + } + + # Assign participant, group and session ID values to the Time/Chats data frame + # For variables with only one underscore + ids_in_new_time_apps <- function(oTree, df_group_in_date, i) { + for (participant in unique(df_group_in_date$participant.code)) { + + # Session ID + oTree[[i]]$session_id[oTree[[i]]$participant_code == participant] <- + df_group_in_date$session_id[ + df_group_in_date$participant.code == participant][1] + + # Group ID + if (group_size_info == TRUE) { + oTree[[i]]$group_id[oTree[[i]]$participant_code == participant] <- + df_group_in_date$group_id[ + df_group_in_date$participant.code == participant][1] + } + + # Participant ID + if (pmake == TRUE) { + oTree[[i]]$participant_id[oTree[[i]]$participant_code == participant] <- + df_group_in_date$participant_id[ + df_group_in_date$participant.code == participant][1] + } + } + return(oTree) + } + + # Assign participant, group and session ID values to the Time/Chats data frame + # For variables with two underscores + ids_in_old_time_apps <- function(oTree, df_group_in_date, i) { + for (participant in unique(df_group_in_date$participant.code)) { + + # Session ID + oTree[[i]]$session_id[oTree[[i]]$participant__code == participant] <- + df_group_in_date$session_id[ + df_group_in_date$participant.code == participant][1] + + # Group ID + if (group_size_info == TRUE) { + oTree[[i]]$group_id[oTree[[i]]$participant__code == participant] <- + df_group_in_date$group_id[ + df_group_in_date$participant.code == participant][1] + } + + # Participant ID + if (pmake == TRUE) { + oTree[[i]]$participant_id[ + oTree[[i]]$participant__code == participant] <- + df_group_in_date$participant_id[ + df_group_in_date$participant.code == participant][1] + } + } + return(oTree) + } + + emptyrows_dealing <- function() { + # Ask user whether they want to stop function + while (is.null(emptyrows) || + (emptyrows != "yes" && emptyrows != "no")) { + cat( + "Your from_app contains empty rows. This might lead to faulty ", + "IDs. It is strongly advised to import data ", + "using the del_empty = TRUE ", + "argument of import_oTree().", + "Do you still want to continue with the creation of IDs?\n", + "Enter \"no\" to stop the function.\n", + "If you want to continue, please enter \"yes\".\n", + "Input: \n") + + emptyrows <- readLines( + con = getOption("mypkg.connection"), + n = 1) + } + return(emptyrows) + } + + # First in all_apps_wide #### + + # Step 1: Make session number #### + + # It's a bit more complicated + # because sometimes sessions start at the same time. + + # Get the entrance of the first participant to the session + startedlist <- stats::aggregate( + x = oTree[[from_app]]$participant.time_started, + by = list(session.code = oTree[[from_app]]$session.code), + FUN = min + ) # Info: NAs are not in the list + + # Deal with empty rows + if (any("" %in% oTree[[from_app]]$participant._current_app_name)) { + + emptyrows <- emptyrows_dealing() + if (emptyrows == "no") { + stop(paste0( + "Your from_app contains empty rows. This might lead to faulty ", + "IDs. You chose to stop this function. You can either import data ", + "using the del_empty = TRUE or rerun this function with the argument ", + "emptyrows=\"yes\" (not advised).")) + } + } + + # Add the entrance of first participant in session as a variable + for (i in unique(oTree[[from_app]]$session.code)) { + + if (i %in% startedlist$session.code) { + + oTree[[from_app]]$participant.time_started_min[ + oTree[[from_app]]$session.code == i] <- startedlist[ + startedlist$session.code == i, ]$x + } else { + # This part is usually called if session.code is NA + # This does not happen with cleaned data + if (any(is.na(oTree[[from_app]]$session.code))) { + my_warnings <- + c(my_warnings, + (paste0("At least one of your session.codes in your from_app is ", + "NA. All session codes that are Na are ", + "handled as being the same ", + "session. This might also result in faulty group_ids!! ", + "If this is not your intention, please manually assign ", + "session codes to avoid this issue."))) + } + oTree[[from_app]]$participant.time_started_min[ + oTree[[from_app]]$session.code == i] <- NA + } + } + + # Sort data frame by session starting time + oTree[[from_app]] <- oTree[[from_app]][ + base::order(oTree[[from_app]]$participant.time_started_min, + decreasing = FALSE), ] + + # Make session_id + oTree[[from_app]]$session_id <- + data.table::rleid(oTree[[from_app]]$session.code) + (sstart - 1) + + # Delete variable again + oTree[[from_app]]$participant.time_started_min <- NULL + + # Step 2: Make group_id #### + + # Calculate + if (gmake == TRUE) { + + if (from_app == "all_apps_wide" && !is.null(from_var)) { + + group_size_info <- TRUE + + oTree <- ids_fromvariable(oTree) + + } else if (is.null(from_var)) { + + group_size_info <- TRUE + + oTree <- ids_notfromvariable(oTree) + + } + } else { + group_size_info <- FALSE + } + + # Step 3: Make participant ID #### + # Up to now the data frame should be arranged according to + # session_id and GroupSessionID, hence + if (pmake == TRUE) { + + if ("participant.code" %in% names(oTree[[from_app]])) { + + # Sort data frame + if ("group_id" %in% colnames(oTree[[from_app]])) { + oTree[[from_app]] <- oTree[[from_app]][order( + oTree[[from_app]]$session_id, + oTree[[from_app]]$group_id, + oTree[[from_app]]$participant.code), ] + } else { + oTree[[from_app]] <- oTree[[from_app]][order( + oTree[[from_app]]$session_id, + oTree[[from_app]]$participant.code), ] + } + + # Make participant_id + oTree[[from_app]]$participant_id <- + data.table::rleidv(oTree[[from_app]]$participant.code) + + (pstart - 1) + + } else { + stop("There is no participant.code in ", + from_app, + "!") # This should never happen! + } + } + + # Step 4: Make info lists #### + listincluded <- c("session_id", "session.code", "participant.code") + oTree[["info"]][["additional_variables"]] <- c("session_id") + + if (group_size_info == TRUE) { + + listincluded <- append(listincluded, "group_id") + + oTree[["info"]][["additional_variables"]] <- + append(oTree[["info"]][["additional_variables"]], + "group_id") + } + + if (pmake == TRUE) { + + listincluded <- append(listincluded, "participant_id") + + oTree[["info"]][["additional_variables"]] <- + append(oTree[["info"]][["additional_variables"]], + "participant_id") + } + + # Step 5: Make list of groups #### + df_group_in_date <- oTree[[from_app]][, listincluded] + df_group_in_date <- df_group_in_date[!duplicated(df_group_in_date), ] + + # Step 6: Apply info list of groups to all apps #### + for (i in seq_along(oTree)) { + + # Get the name of the app/Time/Chats data frame + name_of_app <- rlist::list.names(oTree[i]) + + # Assign values + if (name_of_app != "info") { + + if ("participant.code" %in% names(oTree[[i]])) { # For all normal DFs + + # Get a warning, if the participant is not in the from_app + participants_more <- unique(oTree[[i]]$participant.code[ + !(oTree[[i]]$participant.code %in% + oTree[[from_app]]$participant.code)]) + + if (length(participants_more) > 0) { + my_warnings <- c(my_warnings, + paste0("Data frame \"", + names(oTree)[[i]], + "\" has more participants than ", + from_app, ": ", + paste(participants_more, + collapse = ", "))) + } + + # Assign participant, group and session ID values to the data frame + oTree <- ids_in_all_normal_apps(oTree, df_group_in_date, i) + + } else if ("participant_code" %in% names(oTree[[i]])) { # For Chats/Time + + # Get a warning, if the participant is not in the from_app + participants_more <- unique(oTree[[i]]$participant_code[ + !(oTree[[i]]$participant_code %in% + oTree[[from_app]]$participant.code)]) + + if (length(participants_more) > 0) { + my_warnings <- c(my_warnings, + paste0("Data frame \"", + names(oTree)[[i]], + "\" has more participants than ", + from_app, ": ", + paste(participants_more, + collapse = ", "))) + } + + # Assign participant, group and session ID values to the data frame + oTree <- ids_in_new_time_apps(oTree, df_group_in_date, i) + } else if ("participant__code" %in% names(oTree[[i]])) { + + # Get a warning, if the participant is not in the from_app + participants_more <- oTree[[i]]$participant__code[ + !(oTree[[i]]$participant__code %in% + oTree[[from_app]]$participant.code)] + + + participants_more <- unique(participants_more) + + if (length(participants_more) > 0) { + my_warnings <- c(my_warnings, + paste0("Data frame \"", names(oTree)[[i]], + "\" has more participants than ", + from_app, ": ", + paste(participants_more, collapse = ", "))) + } + + # Assign participant, group and session ID values to the data frame + oTree <- ids_in_old_time_apps(oTree, df_group_in_date, i) + + } else { + my_warnings <- + c(my_warnings, + paste0("Participant code variable couldn't be found in \"", + name_of_app, "\"!")) + } + + # Reorder columns #### + j <- 0 + if (pmake == TRUE) { + j <- j + 1 + } + if (group_size_info == TRUE) { + j <- j + 1 + } + oTree[[i]] <- + oTree[[i]][ , c(c((ncol(oTree[[i]]) - j):ncol(oTree[[i]])), + c(1:(ncol(oTree[[i]]) - j - 1))) + ] # Again -1 because otherwise a number is there twice + + oTree[[i]]$GroupSessionID <- NULL + } + } + + # Restore initial order of from_app #### + oTree[[from_app]] <- + oTree[[from_app]][order(oTree[[from_app]]$initial_order), ] + + oTree[[from_app]]$initial_order <- NULL + + # Print warnings #### + if (length(my_warnings > 0)) { + warning(paste(my_warnings, collapse = "\n")) + } + + return(oTree) +} diff --git a/R/messy_chat.R b/R/messy_chat.R new file mode 100644 index 0000000..40adb8a --- /dev/null +++ b/R/messy_chat.R @@ -0,0 +1,148 @@ +#' Check if the Chats data frame is messy +#' @description +#' Check if the Chats data frame includes both +#' session-related variables and participant-related variables that +#' appear multiple times. This may occur when data from different +#' oTree versions, which use different variable names, are combined. +#' +#' If desired, the function can merge these variables, +#' storing the data using the newer oTree version's variable names +#' and removing the outdated variables. +#' +#' @keywords oTree +#' @param oTree A list of data frames that were created by import_otree(). +#' @param combine Logical. TRUE if all variables referring to +#' the session code should be merged and/or all variables referring +#' to participant code should be merged in case data of several versions +#' of oTree are used. +#' @param session Logical. TRUE if all variables referring to the session code +#' should be checked and merged. Merging only works if combine = TRUE. +#' @param participant Logical. TRUE if all variables referring to the +#' participant code should be checked and merged. Merging only works if +#' combine = TRUE. +#' @param info Logical. TRUE if a brief information on the process should +#' be printed. +#' @returns +#' This function returns an oTree list of data frames that is +#' an exact copy of the original oTree list of data frames but - if the user +#' wishes to do so - combines the participant code and session code +#' variables in the Chats data frame if several variables are referring to +#' those because of the +#' combination of different oTree versions. The final variables are called +#' participant_code and session_code. +#' +#' If combine = FALSE, the function only checks for the existence of several +#' variables referring to the participant code and session code and throws an +#' error if yes. +#' @examplesIf rlang::is_installed("withr") +#' # Set data folder first +#' withr::with_dir(system.file("extdata", package = "gmoTree"), { +#' +#' # Import all oTree files in this folder and its subfolders +#' oTree <- import_otree() +#' }) +#' +#' # Show all Chats column names +#' print(colnames(oTree$Chats)) +#' +#' # Run function +#' oTree <- messy_chat(oTree, combine = TRUE) +#' +#' # Show all Chats column names again +#' print(colnames(oTree$Chats)) + + +#' @export +messy_chat <- function(oTree, + combine = FALSE, + session = TRUE, + participant = TRUE, + info = FALSE) { + + stop_messages <- c() + warning_messages <- c() + + # Background calculations plus error and warning messages + if (session == TRUE) { + length_chat_vars <- sum( + c("session_code", + "participant__session__code") %in% colnames(oTree$Chats)) + + if (length_chat_vars > 1 && combine == FALSE) { + stop_messages <- + c(stop_messages, + paste0( + "More than one variable referred to the session code ", + "in your Chats data frame. This could be because ", + "you mixed data of different ", + "versions of oTree in your data frame. Please combine ", + "them into one variable called either \"session_code,\" or ", + "\"participant__session__code\". ", + "You can do this by using the combine-argument in this ", + "function.")) + + } else if (length_chat_vars > 1 && combine == TRUE) { + oTree$Chats$session_code[is.na(oTree$Chats$session_code)] <- + oTree$Chats$participant__session__code[is.na(oTree$Chats$session_code)] + + oTree$Chats$participant__session__code <- NULL + + warning_messages <- + c(warning_messages, + paste0("More than one variable referred to ", + "the session code in ", + "your Chats data frame. You asked for combining them with ", + "the argument combine = TRUE. ", + "Therefore, variable \"participant__session__code\" was ", + "integrated into variable ", + "\"session_code.\"", + " The variable \"participant__session__code\" was ", + "deleted afterward.")) + } + } + + if (participant == TRUE) { + length_participant_vars <- sum( + c("participant_code", + "participant__code") %in% colnames(oTree$Chats)) + + if (length_participant_vars > 1 && combine == FALSE) { + stop_messages <- + c(stop_messages, + paste0("More than one variable referred to ", + "the participant code ", + "in your Chats data frame. This could be because you ", + "mixed data of different ", + "versions of oTree in your data frame. ", + "Please combine them into one ", + "variable called either \"participant_code,\" or ", + "\"participant__code\". You can do this by using the ", + "combine-argument in this ", + "function.")) + } else if (length_participant_vars > 1 && combine == TRUE) { + oTree$Chats$participant_code[is.na(oTree$Chats$participant_code)] <- + oTree$Chats$participant__code[is.na(oTree$Chats$participant_code)] + oTree$Chats$participant__code <- NULL + warning_messages <- + c(warning_messages, + paste0("More than one variable referred to ", + "the session code in ", + "your Chats data frame. You asked for combining them ", + "with the argument combine = TRUE. ", + "Therefore, variable \"participant__code\" was integrated ", + "into variable \"participant_code\"", + " The variable \"participant__code\" was deleted afterward.")) + } + } + + if (!is.null(stop_messages)) { + stop(paste(stop_messages, collapse = "\n")) + } + + if (info == TRUE && !is.null(warning_messages)) { + # This is printed as a warning because other functions catch the message + warning(paste(warning_messages, collapse = "\n")) + } + + return(oTree) +} diff --git a/R/messy_time.R b/R/messy_time.R new file mode 100644 index 0000000..e07a972 --- /dev/null +++ b/R/messy_time.R @@ -0,0 +1,173 @@ +#' Check if the Time data frame is messy +#' @description +#' Check if the Time data frame includes both participant-related variables +#' and time stamp variables that appear multiple times. This may occur when +#' data from different oTree versions, which use different variable names, +#' are combined. +#' +#' If desired, the function can merge these variables, +#' storing the data using the newer oTree version's variable names +#' and removing the outdated variables. +#' +#' @keywords oTree +#' @param oTree A list of data frames that were created by import_otree(). +#' @param combine Logical. TRUE if all variables referring to epoch time should +#' be merged and/or all variables referring to participant code should be merged +#' in case data of several versions of oTree are used. +#' @param epoch_time Logical. TRUE if all variables referring to the time stamp +#' should be checked and merged. Only works if combine = TRUE. +#' @param participant Logical. TRUE if all variables referring to the +#' participant code should be checked and merged. Only works if combine = TRUE. +#' @param info Logical. TRUE if a brief information on the process should +#' be printed. +#' @returns +#' This function returns an oTree list of data frames that is +#' an exact copy of the original oTree list of data frames but - if the user +#' wishes to do so - combines the +#' time tamps and participant codes in the Time data frame if several variables +#' are referring to those because of the +#' combination of different oTree versions. The final variables are called +#' epoch_time_completed and participant_code. +#' +#' If combine = FALSE, the function only checks for the existence of several +#' variables referring to the time stamp or the participant code and throws an +#' error if yes. +#' @examplesIf rlang::is_installed("withr") +#' # Set data folder first +#' withr::with_dir(system.file("extdata", package = "gmoTree"), { +#' +#' # Import all oTree files in this folder and its subfolders +#' oTree <- import_otree() +#' }) +#' +#' # Show all Time column names +#' print(colnames(oTree$Time)) +#' +#' # Run function +#' oTree <- messy_time(oTree, combine = TRUE) +#' +#' # Show all Time column names again +#' print(colnames(oTree$Time)) + +#' @export +messy_time <- function(oTree, + combine = FALSE, + epoch_time = TRUE, + participant = TRUE, + info = FALSE) { + + # Error messages + stop_messages <- c() + warning_messages <- c() + + participant_stop <- FALSE + participant_stopmessage <- + paste0("More than one variable referred to the participant ", + "code in your Time data frame. ", + "This could be because you mixed data of different ", + "versions of oTree in your data frame. ", + "Please combine them into one ", + "variable called either \"participant_code,\" or ", + "\"participant__code.\" ", + "You can do this by using the combine-argument of this ", + "function.") + + time_stop <- FALSE + time_stopmessage <- + paste0("More than one variable referred to the time stamp ", + "in your Time data frame. This could be because you ", + "mixed data of different versions of oTree in your data frame. ", + "Please combine them into one variable called either ", + "\"epoch time,\" \"epoch_time_completed,\" or ", + "\"time stamp.\" You can do this by using the ", + "combine-argument of this function.") + + + # Set epoch times first with error messages #### + if (epoch_time == TRUE) { + time_names <- c("epoch_time", "epoch_time_completed", "time_stamp") + time_names_in_otree <- + time_names[time_names %in% colnames(oTree$Time)] + length_epoch_times <- length(time_names_in_otree) + other_time_names <- time_names_in_otree[ + time_names_in_otree != "epoch_time_completed"] + + if (length_epoch_times > 1) { + if (combine == FALSE) { + time_stop <- TRUE + stop_messages <- c(stop_messages, time_stopmessage) + + } else if (combine == TRUE) { + + # Merge epoch time codes + if ("epoch_time" %in% colnames(oTree$Time)) { + # Merge variables + oTree$Time$epoch_time_completed[ + is.na(oTree$Time$epoch_time_completed)] <- + oTree$Time$epoch_time[is.na(oTree$Time$epoch_time_completed)] + + # Delete old variable + oTree$Time$epoch_time <- NULL + } + + if ("time_stamp" %in% colnames(oTree$Time)) { + # Merge variables + oTree$Time$epoch_time_completed[ + is.na(oTree$Time$epoch_time_completed)] <- + oTree$Time$time_stamp[is.na(oTree$Time$epoch_time_completed)] + + # Delete old variable + oTree$Time$time_stamp <- NULL + } + + warning_messages <- c(warning_messages, paste0( + "More than one variable referred to the time ", + "stamp. You asked for combining them with the ", + "argument combine = TRUE. ", + "Variable(s) \"", + paste(other_time_names, collapse = ",\" and \""), + "\" was/were integrated to variable ", + "\"epoch_time_completed\" and deleted afterward.")) + } + } + } + + # Set participant code variable first with error messages #### + if (participant == TRUE) { + length_part_codes <- sum( + c("participant_code", + "participant__code") %in% colnames(oTree$Time)) + + if (length_part_codes > 1) { + if (combine == FALSE) { + participant_stop <- TRUE + stop_messages <- c(stop_messages, participant_stopmessage) + } else if (combine == TRUE) { + # Combine participant codes + oTree$Time$participant_code[is.na(oTree$Time$participant_code)] <- + oTree$Time$participant__code[is.na(oTree$Time$participant_code)] + oTree$Time$participant__code <- NULL + warning_messages <- c(warning_messages, paste0( + "More than one variable referred to the participant code. ", + "You asked for combining them with the ", + "argument combine = TRUE. ", + "Variable \"participant__code\" was integrated into ", + "variable \"participant_code\" ", + "The variable \"participant__code\" was deleted afterward.")) + } + } + } + + # Return all error messages and warning messages #### + if (participant_stop == TRUE || time_stop == TRUE) { + stop(paste(stop_messages, collapse = "\n")) + } + + if (info == TRUE && !is.null(warning_messages)) { + # This is printed as a warning for other functions to catch the message + warning(paste(warning_messages, collapse = "\n")) + } + + # Return #### + return(oTree) +} diff --git a/R/oTree.R b/R/oTree.R new file mode 100644 index 0000000..5993e63 --- /dev/null +++ b/R/oTree.R @@ -0,0 +1,10 @@ +#' Sample experiment data +#' +#' @docType data +#' @format A list of data frames created by import_otree(). + +#' @source The data set was created by using modified versions of the official +#' oTree sample experiments that can be downloaded when installing oTree. +#' In detail, the following apps were used: "dictator," "chatapp," "survey." +#' +"oTree" diff --git a/R/pagesec.R b/R/pagesec.R new file mode 100644 index 0000000..6f24dd7 --- /dev/null +++ b/R/pagesec.R @@ -0,0 +1,133 @@ +#' Calculate the seconds spent on each page +#' @description +#' Create a new variable in the Time data frame that contains the time +#' spent on each page. +#' @keywords oTree +#' @param oTree A list of data frames that were created by import_otree(). +#' @param minutes Logical. TRUE if the output should be +#' minutes instead of seconds. +#' @param rounded Logical. TRUE if the output should be rounded. +#' @param digits Integer. The number of digits to which the +#' output should be rounded. +#' This parameter has no effect unless rounded = TRUE. +#' @param combine Logical. TRUE if all variables referring to epoch time should +#' be merged, and all variables referring to participant code should be +#' merged in case data of several versions of oTree are used. +#' @returns This function returns a duplicate of the original oTree list of +#' data frames that also contains a column in the Time data frame named +#' seconds_on_page2 or minutes_on_page. +#' @examples +#' # Use package-internal list of oTree data frames +#' oTree <- gmoTree::oTree +#' +#' # Create two new columns: seconds_on_page2 and minutes_on_page +#' oTree <- pagesec(oTree, rounded = TRUE, minutes = TRUE) +#' +#' # Show the Time data frame +#' head(oTree$Time, n = 30) + + +#' @export +pagesec <- function( + oTree, + rounded = TRUE, + digits = 2, + minutes = FALSE, + combine = FALSE) { + + # Check if time data frame is there #### + if (is.null(oTree$Time)) { + stop("No time data frame found!") + } + + # Check if there are too many epoch times and participant code variables + withCallingHandlers({ + oTree <- messy_time(oTree, combine, info = TRUE) + }, error = function(e) { + stop(e) + }, warning = function(w) { + warning(w) + invokeRestart("muffleWarning") + }) + + # Set time variable + if ("epoch_time" %in% colnames(oTree$Time)) { + timestamp_var_name <- "epoch_time" + } else if ("epoch_time_completed" %in% colnames(oTree$Time)) { + timestamp_var_name <- "epoch_time_completed" + } else if ("time_stamp" %in% colnames(oTree$Time)) { + timestamp_var_name <- "time_stamp" + } else { + stop("There is no variable referring to the epoch time tamp in your Time ", + "data frame. This should be a variable called either ", + "\"epoch time,\" \"epoch_time_completed,\" or \"time stamp.\"") + } + + # Set participant code variable + if ("participant_code" %in% colnames(oTree$Time)) { + participant_code_name <- "participant_code" + } else if ("participant__code" %in% colnames(oTree$Time)) { + participant_code_name <- "participant__code" + } else { + stop("There is no variable referring to the participant ", + "code in your Time data frame. ", + "This should be a variable called either \"participant_code,\" or", + "\"participant__code.\"") + } + + # Make list of Participants #### + list_of_participants <- + unique(stats::na.omit(oTree$Time[[participant_code_name]])) + + + # Make new variable #### + for (participant in list_of_participants) { + + # Make list of indices #### + allindices <- + unique(stats::na.omit(oTree$Time$page_index[ + oTree$Time[[participant_code_name]] == participant])) + + # Calculate #### + for (index in allindices) { + + versionminindex <- ifelse(min(allindices) == 0, 0, 1) + + # If the page index exists and is bigger than 0 or 1 (depending on whether + # there is a 0 index) + if (!is.na(index) && index > versionminindex) { + + # Time = index - next lower index + oTree$Time$seconds_on_page2[ + oTree$Time$page_index == index & + !is.na(oTree$Time[[participant_code_name]]) & + oTree$Time[[participant_code_name]] == participant] <- + + oTree$Time[[timestamp_var_name]][ + oTree$Time$page_index == index & + !is.na(oTree$Time[[participant_code_name]]) & + oTree$Time[[participant_code_name]] == participant] - + + oTree$Time[[timestamp_var_name]][ + oTree$Time$page_index == max(allindices[allindices < index]) & + !is.na(oTree$Time[[participant_code_name]]) & + oTree$Time[[participant_code_name]] == participant] + } + } + } + + # Translate to minutes + if (minutes == TRUE) { + + oTree$Time$minutes_on_page <- oTree$Time$seconds_on_page2 / 60 + + if (rounded == TRUE) { + oTree$Time$minutes_on_page <- round(oTree$Time$minutes_on_page, + digits = digits) + } + oTree$Time$seconds_on_page2 <- NULL + } + + # Return #### + return(oTree) +} diff --git a/R/show_constant.R b/R/show_constant.R new file mode 100644 index 0000000..d8fac32 --- /dev/null +++ b/R/show_constant.R @@ -0,0 +1,89 @@ +#' Show constant columns +#' @description +#' Show all columns with no variation in their values for each data frame +#' in the oTree list of data frames (except the ones in the info list). +#' This function is helpful before running an experiment to check if there +#' are unnecessary variables. +#' You can check for columns that have any unchanging possible value +#' or for columns containing only a specific value. +#' @keywords oTree +#' @param oTree A list of data frames that were created by import_otree(). +#' @param value The value that is controlled to be the same within a column. +#' The default is NA. If the value is set to "any," the function checks for +#' columns where any possible values are identical. +#' @returns This function returns a list of vectors, one for each app, +#' all_apps_wide, the Time and/or the Chats data frame. +#' Each vector contains the names of all variables with constant values. +#' If there are no variables with constant values, the vector is empty. +#' @examples +#' # Use package-internal list of oTree data frames +#' oTree <- gmoTree::oTree +#' +#' # Show all columns that contain only NAs +#' show_constant(oTree = oTree) +#' show_constant(oTree = oTree, value = NA) +#' +#' # Show all columns that contain only -99 +#' show_constant(oTree = oTree, value = -99) + + +#' @export +show_constant <- function(oTree, + value = "any") { + + # Error messages #### + if (length(value) > 1) { + stop("Please only enter only one value!") + } + + if (is.null(value)) { + stop("Please enter a valid value!") + } + + # Make output list + output <- list() + + # Check for specific values #### + if (is.na(value) || + value != "any") { + + # Go through all oTree elements + for (i in seq_along(oTree)) { + + # Only use the data frames (i.e. Apps and Time and Chats) + if (inherits(oTree[[i]], "data.frame") == TRUE) { + + # Get name of the app/Time/Chats + df_name <- rlist::list.names(oTree[i]) + + # Make data frame output (call function constant_col()) + output[[df_name]] <- constant_col( + df = oTree[[i]], + value = value + ) + } + } + + } else { + # Check for any constant columns background function #### + get_constant_cols <- function(df) { + constant_cols <- sapply(df, function(col) length(unique(col)) == 1) + names(df)[constant_cols] + } + + # Check all apps for empty columns #### + for (i in seq_along(oTree)) { + if (inherits(oTree[[i]], "data.frame") == TRUE) { + + # Get name of the app/Time/Chats + df_name <- rlist::list.names(oTree[i]) + + # Make data frame output (call function get_constant_cols()) + output[[df_name]] <- get_constant_cols(oTree[[i]]) + } + } + } + + # Return #### + return(output) +} diff --git a/R/show_dropouts.R b/R/show_dropouts.R new file mode 100644 index 0000000..df5b3d2 --- /dev/null +++ b/R/show_dropouts.R @@ -0,0 +1,234 @@ +#' Show participants who did not finish the experiment +#' @description +#' Show information on the people who did not finish the experiment at (a) +#' certain page(s) and/or app(s). +#' @keywords oTree +#' @param oTree A list of data frames that were created by import_otree(). +#' @param final_apps Character. +#' The name(s) of the app(s) at which the participants have to finish the +#' experiment. +#' @param final_pages Character. +#' The name(s) of the page(s) at which the participants have to finish the +#' experiment. +#' @param saved_vars The name(s) of variable(s) that need(s) to be +#' shown in the list of information on dropout cases. +#' @returns +#' This function returns a list of information on participants who did not +#' finish the experiment. +#' +#' In this list, you can find the following information: +#' +#' $full = A data frame that contains information +#' on all participants who did not finish the study; +#' it shows their participant codes, the names of the apps in which they +#' left the experiment, +#' the names of the pages in which they left the experiment, +#' the names of the app data frames in which this information was found, and +#' the dropout reason ("ENC," experiment not completed, combined +#' with the name of the data frame in which the dropout was observed). +#' Because participants usually appear in multiple app data frames, +#' the $full data frame may contain several entries for +#' each person. +#' +#' $unique = A data frame that contains similar information as the $full data +#' frame but with only one row per participant and no information on the data +#' frame in which the dropout was observed. +#' +#' $all_end = A table that provides information on the app and page combinations +#' where participants ended the experiment. This table also includes +#' information on participants who did not drop out of the experiment. +#' The $all_end table is only shown if an all_apps_wide data frame exists. +#' +#' $codes = A vector containing the participant codes of +#' all participants who did not finish the experiment. +#' +#' $count = The number of all participants who did not finish the experiment. +#' +#' It is important to note that if only the argument final_pages is set, +#' this function does not distinguish between page names that reoccur in +#' different apps. +#' +#' If the columns end_app and end_page in the output are empty, +#' these variables were not saved by oTree for the specific participants. +#' This could be because empty rows were not deleted. This can be done +#' by using the argument "del_empty = TRUE" when using import_otree(). +#' @examples +#' # Use package-internal list of oTree data frames +#' oTree <- gmoTree::oTree +#' +#' # Show everyone who did not finish with the app "survey" +#' show_dropouts(oTree, final_apps = "survey") +#' +#' # Show everyone who did not finish with the page "Demographics" +#' show_dropouts(oTree, final_pages = "Demographics") +#' +#' # Show everyone who finished with the following apps: "survey," "dictator" +#' final_apps <- unique(oTree$all_apps_wide$participant._current_app_name) +#' final_apps <- final_apps[final_apps != "survey"] +#' final_apps <- final_apps[final_apps != "dictator"] +#' show_dropouts(oTree, final_apps = final_apps) + +#' @export +show_dropouts <- function(oTree, + final_apps = NULL, + final_pages = NULL, + saved_vars = NULL) { + + keep_these_participants <- c() # Is just here for the inconsistency test + delete_these_participants <- c() # Not deleted here. Inconsistency check! + dropout_data <- data.frame() + output <- list() + my_warnings <- list() + + # Elements in oTree that are not apps #### + nonappelements <- c("Chats", "Time", "info", "deleted_cases") + + # Error checks #### + # Making sure the arguments are not empty + if (is.null(final_apps) && is.null(final_pages)) { + stop("Please specify final_apps or final_pages or both!") + } + + # Check if saved_vars is in all_apps_wide #### + if (!is.null(saved_vars)) { + if ("all_apps_wide" %in% names(oTree)) { + if (!(all(saved_vars %in% colnames(oTree$all_apps_wide)))) { + stop("saved_vars not in all_apps_wide.") + } # Else: everything is okay + + } else { + saved_vars <- NULL + my_warnings <- + paste0("Caution! saved_vars are taken from \"all_apps_wide\". ", + "Since \"all_apps_wide\" is not in your oTree, this argument ", + "is ignored.") + } + } + + # Create list of participants who did not finish the experiment #### + for (i in seq_along(oTree)) { + + keep_these_participants <- unique(keep_these_participants) + delete_these_participants <- unique(delete_these_participants) + + # Every app except ... + if (!(rlist::list.names(oTree[i]) %in% nonappelements)) { + + # Make if-statements + if (!is.null(final_apps)) { + appif <- oTree[[i]]$participant._current_app_name %in% final_apps + } else { + appif <- TRUE + } + + if (!is.null(final_pages)) { + pageif <- oTree[[i]]$participant._current_page_name %in% final_pages + } else { + pageif <- TRUE + } + + # Make list of people whose data is to be kept or "deleted" + keep_these_participants <- + c(oTree[[i]]$participant.code[appif & pageif], + keep_these_participants) + + delete_these_participants <- + c(oTree[[i]]$participant.code[!(appif) | !(pageif)], + delete_these_participants) + + # Make data frame of people who did not finish the experiment + dropout_app_data <- data.frame( + participant.code = oTree[[i]]$participant.code[!appif | !pageif], + session.code = oTree[[i]]$session.code[!appif | !pageif], + end_app = oTree[[i]]$participant._current_app_name[!appif | !pageif], + end_page = oTree[[i]]$participant._current_page_name[!appif | !pageif]) + + # Add reason + if (nrow(dropout_app_data) >= 1) { + for (j in seq_len(nrow(dropout_app_data))) { + dropout_app_data$reason[j] <- paste0( + "Experiment not completed. Noticed at: ", + rlist::list.names(oTree[i])) + } + dropout_data <- plyr::rbind.fill(dropout_data, dropout_app_data) + } + } + } + + delete_these_participants <- unique(delete_these_participants) + + # Test if no one in "keep" is in "delete" #### + newlist <- c() + for (element in keep_these_participants) { + if (element %in% delete_these_participants) { + newlist <- append(element, newlist) + } + } + + if (length(newlist) > 0) { + my_warnings <- c(my_warnings, paste0( + "At least one participant in the dropout list has inconsistent end ", + "pages, inconsistent end apps, or both.")) + } + + # Make output data frames of people who did not finish the experiment #### + if (nrow(dropout_data) >= 1) { + dropout_data <- unique(dropout_data) + + # Save variables for people who did not finish the experiment + if ("all_apps_wide" %in% names(oTree)) { + saved_vars_frame <- oTree$all_apps_wide[ + !appif | !pageif, + c("participant.code", saved_vars)] + + saved_vars_frame <- as.data.frame(saved_vars_frame) + colnames(saved_vars_frame) <- c("participant.code", saved_vars) + + # Add saved variables + if (ncol(saved_vars_frame) > 0) { + dropout_data <- merge( + x = dropout_data, + y = saved_vars_frame, + by.x = "participant.code", + by.y = "participant.code", + all.x = TRUE, + all.y = TRUE) + } + } + + output[["full"]] <- dropout_data + + # Unique + dropout_data2 <- unique(dropout_data[c(c("participant.code", + "session.code", + "end_app", + "end_page"), + saved_vars)]) + + output[["unique"]] <- cbind(dropout_data2, + reason = "Experiment not completed") + } + + # Make table of all ending apps and pages #### + if ("all_apps_wide" %in% names(oTree)) { + output[["all_end"]] <- table( + oTree$all_apps_wide$participant._current_app_name, + oTree$all_apps_wide$participant._current_page_name) + } else { + my_warnings <- c(my_warnings, + ("No \"all_apps_wide\" to make the table of end pages.")) + } + + # Number of dropouts + output[["codes"]] <- output[["unique"]]$participant.code + + output[["count"]] <- nrow(output[["unique"]]) + + # Warnings + if (length(my_warnings) > 0) { + warning(paste(my_warnings, collapse = "\n\n")) + } + + # Return #### + return(output) +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..e24230c --- /dev/null +++ b/README.md @@ -0,0 +1,126 @@ +# gmoTree – Get and Modify oTree Data + + [![R-CMD-check](https://github.com/ZauchnerP/gmoTree/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/ZauchnerP/gmoTree/actions/workflows/R-CMD-check.yaml) + + +gmoTree is an R package developed for importing, merging, and efficiently managing data obtained from running oTree (https://www.otree.org/) experiments. It's particularly valuable when dealing with complex experimental designs that span multiple sessions and generate a large number of files that need to be integrated. + +gmoTree is not an official package of the oTree team, but it was created to complement the open-source platform. + +## About this version +This is the beta version of the gmoTree package! + +This package has been thoroughly tested, but since it is still in beta, +it's recommended to double-check the results when importing data. For example: +Verify if the number of cases matches the numbers reported by the lab +and ensure that the time results are reasonable. Please let me know if you +encounter any errors or have suggestions for improvement. + +The final package might differ from this package, so please +keep track of the changes. + +# Installation + +To install this package, use the following command: + +`devtools::install_github("ZauchnerP/gmoTree")` + +# List of all functions +See the page Introduction to gmoTree for a +more detailed overview of the functions. Or see the website of gmoTree for more information on the package in general. + +## Importing data + +### import_otree() + +Imports your oTree data and combines them in a list of data frames. + +## Cleaning up data + +### messy_chat() + +Checks for a messy Chats data frame and combines variables that refer to +the same concept. + +### messy_chat() + +Checks for a messy Time data frame and combines variables that refer to +the same concept. + +### delete_duplicate() + +Deletes duplicate rows from all data frames in +the oTree list. + +## Dealing with dropouts and deleting cases + +### show_dropouts() + +Shows participant codes of people who did not finish at (a) certain +app(s) or page(s). + +### delete_dropouts() + +Deletes the data of participants who did not finish at (a) certain app(s) or +page(s). This function deletes the participants' data from all data frames in +the oTree list. Caution: It does not delete the cases from the original +CSV and Excel files! + +### delete_cases() + +Deletes the data of specified participants from all data frames in the +oTree list. Caution: This function does not delete the data from the original +CSV and Excel files! + +### delete_sessions() +Deletes the data of specified sessions from all data frames in the oTree list. +Caution: This function does not delete the data from the original CSV and Excel +files! + +## Deleting sensitive information + +### delete_plabels() + +Deletes the variable `participant.label` from every app because it might +contain identifiable information on the participants, such as their +MTurk ID. Caution: This function does not delete the variable from the +original CSV and Excel files! + +## Making IDs + +### make_ids() + +Makes participant, group, and session IDs that are the same across all +apps. + +## Calculating the time + +### apptime() + +Calculates the time spent on a specific app. + +### extime() + +Calculates the time spent on the experiment. + +### pagesec() + +Calculates the time spent on each page. + +# Transferring variables between the apps + +### assignv() + +Copies a variable from the all_apps_wide data frame to the data frames +of all other apps. + +### assignv_to_aaw() + +Copies a variable from one of your data frames to the all_apps_wide data +frame. + +# Before running the experiment + +### show_constant() + +Shows constant variables. diff --git a/_pkgdown.yml b/_pkgdown.yml new file mode 100644 index 0000000..a110a0e --- /dev/null +++ b/_pkgdown.yml @@ -0,0 +1 @@ +url: https://zauchnerp.github.io/gmoTree/ diff --git a/cran-comments.md b/cran-comments.md new file mode 100644 index 0000000..338acd8 --- /dev/null +++ b/cran-comments.md @@ -0,0 +1,15 @@ +# Version 0.0.1 + +``` +❯ checking for portable file names ... WARNING + Found the following files with non-portable file names: + inst/extdata/exp_data_2.1.0/Chat messages (accessed 2023-05-16).csv + inst/extdata/exp_data_2.1.0/TimeSpent (accessed 2023-05-16).csv + inst/extdata/exp_data_2.2.4/Chat messages (accessed 2023-05-13).csv + inst/extdata/exp_data_2.2.4/TimeSpent (accessed 2023-05-13).csv + These are not fully portable file names. + See section 'Package structure' in the 'Writing R Extensions' manual. +``` + +This warning is not circumventable since my package is intended to import +data that may have this pattern (i.e., may include whitespaces). \ No newline at end of file diff --git a/data/oTree.rda b/data/oTree.rda new file mode 100644 index 0000000..0c2db71 Binary files /dev/null and b/data/oTree.rda differ diff --git a/docs/404.html b/docs/404.html new file mode 100644 index 0000000..fde0b80 --- /dev/null +++ b/docs/404.html @@ -0,0 +1,115 @@ + + + + + + + +Page not found (404) • gmoTree + + + + + + + + + + + +
+
+ + + + +
+
+ + +Content not found. Please use links in the navbar. + +
+ + + +
+ + + +
+ +
+

+

Site built with pkgdown 2.0.7.

+
+ +
+
+ + + + + + + + diff --git a/docs/articles/index.html b/docs/articles/index.html new file mode 100644 index 0000000..6ebac78 --- /dev/null +++ b/docs/articles/index.html @@ -0,0 +1,86 @@ + +Articles • gmoTree + + +
+
+ + + +
+
+ + +
+

All vignettes

+

+ +
Introduction to gmoTree
+
+
+
+
+ + +
+ +
+

Site built with pkgdown 2.0.7.

+
+ +
+ + + + + + + + diff --git a/docs/articles/intro_to_gmoTree.html b/docs/articles/intro_to_gmoTree.html new file mode 100644 index 0000000..b7860dc --- /dev/null +++ b/docs/articles/intro_to_gmoTree.html @@ -0,0 +1,972 @@ + + + + + + + +Introduction to gmoTree • gmoTree + + + + + + + + + + + + +
+
+ + + + +
+
+ + + + +

Handling data from online experiments made with oTree (https://www.otree.org/) +can be challenging, especially when dealing with complex experimental +designs that span multiple sessions and return numerous files that must +be combined. This is where the gmoTree package comes in. gmoTree is not +an official package of the oTree team but is built to complement the +oTree open-source platform. It helps streamline the data processing +workflow by providing tools designed to import, merge, and manage data +from oTree experiments.

+
+

Importing and cleaning up data +

+
+

Background information on the data downloaded by oTree +

+

An oTree experiment is structured around one or more modular units +called ‘apps,’ which encompass one or multiple ‘pages.’ Data generated +from each app can be downloaded individually, offering the flexibility +to analyze separate components of the experiment. For an +all-encompassing view of the experiment, the data from all apps can also +be downloaded in a comprehensive file labeled ‘all_apps_wide.’

+

In addition to the aforementioned app data and the cumulative +all_apps_wide file, oTree generates a file with time stamps for every +page. A file documenting all chat interactions is also provided if the +experiment includes one or multiple chat rooms. In newer oTree versions, +also custom data can be downloaded.

+

When an oTree experiment is run across different databases, this set +of data files is downloaded for each database. This would include +individual app data files, the all_apps_wide file, a file for the time +stamps of every page, and a chat log file if a chat room was used in the +experiment.

+

The gmoTree package’s functionality lies in its ability to load and +aggregate all of these files with ease.

+
+
+

import_otree() +

+

We can import all oTree data and combine them into a list of data +frames using the import otree() function. Each data frame +is named according to its associated app, and the function generates an +accompanying info list that details essential information regarding the +imported files, such as any deleted cases. This information list is +updated as we use other functions within the package.

+

It is worth noting that even if we only use one all_apps_wide file, +we should still load the data with import otree() if we +want to access other functions within the gmoTree package. +Alternatively, we could reproduce the structure created by this function +by hand. The following example shows how to import oTree data, the +structure of the oTree list of data frames after importing the data, and +all of the information provided in oTree$info.

+
+# Get path to the package data
+path <- system.file("extdata/exp_data_5.4.0", package = "gmoTree")
+
+# Import without specifications
+# Import all oTree files in this folder and its subfolders
+otree <- gmoTree::import_otree(path = path)
+## Warning in gmoTree::import_otree(path = path): You have stored all_apps_wide
+## globally but also room-specific. This function will import both of them.
+## (Globally, the files are saved as "all_apps_wide_." Room-specific, the files
+## are saved as "All apps - wide-" or "all_apps_wide-.") After importing the data,
+## make sure nothing is there twice! (Advice: You may use delete_duplicate() to
+## remove duplicate rows of all oTree data frames.
+
+# Check the structure of the oTree list of data frames
+str(otree, 1)
+## List of 8
+##  $ all_apps_wide:'data.frame':   12 obs. of  60 variables:
+##  $ info         :List of 2
+##  $ chatapp      :'data.frame':   8 obs. of  24 variables:
+##  $ dictator     :'data.frame':   48 obs. of  25 variables:
+##  $ start        :'data.frame':   8 obs. of  24 variables:
+##  $ survey       :'data.frame':   8 obs. of  29 variables:
+##  $ Time         :'data.frame':   77 obs. of  10 variables:
+##  $ Chats        :'data.frame':   6 obs. of  7 variables:
+
+# The initial info list
+otree$info
+## $imported_files
+## [1] "C:/Users/User/AppData/Local/R/win-library/4.3/gmoTree/extdata/exp_data_5.4.0/ChatMessages-2023-05-16.csv" 
+## [2] "C:/Users/User/AppData/Local/R/win-library/4.3/gmoTree/extdata/exp_data_5.4.0/PageTimes-2023-05-16.csv"    
+## [3] "C:/Users/User/AppData/Local/R/win-library/4.3/gmoTree/extdata/exp_data_5.4.0/survey_2023-05-16.csv"       
+## [4] "C:/Users/User/AppData/Local/R/win-library/4.3/gmoTree/extdata/exp_data_5.4.0/start_2023-05-16.csv"        
+## [5] "C:/Users/User/AppData/Local/R/win-library/4.3/gmoTree/extdata/exp_data_5.4.0/dictator_2023-05-16.csv"     
+## [6] "C:/Users/User/AppData/Local/R/win-library/4.3/gmoTree/extdata/exp_data_5.4.0/dictator_2023-05-00.csv"     
+## [7] "C:/Users/User/AppData/Local/R/win-library/4.3/gmoTree/extdata/exp_data_5.4.0/chatapp_2023-05-16.csv"      
+## [8] "C:/Users/User/AppData/Local/R/win-library/4.3/gmoTree/extdata/exp_data_5.4.0/all_apps_wide_2023-05-16.csv"
+## [9] "C:/Users/User/AppData/Local/R/win-library/4.3/gmoTree/extdata/exp_data_5.4.0/all_apps_wide-2023-05-16.csv"
+## 
+## $initial_n
+## [1] 12
+

Caution: This function only works if the oTree data is saved using +the typical oTree file pattern!

+
+
+

delete_duplicate() +

+

Sometimes, the same data is imported several times. This could happen +for several reasons. First, one data set might be part of another +because of the download of temporarily stored data before downloading +the final data frame. Second, if room-specific and global data is +imported, the data in the all_apps_wide data frame are +there two times. Third, the same data is stored in several imported +folders. The function delete_duplicate() deletes duplicate +data from all apps and all_apps_wide. It, however, does not +change the Time and Chats data frames.

+

Before running the function, let us first check the number of +participant codes and the initial count before executing the +delete_duplicate() function. In the imported +all_apps_wide data frame, we have 12 participant codes. +However, among these, only 8 are unique, which indicates the presence of +duplicate data. The info data frame suggests that there are +initially 12 entries.

+
+# Initial check before deletion
+length(otree$all_apps_wide$participant.code)
+## [1] 12
+length(unique(otree$all_apps_wide$participant.code))
+## [1] 8
+otree$info$initial_n
+## [1] 12
+

To remove these duplicates, we employ the +delete_duplicate() function:

+
+# Delete duplicate cases
+otree <- delete_duplicate(otree)
+

Please note that details about the deleted rows are not added to a +list of deleted cases. This is because the list might be used for +analysis, and this function mainly focuses on cleaning up an untidy data +import. However, the count in info$initial_n is adjusted +accordingly.

+

After the deletion operation, we should find that all participant +codes are unique, and the count info$initial_n matches the +number of unique participant codes.

+
+# Check participant codes and initial_n after deletion
+length(otree$all_apps_wide$participant.code)
+## [1] 8
+length(unique(otree$all_apps_wide$participant.code))
+## [1] 8
+otree$info$initial_n
+## [1] 8
+
+
+

Dealing with messy Chats and Time data frames +

+

If we combine data from experiments that ran on different versions of +oTree, it might happen that there are several variables referring to the +same attribute in the Time and in the Chats +data frames. The functions messy_chat() and +messy_time() integrate the corresponding variables if used +with the argument combine = TRUE.

+

To show an example, let us first load data from different versions of +oTree.

+
+# Import data from different oTree versions
+otree_all <- gmoTree::import_otree(
+  path = system.file("extdata", package = "gmoTree"))
+## Warning in gmoTree::import_otree(path = system.file("extdata", package =
+## "gmoTree")): You have stored all_apps_wide globally but also room-specific.
+## This function will import both of them. (Globally, the files are saved as
+## "all_apps_wide_." Room-specific, the files are saved as "All apps - wide-" or
+## "all_apps_wide-.") After importing the data, make sure nothing is there twice!
+## (Advice: You may use delete_duplicate() to remove duplicate rows of all oTree
+## data frames.
+
+# Check names of Time data frame
+names(otree_all$Time)
+##  [1] "session_code"               "participant_id_in_session" 
+##  [3] "participant_code"           "page_index"                
+##  [5] "app_name"                   "page_name"                 
+##  [7] "epoch_time"                 "round_number"              
+##  [9] "timeout_happened"           "is_wait_page"              
+## [11] "epoch_time_completed"       "session_id"                
+## [13] "participant__id_in_session" "participant__code"         
+## [15] "time_stamp"                 "seconds_on_page"           
+## [17] "subsession_pk"              "auto_submitted"
+
+# Check names of Chats data frame
+names(otree_all$Chats)
+##  [1] "session_code"               "id_in_session"             
+##  [3] "participant_code"           "channel"                   
+##  [5] "nickname"                   "body"                      
+##  [7] "timestamp"                  "participant__session__code"
+##  [9] "participant__session_id"    "participant__id_in_session"
+## [11] "participant__code"
+

Now we can run the functions messy_time() and +messy_chat(). The warning messages are part of the expected +output, indicating precisely which variables were combined. There is no +need for concern when we see them. However, you can also turn them off +using info = FALSE.

+
+otree_all <- messy_time(otree_all,
+                        combine = TRUE,
+                        info = TRUE)
+## Warning in messy_time(otree_all, combine = TRUE, info = TRUE): More than one variable referred to the time stamp. You asked for combining them with the argument combine = TRUE. Variable(s) "epoch_time," and "time_stamp" was/were integrated to variable "epoch_time_completed" and deleted afterward.
+## More than one variable referred to the participant code. You asked for combining them with the argument combine = TRUE. Variable "participant__code" was integrated into variable "participant_code" The variable "participant__code" was deleted afterward.
+
+otree_all <- messy_chat(otree_all,
+                        combine = TRUE,
+                        info = TRUE)
+## Warning in messy_chat(otree_all, combine = TRUE, info = TRUE): More than one variable referred to the session code in your Chats data frame. You asked for combining them with the argument combine = TRUE. Therefore, variable "participant__session__code" was integrated into variable "session_code." The variable "participant__session__code" was deleted afterward.
+## More than one variable referred to the session code in your Chats data frame. You asked for combining them with the argument combine = TRUE. Therefore, variable "participant__code" was integrated into variable "participant_code" The variable "participant__code" was deleted afterward.
+
+# Check names of Time data frame again
+names(otree_all$Time)
+##  [1] "session_code"               "participant_id_in_session" 
+##  [3] "participant_code"           "page_index"                
+##  [5] "app_name"                   "page_name"                 
+##  [7] "round_number"               "timeout_happened"          
+##  [9] "is_wait_page"               "epoch_time_completed"      
+## [11] "session_id"                 "participant__id_in_session"
+## [13] "seconds_on_page"            "subsession_pk"             
+## [15] "auto_submitted"
+
+# Check names of Chats data frame again
+names(otree_all$Chats)
+## [1] "session_code"               "id_in_session"             
+## [3] "participant_code"           "channel"                   
+## [5] "nickname"                   "body"                      
+## [7] "timestamp"                  "participant__session_id"   
+## [9] "participant__id_in_session"
+
+
+
+

Dealing with dropouts and deleting cases +

+
+

show_dropouts() +

+

Sometimes, participants drop out of experiments. To get an overview +of the dropouts, we can use the function show_dropouts(). +It creates three data frames/tables with information on the participants +that did not finish at (a) certain app(s) or page(s).

+

First, the function show_dropouts() creates a data frame +full that provides specific information on the apps and +pages where participants left the experiment prematurely. Additionally, +this data frame indicates which apps were affected by the participants +who dropped out.

+
+# Show everyone that has not finished with the app "survey"
+dropout_list <- show_dropouts(otree, "survey")
+
+head(dropout_list$full)
+##   participant.code session.code  end_app        end_page
+## 1         1k58kgm7     jk9ekpl0 dictator ResultsWaitPage
+## 2         1k58kgm7     jk9ekpl0 dictator ResultsWaitPage
+## 3         1k58kgm7     jk9ekpl0 dictator ResultsWaitPage
+## 4         1k58kgm7     jk9ekpl0 dictator ResultsWaitPage
+## 5         1k58kgm7     jk9ekpl0 dictator ResultsWaitPage
+## 6         dhgisush     2wlrl5kb dictator           Offer
+##                                                reason
+## 1 Experiment not completed. Noticed at: all_apps_wide
+## 2       Experiment not completed. Noticed at: chatapp
+## 3      Experiment not completed. Noticed at: dictator
+## 4         Experiment not completed. Noticed at: start
+## 5        Experiment not completed. Noticed at: survey
+## 6 Experiment not completed. Noticed at: all_apps_wide
+

Second, the function show_dropouts() also generates a +smaller data frame unique that only includes information on +each person once.

+
+dropout_list$unique
+##    participant.code session.code  end_app        end_page
+## 1          1k58kgm7     jk9ekpl0 dictator ResultsWaitPage
+## 6          dhgisush     2wlrl5kb dictator           Offer
+## 11         j2g9mcaf     jk9ekpl0 dictator    Introduction
+## 16         p6m495xi     2wlrl5kb dictator    Introduction
+##                      reason
+## 1  Experiment not completed
+## 6  Experiment not completed
+## 11 Experiment not completed
+## 16 Experiment not completed
+

Third, the function show_dropouts() furthermore creates +a table all_end, which contains information on all +participants and where they ended the experiment. The columns contain +the names of the pages of the experiment; the rows contain the names of +the apps.

+
+dropout_list$all_end
+##           
+##            Demographics Introduction Offer ResultsWaitPage
+##   dictator            0            2     1               1
+##   survey              4            0     0               0
+
+
+

delete_dropouts() +

+

Normally, we want to exclude dropouts from our analysis. The function +delete_dropouts() removes all data related to participants +who prematurely terminated the experiment from the data frames in the +oTree list, except the data contained within the info list and the +Chats data frame. I highly recommend personally deleting +the chat data because it can occasionally become unintelligible once one +person’s input is removed. Therefore, this function does not delete the +chat input of the participants who dropped out of the experiment.

+

Before running the example, let us first check the row numbers of +some data frames.

+
+# First, check some row numbers
+nrow(otree$all_apps_wide)
+## [1] 8
+nrow(otree$survey)
+## [1] 8
+nrow(otree$Time)
+## [1] 77
+nrow(otree$Chats)
+## [1] 6
+

When we run the function delete_dropouts() and check the +row numbers again, we see that cases were deleted in each data frame but +not in the Chats data frame.

+
+# Delete all cases that didn't end the experiment on the page "Demographics"
+# within the app "survey"
+otree2 <- delete_dropouts(otree,
+                         final_apps = c("survey"),
+                         final_pages = c("Demographics"),
+                         info = TRUE)
+## 4 case(s) deleted
+## Dropouts are deleted from all data frames. Except: The list of oTree data frames includes a chat. As the interpretation of chat data depends on how participants engage with each other, the data must be deleted with more care than deleting data in other apps. Hence, this function does not delete data in this data frame. Please do this manually if necessary!
+
+# Check row numbers again
+nrow(otree2$all_apps_wide)
+## [1] 4
+nrow(otree2$survey)
+## [1] 4
+nrow(otree2$Time)
+## [1] 66
+nrow(otree2$Chats)
+## [1] 6
+

Just as show_dropouts(), the +delete_dropouts() function also gives detailed information +on all the deleted cases.

+
+head(otree2$info$deleted_cases$full)
+##   participant.code session.code  end_app        end_page
+## 1         1k58kgm7     jk9ekpl0 dictator ResultsWaitPage
+## 2         1k58kgm7     jk9ekpl0 dictator ResultsWaitPage
+## 3         1k58kgm7     jk9ekpl0 dictator ResultsWaitPage
+## 4         1k58kgm7     jk9ekpl0 dictator ResultsWaitPage
+## 5         1k58kgm7     jk9ekpl0 dictator ResultsWaitPage
+## 6         dhgisush     2wlrl5kb dictator           Offer
+##                           reason
+## 1        ENC. Noticed at: survey
+## 2         ENC. Noticed at: start
+## 3      ENC. Noticed at: dictator
+## 4       ENC. Noticed at: chatapp
+## 5 ENC. Noticed at: all_apps_wide
+## 6        ENC. Noticed at: survey
+
+
+otree2$info$deleted_cases$unique
+##    participant.code session.code  end_app        end_page reason
+## 1          1k58kgm7     jk9ekpl0 dictator ResultsWaitPage    ENC
+## 6          dhgisush     2wlrl5kb dictator           Offer    ENC
+## 11         j2g9mcaf     jk9ekpl0 dictator    Introduction    ENC
+## 16         p6m495xi     2wlrl5kb dictator    Introduction    ENC
+
+
+otree2$info$deleted_cases$all_end
+##           
+##            Demographics Introduction Offer ResultsWaitPage
+##   dictator            0            2     1               1
+##   survey              4            0     0               0
+

Caution: This function does not delete any data from the original CSV +and Excel files!

+
+
+

delete_cases() +

+

Sometimes, participants ask for their data to be deleted. The +delete_cases() function can delete a person from each app’s +data frame, all_apps_wide, and the Time data +frame. Again, data in the Chats data frame must be deleted +by hand.

+
+# First, check some row numbers
+nrow(otree2$all_apps_wide)
+## [1] 4
+nrow(otree2$survey)
+## [1] 4
+nrow(otree2$Time)
+## [1] 66
+nrow(otree2$Chats)
+## [1] 6
+
+# Delete one participant
+person <- otree2$all_apps_wide$participant.code[1]
+otree2 <- delete_cases(otree2,
+                       pcodes = person,
+                       reason = "requested",
+                       saved_vars = "participant._index_in_pages",
+                       info = TRUE)
+## 1 case(s) deleted. Cases are deleted from all data frames. Except: The list of oTree data frames includes a chat. As the interpretation of chat data depends on how participants engage with each other, the data must be deleted with more care than deleting data in other apps. Hence, this function does not delete data in this data frame. Please do this manually if necessary!
+
+# Check row numbers again
+nrow(otree2$all_apps_wide)
+## [1] 3
+nrow(otree2$survey)
+## [1] 3
+nrow(otree2$Time)
+## [1] 48
+nrow(otree2$Chats)
+## [1] 6
+

This function adds the information of all these deleted cases to the +previously created information on all deleted cases.

+
+# Check for all deleted cases (also dropouts):
+tail(otree2$info$deleted_cases$full)
+##    participant.code session.code  end_app     end_page
+## 16         p6m495xi     2wlrl5kb dictator Introduction
+## 17         p6m495xi     2wlrl5kb dictator Introduction
+## 18         p6m495xi     2wlrl5kb dictator Introduction
+## 19         p6m495xi     2wlrl5kb dictator Introduction
+## 20         p6m495xi     2wlrl5kb dictator Introduction
+## 21         sdh9ar2m         <NA>                      
+##                            reason  session participant._index_in_pages
+## 16        ENC. Noticed at: survey     <NA>                          NA
+## 17         ENC. Noticed at: start     <NA>                          NA
+## 18      ENC. Noticed at: dictator     <NA>                          NA
+## 19       ENC. Noticed at: chatapp     <NA>                          NA
+## 20 ENC. Noticed at: all_apps_wide     <NA>                          NA
+## 21                      requested jk9ekpl0                          18
+

Caution: This function does not delete any data from the original CSV +and Excel files!

+
+
+

delete_sessions() +

+

While we certainly hope that it never becomes necessary, there may be +instances where an entire session needs to be removed from the data set +due to unforeseen issues. However, if that occurs, we can use the +function delete_sessions(). This function removes not only +the sessions’ data in all apps, all_apps_wide, and the +Time data frame but also the sessions’ chat data in the +Chats data frame because chatting is usually restricted +within a session.

+

In the following, we see the row numbers before deletion, the +application of the function, and the row numbers after deletion. Apart +from the other functions, the sessions’ entries in the +Chats data frame are destroyed here since chat data occurs +just once per session and may thus be eliminated without impacting the +comprehensibility of the chat data.

+
+# First, check some row numbers
+nrow(otree2$all_apps_wide)
+## [1] 3
+nrow(otree2$survey)
+## [1] 3
+nrow(otree2$Time)
+## [1] 48
+nrow(otree2$Chats)
+## [1] 6
+
+# Delete one session
+otree2 <- delete_sessions(otree,
+  scodes = "jk9ekpl0",
+  reason = "Only tests",
+  info = TRUE)
+## 4 case(s) deleted
+
+# Check row numbers again
+nrow(otree2$all_apps_wide)
+## [1] 4
+nrow(otree2$survey)
+## [1] 4
+nrow(otree2$Time)
+## [1] 38
+nrow(otree2$Chats)
+## [1] 3
+
+
+
+

Deleting sensitive information +

+
+

delete_pabels() +

+

It is not uncommon for the participant.label variable to contain +sensitive information like an MTurk worker ID. This can raise serious +privacy concerns. The function delete_plabels() +automatically removes the participant.label variable from +all data frames. Additionally, the function has the option to delete all +MTurk-related variables.

+

In the following, we see the application of the +delete_plabels() function, preceded by information on the +sensitive variables before running the function and followed by +information on the sensitive variables after running the function.

+
+# Check variables
+head(otree2$all_apps_wide$participant.label)
+## [1] ""        ""        "Person1" "Person2"
+head(otree2$all_apps_wide$participant.mturk_worker_id)
+## [1] NA NA NA NA
+head(otree2$survey$participant.label)
+## [1] ""        ""        "Person1" "Person2"
+
+# Delete all participant labels
+otree2 <- delete_plabels(otree2, del_mturk = TRUE)
+
+# Check variables
+head(otree2$all_apps_wide$participant.label)
+## NULL
+head(otree2$all_apps_wide$participant.mturk_worker_id)
+## NULL
+head(otree2$survey$participant.label)
+## NULL
+

Caution: This function does not delete the variable from the original +CSV and Excel files!

+
+
+
+

Making IDs +

+
+

make_ids() +

+

When working with oTree, participant codes, session codes, and group +IDs are used to identify the cases. However, often, researchers prefer a +streamlined, consecutive numbering system that spans all sessions, +beginning with the first participant, session, or group and concluding +with the last. The make_ids() function provides a way to +achieve this goal. Before using the function, let us inspect the +underlying variables first.

+
+# Check variables first
+otree2$all_apps_wide$participant.code
+## [1] "dhgisush" "p6m495xi" "c9inx5wl" "kr8yd7f3"
+otree2$all_apps_wide$session.code
+## [1] "2wlrl5kb" "2wlrl5kb" "mz2r27bk" "mz2r27bk"
+otree2$all_apps_wide$dictator.1.group.id_in_subsession
+## [1] 1 1 1 1
+
+# Make session IDs only
+otree2 <- make_ids(otree2)
+

This function returns the following variables.

+
+# Check variables
+otree2$all_apps_wide$participant_id
+## [1] 1 2 3 4
+otree2$all_apps_wide$session_id
+## [1] 1 1 2 2
+

In the prior example, Group IDs were not calculated because group IDs +must be called specifically. Since the group IDs per app in our data do +not match (groups are only relevant in the dictator app), just using +group_id = TRUE would lead to an error message.

+

For cases where the group IDs vary among apps, it can be specified in +make_ids() which app or variable should be used for +extracting group information. For instance, the following syntax can be +used to obtain group IDs from the variable +dictator.1.group.id_in_subsession in +all_apps_wide.

+
+# Get IDs from "from_variable" in the data frame "all_apps_wide"
+otree2 <- make_ids(otree2,
+                   # gmake = TRUE,  # Not necessary if from_var is not NULL
+                   from_var = "dictator.1.group.id_in_subsession")
+## Warning in make_ids(otree2, from_var = "dictator.1.group.id_in_subsession"):
+## The group variable values are constant. Group IDs now correspond to session
+## IDs.
+
+# Check variables
+otree2$all_apps_wide$participant_id
+## [1] 1 2 3 4
+otree2$all_apps_wide$group_id
+## [1] 1 1 2 2
+otree2$all_apps_wide$session_id
+## [1] 1 1 2 2
+
+
+
+

Calculating the time +

+
+

apptime() +

+

If we need to determine how much time the participants spent on a +specific app, the apptime() function is a powerful tool +that can help. This function calculates summary statistics such as the +mean, minimum, and maximum time spent on each page, as well as a +detailed list of durations for each participant in the app. The +following example shows how much time the participants spent on the app +‘survey’ in minutes.

+
+# Calculate the time all participants spent on app "survey"
+apptime(otree2, apps = "survey", digits = 3)
+## $mean_duration
+## [1] 0.242
+## 
+## $min_duration
+## [1] 0.233
+## 
+## $max_duration
+## [1] 0.25
+## 
+## $single_durations
+##   participant  session duration
+## 1    c9inx5wl mz2r27bk    0.250
+## 2    kr8yd7f3 mz2r27bk    0.233
+## 
+## $messages
+## [1] "For some participants, no duration could be calculated. See list in $warnings. Did they make it to the app(s)?"
+## 
+## $warnings
+## [1] "dhgisush" "p6m495xi"
+

We can also get the time for specified individuals only. Without the +specification of the apps, we get their durations for all apps +individually.

+
+# Calculate the time one participant spent on app "dictator"
+apptime(otree2, pcode = "c9inx5wl", digits = 3)
+## $chatapp
+## [1] 0.267
+## 
+## $dictator
+## [1] 0.5
+## 
+## $start
+## [1] 0.017
+## 
+## $survey
+## [1] 0.25
+
+
+

extime() +

+

If we need to determine how much time participants spent on the +complete experiment, we can use the extime() function. This +function calculates summary statistics such as the mean, minimum, and +maximum time spent on the experiment, as well as a detailed list of +durations for each participant. (Note that these min, max, and mean +values only have two digits because of the underlying data.)

+
+# Calculate the time that all participants spent on the experiment
+extime(otree2, digits = 3)
+## $mean_duration
+## [1] 0.525
+## 
+## $min_duration
+## [1] 0.05
+## 
+## $max_duration
+## [1] 1.033
+## 
+## $single_durations
+##   participant  session duration
+## 2    p6m495xi 2wlrl5kb    0.050
+## 1    dhgisush 2wlrl5kb    0.117
+## 4    kr8yd7f3 mz2r27bk    0.900
+## 3    c9inx5wl mz2r27bk    1.033
+

We can also get the duration for just one participant.

+
+# Calculate the time one participant spent on the experiment
+extime(otree2, pcode = "c9inx5wl", digits = 3)
+## [1] 1.033
+
+
+

pagesec() +

+

The older versions of oTree included a variable called +seconds_on_page in the Time data frame. +Although there is a good reason to omit it, we sometimes want to have +more detailed information on the time spent on one page. Therefore, I +created the function pagesec() that adds a new variable +seconds_on_page2 to the Time data frame.

+
+# Create two new columns: seconds_on_page2 and minutes_on_page
+otree2 <- pagesec(otree2, rounded = TRUE, minutes = TRUE)
+tail(otree2$Time)
+##    timeout_happened is_wait_page group_id session_id participant_id
+## 72                0            0        2          2              3
+## 73                0            0        2          2              4
+## 74                0            0        2          2              4
+## 75                0            0        2          2              3
+## 76                0            0        2          2              4
+## 77                0            0        2          2              3
+##    session_code participant_id_in_session participant_code page_index app_name
+## 72     mz2r27bk                         1         c9inx5wl         15   survey
+## 73     mz2r27bk                         2         kr8yd7f3         15   survey
+## 74     mz2r27bk                         2         kr8yd7f3         16   survey
+## 75     mz2r27bk                         1         c9inx5wl         16   survey
+## 76     mz2r27bk                         2         kr8yd7f3         17   survey
+## 77     mz2r27bk                         1         c9inx5wl         17   survey
+##                  page_name epoch_time_completed round_number minutes_on_page
+## 72 CognitiveReflectionTest           1684258104            1            0.05
+## 73 CognitiveReflectionTest           1684258108            1            0.13
+## 74                   Offer           1684258109            1            0.02
+## 75                   Offer           1684258110            1            0.10
+## 76            Demographics           1684258114            1            0.08
+## 77            Demographics           1684258116            1            0.10
+
+
+
+

Transferring variables between the apps +

+
+

assignv() +

+

The function assignv() copies a variable from the +all_apps_wide data frame to the data frames of all other +apps. In the following example, the variable survey.1.player.gender is +copied from all_apps_wide to all other app data frames; in +all of these data frames, the new variable is named gender. +It also copies the variable to all_apps_wide to keep some +degree of consistency.

+
+# Assign variable "survey.1.player.gender" and name it "gender"
+otree2 <- assignv(oTree = otree2,
+                 variable = "survey.1.player.gender",
+                 newvar = "gender")
+# Control
+otree2$dictator$gender
+##  [1] ""       ""       ""       ""       ""       ""       "Female" "Male"  
+##  [9] "Female" "Male"   "Female" "Male"
+otree2$chatapp$gender
+## [1] ""       ""       "Female" "Male"
+# In app "survey", the variable is now twice because it is taken from here
+otree2$survey$gender
+## [1] ""       ""       "Female" "Male"
+otree2$survey$player.gender
+## [1] ""       ""       "Female" "Male"
+# In app "all_apps_wide," the variable is also there twice
+# (This can be avoided by calling the new variable the same
+# as the old variable)
+otree2$all_apps_wide$gender
+## [1] ""       ""       "Female" "Male"
+otree2$all_apps_wide$survey.1.player.gender
+## [1] ""       ""       "Female" "Male"
+
+
+

assignv_to_aaw() +

+

The function assignv_to_aaw() copies a variable from one +of the data frames to the all_apps_wide data frame. In the +following example, a variable from the app survey is copied +to all_apps_wide and placed directly after the variable +survey.1.player.age.

+
+# Create a new variable
+otree2$survey$younger30 <- ifelse(otree2$survey$player.age < 30, 0, 1)
+
+# Get variable younger30 from survey to all_apps_wide
+# and put the new variable right behind the old age variable
+otree2 <- assignv_to_aaw(otree2,
+                        app = "survey",
+                        variable = "younger30",
+                        newvar = "younger30",
+                        resafter = "survey.1.player.age")
+
+# Control
+otree2$all_apps_wide$survey.1.player.age
+## [1] NA NA 66 33
+
+# Check the position of the old age variable and the new variable
+match("survey.1.player.age", colnames(otree2$all_apps_wide))
+## [1] 52
+match("younger30", colnames(otree2$all_apps_wide))
+## [1] 53
+
+
+
+

Before running the experiment +

+
+

show_constant() +

+

When we program experiments, we frequently add variables that turn +out to be useless later. When we forget to remove them, especially in +experiments with numerous rounds, the data frame becomes unreasonably +huge. With the function show_constant(), we may identify +variables that have no variation and remove them before the experiment. +In the following example, a variable named constant is +created, which does not vary. The function show_constant() +shows us many variables that are also unchanging; however, we cannot +delete most of them because they are oTree internal. Yet, to prevent an +unreasonably large data frame, we should remove the variable +constant before running the experiment.

+
+# Make a constant column (this variable is usually created in oTree)
+otree2$dictator$constant <- 3
+
+# Show all columns that contain columns containing only one specified value
+show_constant(oTree = otree2)
+## $all_apps_wide
+##  [1] "participant._is_bot"                         
+##  [2] "participant._max_page_index"                 
+##  [3] "participant.visited"                         
+##  [4] "session.label"                               
+##  [5] "session.comment"                             
+##  [6] "session.config.real_world_currency_per_point"
+##  [7] "session.config.name"                         
+##  [8] "session.config.participation_fee"            
+##  [9] "start.1.player.role"                         
+## [10] "start.1.player.payoff"                       
+## [11] "start.1.group.id_in_subsession"              
+## [12] "start.1.subsession.round_number"             
+## [13] "dictator.1.player.role"                      
+## [14] "dictator.1.group.id_in_subsession"           
+## [15] "dictator.1.subsession.round_number"          
+## [16] "dictator.2.player.role"                      
+## [17] "dictator.2.group.id_in_subsession"           
+## [18] "dictator.2.subsession.round_number"          
+## [19] "dictator.3.player.role"                      
+## [20] "dictator.3.group.id_in_subsession"           
+## [21] "dictator.3.subsession.round_number"          
+## [22] "chatapp.1.player.role"                       
+## [23] "chatapp.1.player.payoff"                     
+## [24] "chatapp.1.group.id_in_subsession"            
+## [25] "chatapp.1.subsession.round_number"           
+## [26] "survey.1.player.role"                        
+## [27] "survey.1.player.payoff"                      
+## [28] "survey.1.group.id_in_subsession"             
+## [29] "survey.1.subsession.round_number"            
+## 
+## $chatapp
+## [1] "session.comment"             "participant._is_bot"        
+## [3] "participant._max_page_index" "participant.visited"        
+## [5] "player.role"                 "player.payoff"              
+## [7] "group.id_in_subsession"      "subsession.round_number"    
+## [9] "session.label"              
+## 
+## $dictator
+## [1] "session.comment"             "participant._is_bot"        
+## [3] "participant._max_page_index" "participant.visited"        
+## [5] "player.role"                 "group.id_in_subsession"     
+## [7] "session.label"               "constant"                   
+## 
+## $start
+## [1] "session.comment"             "participant._is_bot"        
+## [3] "participant._max_page_index" "participant.visited"        
+## [5] "player.role"                 "player.payoff"              
+## [7] "group.id_in_subsession"      "subsession.round_number"    
+## [9] "session.label"              
+## 
+## $survey
+## [1] "session.comment"             "participant._is_bot"        
+## [3] "participant._max_page_index" "participant.visited"        
+## [5] "player.role"                 "player.payoff"              
+## [7] "group.id_in_subsession"      "subsession.round_number"    
+## [9] "session.label"              
+## 
+## $Time
+## character(0)
+## 
+## $Chats
+## [1] "group_id"     "session_id"   "session_code" "channel"
+
+
+
+ + + +
+ + + +
+ +
+

+

Site built with pkgdown 2.0.7.

+
+ +
+
+ + + + + + + + diff --git a/docs/authors.html b/docs/authors.html new file mode 100644 index 0000000..d629d1a --- /dev/null +++ b/docs/authors.html @@ -0,0 +1,105 @@ + +Authors and Citation • gmoTree + + +
+
+ + + +
+
+
+ + + +
  • +

    Patricia F. Zauchner. Author, translator, maintainer, copyright holder. +

    +
  • +
+
+
+

Citation

+ Source: inst/CITATION +
+
+ + +

Zauchner, Patricia F. (2023). gmoTree: oTree Data Manipulation Tool. R package version 0.0.1, <https://github.com/ZauchnerP/gmoTree/>

+
@Manual{,
+  title = {gmoTree: oTree Data Manipulation Tool},
+  author = {Patricia F. Zauchner},
+  year = {2023},
+  note = {R package version 0.0.1},
+  url = {https://github.com/ZauchnerP/gmoTree},
+}
+ +
+ +
+ + + +
+ +
+

Site built with pkgdown 2.0.7.

+
+ +
+ + + + + + + + diff --git a/docs/bootstrap-toc.css b/docs/bootstrap-toc.css new file mode 100644 index 0000000..5a85941 --- /dev/null +++ b/docs/bootstrap-toc.css @@ -0,0 +1,60 @@ +/*! + * Bootstrap Table of Contents v0.4.1 (http://afeld.github.io/bootstrap-toc/) + * Copyright 2015 Aidan Feldman + * Licensed under MIT (https://github.com/afeld/bootstrap-toc/blob/gh-pages/LICENSE.md) */ + +/* modified from https://github.com/twbs/bootstrap/blob/94b4076dd2efba9af71f0b18d4ee4b163aa9e0dd/docs/assets/css/src/docs.css#L548-L601 */ + +/* All levels of nav */ +nav[data-toggle='toc'] .nav > li > a { + display: block; + padding: 4px 20px; + font-size: 13px; + font-weight: 500; + color: #767676; +} +nav[data-toggle='toc'] .nav > li > a:hover, +nav[data-toggle='toc'] .nav > li > a:focus { + padding-left: 19px; + color: #563d7c; + text-decoration: none; + background-color: transparent; + border-left: 1px solid #563d7c; +} +nav[data-toggle='toc'] .nav > .active > a, +nav[data-toggle='toc'] .nav > .active:hover > a, +nav[data-toggle='toc'] .nav > .active:focus > a { + padding-left: 18px; + font-weight: bold; + color: #563d7c; + background-color: transparent; + border-left: 2px solid #563d7c; +} + +/* Nav: second level (shown on .active) */ +nav[data-toggle='toc'] .nav .nav { + display: none; /* Hide by default, but at >768px, show it */ + padding-bottom: 10px; +} +nav[data-toggle='toc'] .nav .nav > li > a { + padding-top: 1px; + padding-bottom: 1px; + padding-left: 30px; + font-size: 12px; + font-weight: normal; +} +nav[data-toggle='toc'] .nav .nav > li > a:hover, +nav[data-toggle='toc'] .nav .nav > li > a:focus { + padding-left: 29px; +} +nav[data-toggle='toc'] .nav .nav > .active > a, +nav[data-toggle='toc'] .nav .nav > .active:hover > a, +nav[data-toggle='toc'] .nav .nav > .active:focus > a { + padding-left: 28px; + font-weight: 500; +} + +/* from https://github.com/twbs/bootstrap/blob/e38f066d8c203c3e032da0ff23cd2d6098ee2dd6/docs/assets/css/src/docs.css#L631-L634 */ +nav[data-toggle='toc'] .nav > .active > ul { + display: block; +} diff --git a/docs/bootstrap-toc.js b/docs/bootstrap-toc.js new file mode 100644 index 0000000..1cdd573 --- /dev/null +++ b/docs/bootstrap-toc.js @@ -0,0 +1,159 @@ +/*! + * Bootstrap Table of Contents v0.4.1 (http://afeld.github.io/bootstrap-toc/) + * Copyright 2015 Aidan Feldman + * Licensed under MIT (https://github.com/afeld/bootstrap-toc/blob/gh-pages/LICENSE.md) */ +(function() { + 'use strict'; + + window.Toc = { + helpers: { + // return all matching elements in the set, or their descendants + findOrFilter: function($el, selector) { + // http://danielnouri.org/notes/2011/03/14/a-jquery-find-that-also-finds-the-root-element/ + // http://stackoverflow.com/a/12731439/358804 + var $descendants = $el.find(selector); + return $el.filter(selector).add($descendants).filter(':not([data-toc-skip])'); + }, + + generateUniqueIdBase: function(el) { + var text = $(el).text(); + var anchor = text.trim().toLowerCase().replace(/[^A-Za-z0-9]+/g, '-'); + return anchor || el.tagName.toLowerCase(); + }, + + generateUniqueId: function(el) { + var anchorBase = this.generateUniqueIdBase(el); + for (var i = 0; ; i++) { + var anchor = anchorBase; + if (i > 0) { + // add suffix + anchor += '-' + i; + } + // check if ID already exists + if (!document.getElementById(anchor)) { + return anchor; + } + } + }, + + generateAnchor: function(el) { + if (el.id) { + return el.id; + } else { + var anchor = this.generateUniqueId(el); + el.id = anchor; + return anchor; + } + }, + + createNavList: function() { + return $(''); + }, + + createChildNavList: function($parent) { + var $childList = this.createNavList(); + $parent.append($childList); + return $childList; + }, + + generateNavEl: function(anchor, text) { + var $a = $(''); + $a.attr('href', '#' + anchor); + $a.text(text); + var $li = $('
  • '); + $li.append($a); + return $li; + }, + + generateNavItem: function(headingEl) { + var anchor = this.generateAnchor(headingEl); + var $heading = $(headingEl); + var text = $heading.data('toc-text') || $heading.text(); + return this.generateNavEl(anchor, text); + }, + + // Find the first heading level (`

    `, then `

    `, etc.) that has more than one element. Defaults to 1 (for `

    `). + getTopLevel: function($scope) { + for (var i = 1; i <= 6; i++) { + var $headings = this.findOrFilter($scope, 'h' + i); + if ($headings.length > 1) { + return i; + } + } + + return 1; + }, + + // returns the elements for the top level, and the next below it + getHeadings: function($scope, topLevel) { + var topSelector = 'h' + topLevel; + + var secondaryLevel = topLevel + 1; + var secondarySelector = 'h' + secondaryLevel; + + return this.findOrFilter($scope, topSelector + ',' + secondarySelector); + }, + + getNavLevel: function(el) { + return parseInt(el.tagName.charAt(1), 10); + }, + + populateNav: function($topContext, topLevel, $headings) { + var $context = $topContext; + var $prevNav; + + var helpers = this; + $headings.each(function(i, el) { + var $newNav = helpers.generateNavItem(el); + var navLevel = helpers.getNavLevel(el); + + // determine the proper $context + if (navLevel === topLevel) { + // use top level + $context = $topContext; + } else if ($prevNav && $context === $topContext) { + // create a new level of the tree and switch to it + $context = helpers.createChildNavList($prevNav); + } // else use the current $context + + $context.append($newNav); + + $prevNav = $newNav; + }); + }, + + parseOps: function(arg) { + var opts; + if (arg.jquery) { + opts = { + $nav: arg + }; + } else { + opts = arg; + } + opts.$scope = opts.$scope || $(document.body); + return opts; + } + }, + + // accepts a jQuery object, or an options object + init: function(opts) { + opts = this.helpers.parseOps(opts); + + // ensure that the data attribute is in place for styling + opts.$nav.attr('data-toggle', 'toc'); + + var $topContext = this.helpers.createChildNavList(opts.$nav); + var topLevel = this.helpers.getTopLevel(opts.$scope); + var $headings = this.helpers.getHeadings(opts.$scope, topLevel); + this.helpers.populateNav($topContext, topLevel, $headings); + } + }; + + $(function() { + $('nav[data-toggle="toc"]').each(function(i, el) { + var $nav = $(el); + Toc.init($nav); + }); + }); +})(); diff --git a/docs/docsearch.css b/docs/docsearch.css new file mode 100644 index 0000000..e5f1fe1 --- /dev/null +++ b/docs/docsearch.css @@ -0,0 +1,148 @@ +/* Docsearch -------------------------------------------------------------- */ +/* + Source: https://github.com/algolia/docsearch/ + License: MIT +*/ + +.algolia-autocomplete { + display: block; + -webkit-box-flex: 1; + -ms-flex: 1; + flex: 1 +} + +.algolia-autocomplete .ds-dropdown-menu { + width: 100%; + min-width: none; + max-width: none; + padding: .75rem 0; + background-color: #fff; + background-clip: padding-box; + border: 1px solid rgba(0, 0, 0, .1); + box-shadow: 0 .5rem 1rem rgba(0, 0, 0, .175); +} + +@media (min-width:768px) { + .algolia-autocomplete .ds-dropdown-menu { + width: 175% + } +} + +.algolia-autocomplete .ds-dropdown-menu::before { + display: none +} + +.algolia-autocomplete .ds-dropdown-menu [class^=ds-dataset-] { + padding: 0; + background-color: rgb(255,255,255); + border: 0; + max-height: 80vh; +} + +.algolia-autocomplete .ds-dropdown-menu .ds-suggestions { + margin-top: 0 +} + +.algolia-autocomplete .algolia-docsearch-suggestion { + padding: 0; + overflow: visible +} + +.algolia-autocomplete .algolia-docsearch-suggestion--category-header { + padding: .125rem 1rem; + margin-top: 0; + font-size: 1.3em; + font-weight: 500; + color: #00008B; + border-bottom: 0 +} + +.algolia-autocomplete .algolia-docsearch-suggestion--wrapper { + float: none; + padding-top: 0 +} + +.algolia-autocomplete .algolia-docsearch-suggestion--subcategory-column { + float: none; + width: auto; + padding: 0; + text-align: left +} + +.algolia-autocomplete .algolia-docsearch-suggestion--content { + float: none; + width: auto; + padding: 0 +} + +.algolia-autocomplete .algolia-docsearch-suggestion--content::before { + display: none +} + +.algolia-autocomplete .ds-suggestion:not(:first-child) .algolia-docsearch-suggestion--category-header { + padding-top: .75rem; + margin-top: .75rem; + border-top: 1px solid rgba(0, 0, 0, .1) +} + +.algolia-autocomplete .ds-suggestion .algolia-docsearch-suggestion--subcategory-column { + display: block; + padding: .1rem 1rem; + margin-bottom: 0.1; + font-size: 1.0em; + font-weight: 400 + /* display: none */ +} + +.algolia-autocomplete .algolia-docsearch-suggestion--title { + display: block; + padding: .25rem 1rem; + margin-bottom: 0; + font-size: 0.9em; + font-weight: 400 +} + +.algolia-autocomplete .algolia-docsearch-suggestion--text { + padding: 0 1rem .5rem; + margin-top: -.25rem; + font-size: 0.8em; + font-weight: 400; + line-height: 1.25 +} + +.algolia-autocomplete .algolia-docsearch-footer { + width: 110px; + height: 20px; + z-index: 3; + margin-top: 10.66667px; + float: right; + font-size: 0; + line-height: 0; +} + +.algolia-autocomplete .algolia-docsearch-footer--logo { + background-image: url("data:image/svg+xml;utf8,"); + background-repeat: no-repeat; + background-position: 50%; + background-size: 100%; + overflow: hidden; + text-indent: -9000px; + width: 100%; + height: 100%; + display: block; + transform: translate(-8px); +} + +.algolia-autocomplete .algolia-docsearch-suggestion--highlight { + color: #FF8C00; + background: rgba(232, 189, 54, 0.1) +} + + +.algolia-autocomplete .algolia-docsearch-suggestion--text .algolia-docsearch-suggestion--highlight { + box-shadow: inset 0 -2px 0 0 rgba(105, 105, 105, .5) +} + +.algolia-autocomplete .ds-suggestion.ds-cursor .algolia-docsearch-suggestion--content { + background-color: rgba(192, 192, 192, .15) +} diff --git a/docs/docsearch.js b/docs/docsearch.js new file mode 100644 index 0000000..b35504c --- /dev/null +++ b/docs/docsearch.js @@ -0,0 +1,85 @@ +$(function() { + + // register a handler to move the focus to the search bar + // upon pressing shift + "/" (i.e. "?") + $(document).on('keydown', function(e) { + if (e.shiftKey && e.keyCode == 191) { + e.preventDefault(); + $("#search-input").focus(); + } + }); + + $(document).ready(function() { + // do keyword highlighting + /* modified from https://jsfiddle.net/julmot/bL6bb5oo/ */ + var mark = function() { + + var referrer = document.URL ; + var paramKey = "q" ; + + if (referrer.indexOf("?") !== -1) { + var qs = referrer.substr(referrer.indexOf('?') + 1); + var qs_noanchor = qs.split('#')[0]; + var qsa = qs_noanchor.split('&'); + var keyword = ""; + + for (var i = 0; i < qsa.length; i++) { + var currentParam = qsa[i].split('='); + + if (currentParam.length !== 2) { + continue; + } + + if (currentParam[0] == paramKey) { + keyword = decodeURIComponent(currentParam[1].replace(/\+/g, "%20")); + } + } + + if (keyword !== "") { + $(".contents").unmark({ + done: function() { + $(".contents").mark(keyword); + } + }); + } + } + }; + + mark(); + }); +}); + +/* Search term highlighting ------------------------------*/ + +function matchedWords(hit) { + var words = []; + + var hierarchy = hit._highlightResult.hierarchy; + // loop to fetch from lvl0, lvl1, etc. + for (var idx in hierarchy) { + words = words.concat(hierarchy[idx].matchedWords); + } + + var content = hit._highlightResult.content; + if (content) { + words = words.concat(content.matchedWords); + } + + // return unique words + var words_uniq = [...new Set(words)]; + return words_uniq; +} + +function updateHitURL(hit) { + + var words = matchedWords(hit); + var url = ""; + + if (hit.anchor) { + url = hit.url_without_anchor + '?q=' + escape(words.join(" ")) + '#' + hit.anchor; + } else { + url = hit.url + '?q=' + escape(words.join(" ")); + } + + return url; +} diff --git a/docs/google2c2550f0be092f90.html b/docs/google2c2550f0be092f90.html new file mode 100644 index 0000000..ca604ab --- /dev/null +++ b/docs/google2c2550f0be092f90.html @@ -0,0 +1 @@ +google-site-verification: google2c2550f0be092f90.html \ No newline at end of file diff --git a/docs/index.html b/docs/index.html new file mode 100644 index 0000000..6a5ffe4 --- /dev/null +++ b/docs/index.html @@ -0,0 +1,277 @@ + + + + + + + +Get and Modify oTree Data • gmoTree + + + + + + + + + + + + +
    +
    + + + + +
    +
    + +
    + +

    R-CMD-check

    +

    gmoTree is an R package developed for importing, merging, and efficiently managing data obtained from running oTree (https://www.otree.org/) experiments. It’s particularly valuable when dealing with complex experimental designs that span multiple sessions and generate a large number of files that need to be integrated.

    +

    gmoTree is not an official package of the oTree team, but it was created to complement the open-source platform.

    +
    +

    About this version +

    +

    This is the beta version of the gmoTree package!

    +

    This package has been thoroughly tested, but since it is still in beta, it’s recommended to double-check the results when importing data. For example: Verify if the number of cases matches the numbers reported by the lab and ensure that the time results are reasonable. Please let me know if you encounter any errors or have suggestions for improvement.

    +

    The final package might differ from this package, so please keep track of the changes.

    +
    +
    +
    +

    Installation +

    +

    To install this package, use the following command:

    +

    devtools::install_github("ZauchnerP/gmoTree")

    +
    +
    +

    List of all functions +

    +

    See the page Introduction to gmoTree for a more detailed overview of the functions. Or see the website of gmoTree for more information on the package in general.

    +
    +

    Importing data +

    +
    +

    import_otree() +

    +

    Imports your oTree data and combines them in a list of data frames.

    +
    +
    +
    +

    Cleaning up data +

    +
    +

    messy_chat() +

    +

    Checks for a messy Chats data frame and combines variables that refer to the same concept.

    +
    +
    +

    messy_chat() +

    +

    Checks for a messy Time data frame and combines variables that refer to the same concept.

    +
    +
    +

    delete_duplicate() +

    +

    Deletes duplicate rows from all data frames in the oTree list.

    +
    +
    +
    +

    Dealing with dropouts and deleting cases +

    +
    +

    show_dropouts() +

    +

    Shows participant codes of people who did not finish at (a) certain app(s) or page(s).

    +
    +
    +

    delete_dropouts() +

    +

    Deletes the data of participants who did not finish at (a) certain app(s) or page(s). This function deletes the participants’ data from all data frames in the oTree list. Caution: It does not delete the cases from the original CSV and Excel files!

    +
    +
    +

    delete_cases() +

    +

    Deletes the data of specified participants from all data frames in the oTree list. Caution: This function does not delete the data from the original CSV and Excel files!

    +
    +
    +

    delete_sessions() +

    +

    Deletes the data of specified sessions from all data frames in the oTree list. Caution: This function does not delete the data from the original CSV and Excel files!

    +
    +
    +
    +

    Deleting sensitive information +

    +
    +

    delete_plabels() +

    +

    Deletes the variable participant.label from every app because it might contain identifiable information on the participants, such as their MTurk ID. Caution: This function does not delete the variable from the original CSV and Excel files!

    +
    +
    +
    +

    Making IDs +

    +
    +

    make_ids() +

    +

    Makes participant, group, and session IDs that are the same across all apps.

    +
    +
    +
    +

    Calculating the time +

    +
    +

    apptime() +

    +

    Calculates the time spent on a specific app.

    +
    +
    +

    extime() +

    +

    Calculates the time spent on the experiment.

    +
    +
    +

    pagesec() +

    +

    Calculates the time spent on each page.

    +
    +
    +
    +
    +

    Transferring variables between the apps +

    +
    +

    assignv() +

    +

    Copies a variable from the all_apps_wide data frame to the data frames of all other apps.

    +
    +
    +

    assignv_to_aaw() +

    +

    Copies a variable from one of your data frames to the all_apps_wide data frame.

    +
    +
    +
    +

    Before running the experiment +

    +
    +

    show_constant() +

    +

    Shows constant variables.

    +
    +
    + +
    + + +
    + + +
    + +
    +

    +

    Site built with pkgdown 2.0.7.

    +
    + +
    +
    + + + + + + + + diff --git a/docs/link.svg b/docs/link.svg new file mode 100644 index 0000000..88ad827 --- /dev/null +++ b/docs/link.svg @@ -0,0 +1,12 @@ + + + + + + diff --git a/docs/news/index.html b/docs/news/index.html new file mode 100644 index 0000000..7fcb34c --- /dev/null +++ b/docs/news/index.html @@ -0,0 +1,89 @@ + +Changelog • gmoTree + + +
    +
    + + + +
    +
    + + +
    + +
    • Beta version of gmoTree published (formerly known as “ioTree”)
    • +
    +
    + + + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/docs/pkgdown.css b/docs/pkgdown.css new file mode 100644 index 0000000..80ea5b8 --- /dev/null +++ b/docs/pkgdown.css @@ -0,0 +1,384 @@ +/* Sticky footer */ + +/** + * Basic idea: https://philipwalton.github.io/solved-by-flexbox/demos/sticky-footer/ + * Details: https://github.com/philipwalton/solved-by-flexbox/blob/master/assets/css/components/site.css + * + * .Site -> body > .container + * .Site-content -> body > .container .row + * .footer -> footer + * + * Key idea seems to be to ensure that .container and __all its parents__ + * have height set to 100% + * + */ + +html, body { + height: 100%; +} + +body { + position: relative; +} + +body > .container { + display: flex; + height: 100%; + flex-direction: column; +} + +body > .container .row { + flex: 1 0 auto; +} + +footer { + margin-top: 45px; + padding: 35px 0 36px; + border-top: 1px solid #e5e5e5; + color: #666; + display: flex; + flex-shrink: 0; +} +footer p { + margin-bottom: 0; +} +footer div { + flex: 1; +} +footer .pkgdown { + text-align: right; +} +footer p { + margin-bottom: 0; +} + +img.icon { + float: right; +} + +/* Ensure in-page images don't run outside their container */ +.contents img { + max-width: 100%; + height: auto; +} + +/* Fix bug in bootstrap (only seen in firefox) */ +summary { + display: list-item; +} + +/* Typographic tweaking ---------------------------------*/ + +.contents .page-header { + margin-top: calc(-60px + 1em); +} + +dd { + margin-left: 3em; +} + +/* Section anchors ---------------------------------*/ + +a.anchor { + display: none; + margin-left: 5px; + width: 20px; + height: 20px; + + background-image: url(./link.svg); + background-repeat: no-repeat; + background-size: 20px 20px; + background-position: center center; +} + +h1:hover .anchor, +h2:hover .anchor, +h3:hover .anchor, +h4:hover .anchor, +h5:hover .anchor, +h6:hover .anchor { + display: inline-block; +} + +/* Fixes for fixed navbar --------------------------*/ + +.contents h1, .contents h2, .contents h3, .contents h4 { + padding-top: 60px; + margin-top: -40px; +} + +/* Navbar submenu --------------------------*/ + +.dropdown-submenu { + position: relative; +} + +.dropdown-submenu>.dropdown-menu { + top: 0; + left: 100%; + margin-top: -6px; + margin-left: -1px; + border-radius: 0 6px 6px 6px; +} + +.dropdown-submenu:hover>.dropdown-menu { + display: block; +} + +.dropdown-submenu>a:after { + display: block; + content: " "; + float: right; + width: 0; + height: 0; + border-color: transparent; + border-style: solid; + border-width: 5px 0 5px 5px; + border-left-color: #cccccc; + margin-top: 5px; + margin-right: -10px; +} + +.dropdown-submenu:hover>a:after { + border-left-color: #ffffff; +} + +.dropdown-submenu.pull-left { + float: none; +} + +.dropdown-submenu.pull-left>.dropdown-menu { + left: -100%; + margin-left: 10px; + border-radius: 6px 0 6px 6px; +} + +/* Sidebar --------------------------*/ + +#pkgdown-sidebar { + margin-top: 30px; + position: -webkit-sticky; + position: sticky; + top: 70px; +} + +#pkgdown-sidebar h2 { + font-size: 1.5em; + margin-top: 1em; +} + +#pkgdown-sidebar h2:first-child { + margin-top: 0; +} + +#pkgdown-sidebar .list-unstyled li { + margin-bottom: 0.5em; +} + +/* bootstrap-toc tweaks ------------------------------------------------------*/ + +/* All levels of nav */ + +nav[data-toggle='toc'] .nav > li > a { + padding: 4px 20px 4px 6px; + font-size: 1.5rem; + font-weight: 400; + color: inherit; +} + +nav[data-toggle='toc'] .nav > li > a:hover, +nav[data-toggle='toc'] .nav > li > a:focus { + padding-left: 5px; + color: inherit; + border-left: 1px solid #878787; +} + +nav[data-toggle='toc'] .nav > .active > a, +nav[data-toggle='toc'] .nav > .active:hover > a, +nav[data-toggle='toc'] .nav > .active:focus > a { + padding-left: 5px; + font-size: 1.5rem; + font-weight: 400; + color: inherit; + border-left: 2px solid #878787; +} + +/* Nav: second level (shown on .active) */ + +nav[data-toggle='toc'] .nav .nav { + display: none; /* Hide by default, but at >768px, show it */ + padding-bottom: 10px; +} + +nav[data-toggle='toc'] .nav .nav > li > a { + padding-left: 16px; + font-size: 1.35rem; +} + +nav[data-toggle='toc'] .nav .nav > li > a:hover, +nav[data-toggle='toc'] .nav .nav > li > a:focus { + padding-left: 15px; +} + +nav[data-toggle='toc'] .nav .nav > .active > a, +nav[data-toggle='toc'] .nav .nav > .active:hover > a, +nav[data-toggle='toc'] .nav .nav > .active:focus > a { + padding-left: 15px; + font-weight: 500; + font-size: 1.35rem; +} + +/* orcid ------------------------------------------------------------------- */ + +.orcid { + font-size: 16px; + color: #A6CE39; + /* margins are required by official ORCID trademark and display guidelines */ + margin-left:4px; + margin-right:4px; + vertical-align: middle; +} + +/* Reference index & topics ----------------------------------------------- */ + +.ref-index th {font-weight: normal;} + +.ref-index td {vertical-align: top; min-width: 100px} +.ref-index .icon {width: 40px;} +.ref-index .alias {width: 40%;} +.ref-index-icons .alias {width: calc(40% - 40px);} +.ref-index .title {width: 60%;} + +.ref-arguments th {text-align: right; padding-right: 10px;} +.ref-arguments th, .ref-arguments td {vertical-align: top; min-width: 100px} +.ref-arguments .name {width: 20%;} +.ref-arguments .desc {width: 80%;} + +/* Nice scrolling for wide elements --------------------------------------- */ + +table { + display: block; + overflow: auto; +} + +/* Syntax highlighting ---------------------------------------------------- */ + +pre, code, pre code { + background-color: #f8f8f8; + color: #333; +} +pre, pre code { + white-space: pre-wrap; + word-break: break-all; + overflow-wrap: break-word; +} + +pre { + border: 1px solid #eee; +} + +pre .img, pre .r-plt { + margin: 5px 0; +} + +pre .img img, pre .r-plt img { + background-color: #fff; +} + +code a, pre a { + color: #375f84; +} + +a.sourceLine:hover { + text-decoration: none; +} + +.fl {color: #1514b5;} +.fu {color: #000000;} /* function */ +.ch,.st {color: #036a07;} /* string */ +.kw {color: #264D66;} /* keyword */ +.co {color: #888888;} /* comment */ + +.error {font-weight: bolder;} +.warning {font-weight: bolder;} + +/* Clipboard --------------------------*/ + +.hasCopyButton { + position: relative; +} + +.btn-copy-ex { + position: absolute; + right: 0; + top: 0; + visibility: hidden; +} + +.hasCopyButton:hover button.btn-copy-ex { + visibility: visible; +} + +/* headroom.js ------------------------ */ + +.headroom { + will-change: transform; + transition: transform 200ms linear; +} +.headroom--pinned { + transform: translateY(0%); +} +.headroom--unpinned { + transform: translateY(-100%); +} + +/* mark.js ----------------------------*/ + +mark { + background-color: rgba(255, 255, 51, 0.5); + border-bottom: 2px solid rgba(255, 153, 51, 0.3); + padding: 1px; +} + +/* vertical spacing after htmlwidgets */ +.html-widget { + margin-bottom: 10px; +} + +/* fontawesome ------------------------ */ + +.fab { + font-family: "Font Awesome 5 Brands" !important; +} + +/* don't display links in code chunks when printing */ +/* source: https://stackoverflow.com/a/10781533 */ +@media print { + code a:link:after, code a:visited:after { + content: ""; + } +} + +/* Section anchors --------------------------------- + Added in pandoc 2.11: https://github.com/jgm/pandoc-templates/commit/9904bf71 +*/ + +div.csl-bib-body { } +div.csl-entry { + clear: both; +} +.hanging-indent div.csl-entry { + margin-left:2em; + text-indent:-2em; +} +div.csl-left-margin { + min-width:2em; + float:left; +} +div.csl-right-inline { + margin-left:2em; + padding-left:1em; +} +div.csl-indent { + margin-left: 2em; +} diff --git a/docs/pkgdown.js b/docs/pkgdown.js new file mode 100644 index 0000000..6f0eee4 --- /dev/null +++ b/docs/pkgdown.js @@ -0,0 +1,108 @@ +/* http://gregfranko.com/blog/jquery-best-practices/ */ +(function($) { + $(function() { + + $('.navbar-fixed-top').headroom(); + + $('body').css('padding-top', $('.navbar').height() + 10); + $(window).resize(function(){ + $('body').css('padding-top', $('.navbar').height() + 10); + }); + + $('[data-toggle="tooltip"]').tooltip(); + + var cur_path = paths(location.pathname); + var links = $("#navbar ul li a"); + var max_length = -1; + var pos = -1; + for (var i = 0; i < links.length; i++) { + if (links[i].getAttribute("href") === "#") + continue; + // Ignore external links + if (links[i].host !== location.host) + continue; + + var nav_path = paths(links[i].pathname); + + var length = prefix_length(nav_path, cur_path); + if (length > max_length) { + max_length = length; + pos = i; + } + } + + // Add class to parent
  • , and enclosing
  • if in dropdown + if (pos >= 0) { + var menu_anchor = $(links[pos]); + menu_anchor.parent().addClass("active"); + menu_anchor.closest("li.dropdown").addClass("active"); + } + }); + + function paths(pathname) { + var pieces = pathname.split("/"); + pieces.shift(); // always starts with / + + var end = pieces[pieces.length - 1]; + if (end === "index.html" || end === "") + pieces.pop(); + return(pieces); + } + + // Returns -1 if not found + function prefix_length(needle, haystack) { + if (needle.length > haystack.length) + return(-1); + + // Special case for length-0 haystack, since for loop won't run + if (haystack.length === 0) { + return(needle.length === 0 ? 0 : -1); + } + + for (var i = 0; i < haystack.length; i++) { + if (needle[i] != haystack[i]) + return(i); + } + + return(haystack.length); + } + + /* Clipboard --------------------------*/ + + function changeTooltipMessage(element, msg) { + var tooltipOriginalTitle=element.getAttribute('data-original-title'); + element.setAttribute('data-original-title', msg); + $(element).tooltip('show'); + element.setAttribute('data-original-title', tooltipOriginalTitle); + } + + if(ClipboardJS.isSupported()) { + $(document).ready(function() { + var copyButton = ""; + + $("div.sourceCode").addClass("hasCopyButton"); + + // Insert copy buttons: + $(copyButton).prependTo(".hasCopyButton"); + + // Initialize tooltips: + $('.btn-copy-ex').tooltip({container: 'body'}); + + // Initialize clipboard: + var clipboardBtnCopies = new ClipboardJS('[data-clipboard-copy]', { + text: function(trigger) { + return trigger.parentNode.textContent.replace(/\n#>[^\n]*/g, ""); + } + }); + + clipboardBtnCopies.on('success', function(e) { + changeTooltipMessage(e.trigger, 'Copied!'); + e.clearSelection(); + }); + + clipboardBtnCopies.on('error', function() { + changeTooltipMessage(e.trigger,'Press Ctrl+C or Command+C to copy'); + }); + }); + } +})(window.jQuery || window.$) diff --git a/docs/pkgdown.yml b/docs/pkgdown.yml new file mode 100644 index 0000000..7afb254 --- /dev/null +++ b/docs/pkgdown.yml @@ -0,0 +1,10 @@ +pandoc: 2.19.2 +pkgdown: 2.0.7 +pkgdown_sha: ~ +articles: + intro_to_gmoTree: intro_to_gmoTree.html +last_built: 2023-08-24T16:50Z +urls: + reference: https://zauchnerp.github.io/gmoTree/reference + article: https://zauchnerp.github.io/gmoTree/articles + diff --git a/docs/reference/Rplot001.png b/docs/reference/Rplot001.png new file mode 100644 index 0000000..17a3580 Binary files /dev/null and b/docs/reference/Rplot001.png differ diff --git a/docs/reference/apptime.html b/docs/reference/apptime.html new file mode 100644 index 0000000..089dde4 --- /dev/null +++ b/docs/reference/apptime.html @@ -0,0 +1,251 @@ + +Calculate the time that was spent on an app — apptime • gmoTree + + +
    +
    + + + +
    +
    + + +
    +

    Calculate the time spent on one app or several apps.

    +
    + +
    +
    apptime(
    +  oTree,
    +  apps = NULL,
    +  pcode = NULL,
    +  plabel = NULL,
    +  group_id = NULL,
    +  seconds = FALSE,
    +  rounded = TRUE,
    +  digits = 2,
    +  sinfo = "session_code",
    +  combine = FALSE
    +)
    +
    + +
    +

    Arguments

    +
    oTree
    +

    A list of data frames that were created by import_otree().

    + + +
    apps
    +

    Name(s) of the app(s) for which the time +should be calculated.

    + + +
    pcode
    +

    Character. The value of the participant.code variable if the +time should only be calculated for one specified participant.

    + + +
    plabel
    +

    Character. The value of the participant.label variable if the +time should only be calculated for one specified participant.

    + + +
    group_id
    +

    Integer. The value of the group_id variable if the +time should only be calculated for one specified group. The group_id +variable can be created with make_ids().

    + + +
    seconds
    +

    Logical. +TRUE if the output should be in seconds instead of minutes.

    + + +
    rounded
    +

    Logical. +TRUE if the output should be rounded.

    + + +
    digits
    +

    Integer. +The number of digits to which the output should be rounded. +This parameter has no effect unless rounded = TRUE.

    + + +
    sinfo
    +

    Character. +"session_id" to use session ID for additional information in the data frame +of single durations, "session_code" to use session codes, or NULL if no +session column should be shown.

    + + +
    combine
    +

    Logical. +TRUE if all variables relating to epoch time should be merged, and +all variables relating to participant code should be merged +when data from multiple versions of oTree are used.

    + +
    +
    +

    Value

    + + +

    This function returns a list for each app containing +information on the mean, the minimum, and maximum time the participants +spent on the app, a data frame with information on the time +each participant spent on the app, and eventually, +vectors of background information on these numbers.

    + + +

    If the experiment's duration is only calculated for one participant, +the output returns an NA (per app) if the person did not make +it to the app(s).

    +
    + +
    +

    Examples

    +
    # Use package-internal list of oTree data frames
    +oTree <- gmoTree::oTree
    +
    +# Show how much time all participants spent on app "survey"
    +apptime(oTree, "survey")
    +#> $mean_duration
    +#> [1] 0.28
    +#> 
    +#> $min_duration
    +#> [1] 0.08
    +#> 
    +#> $max_duration
    +#> [1] 1.13
    +#> 
    +#> $single_durations
    +#>    participant  session duration
    +#> 1     46kxib6w 7bfqtokx     1.13
    +#> 2     iay3dhkn 7bfqtokx     0.22
    +#> 3     4zhzdmzo 7bfqtokx     0.15
    +#> 4     3ttf7yix 7bfqtokx     0.42
    +#> 5     2d72mfgh 7bfqtokx     0.13
    +#> 6     rvce7958 7bfqtokx     0.22
    +#> 7     lsl3vbij 7bfqtokx     0.13
    +#> 8     xx78b3x0 vd1h01iv     0.17
    +#> 9     xmxl46rm vd1h01iv     0.15
    +#> 10    iagvtslv t0rog7nz     0.15
    +#> 11    jxh15obl t0rog7nz     0.08
    +#> 12    a7dppel1 t0rog7nz     0.23
    +#> 13    wk247s9w t0rog7nz     0.73
    +#> 14    xkobdvuh t0rog7nz     0.40
    +#> 15    1l5kal0r t0rog7nz     0.13
    +#> 16    7l0hmpcq qyu3qg0q     0.15
    +#> 17    ia9rnfvc qyu3qg0q     0.15
    +#> 
    +#> $messages
    +#> [1] "For some participants, no duration could be calculated. See list in $warnings. Did they make it to the app(s)?"
    +#> 
    +#> $warnings
    +#> [1] "164r1hs4" "ktjz5jli" "vbhvhozv" "2scvem7a" "7wa8kk3d" "znri6myc" "ao9kqvqn"
    +#> [8] "d4sq7zio"
    +#> 
    +
    +# Show how much time the participant "y8rbzcju" spent on
    +# the app "survey"
    +apptime(oTree, pcode = "y8rbzcju", "survey")
    +#> [1] NA
    +
    +# Show how much time the participants in group 4 spent on
    +# the app "survey"
    +oTree <- make_ids(oTree, gmake = TRUE,
    +                  from_var = "dictator.1.group.id_in_subsession")
    +apptime(oTree, group_id = 4, apps = "survey")
    +#> $mean_duration
    +#> [1] 0.13
    +#> 
    +#> $min_duration
    +#> [1] 0.13
    +#> 
    +#> $max_duration
    +#> [1] 0.13
    +#> 
    +#> $single_durations
    +#>   participant  session duration
    +#> 1    lsl3vbij 7bfqtokx     0.13
    +#> 
    +#> $messages
    +#> [1] "For some participants, no duration could be calculated. See list in $warnings. Did they make it to the app(s)?"
    +#> 
    +#> $warnings
    +#> [1] "164r1hs4"
    +#> 
    +
    +
    +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/docs/reference/assignv.html b/docs/reference/assignv.html new file mode 100644 index 0000000..b07556a --- /dev/null +++ b/docs/reference/assignv.html @@ -0,0 +1,173 @@ + +Assign a variable from all_apps_wide — assignv • gmoTree + + +
    +
    + + + +
    +
    + + +
    +

    Assign a variable from all_apps_wide to the other app data frames.

    +
    + +
    +
    assignv(oTree, variable, newvar)
    +
    + +
    +

    Arguments

    +
    oTree
    +

    A list of data frames that were created by import_otree().

    + + +
    variable
    +

    Character. The variable in the all_apps_wide data frame that +should be assigned to all other apps.

    + + +
    newvar
    +

    Character. The name of the newly created variable.

    + +
    +
    +

    Value

    + + +

    This function returns a duplicate of the +original oTree list of data frames +but with an additional column in all data frames. The additional column +contains data from the specified variable found in all_apps_wide.

    +
    + +
    +

    Examples

    +
    # Use package-internal list of oTree data frames
    +oTree <- gmoTree::oTree
    +
    +# Assign variable "survey.1.player.gender" and name it "gender"
    +oTree <- assignv(oTree = oTree,
    +                 variable = "survey.1.player.gender",
    +                 newvar = "gender")
    +
    +# Show the new variable in some of the other app data frames
    +oTree$dictator$gender
    +#>  [1] "Male"   "Female" "Male"   "Female" "Female" "Male"   ""       "Male"  
    +#>  [9] ""       "Male"   "Female" "Male"   "Female" "Female" "Male"   ""      
    +#> [17] "Male"   ""       "Male"   "Female" "Male"   "Female" "Female" "Male"  
    +#> [25] ""       "Male"   ""       "Female" "Female" ""       ""       "Female"
    +#> [33] "Female" ""       ""       "Female" "Female" ""       ""       "Male"  
    +#> [41] ""       "Female" "Female" "Female" "Male"   "Male"   ""       "Female"
    +#> [49] "Female" "Female" "Male"   "Male"   ""       "Female" "Female" "Female"
    +#> [57] "Male"   ""       ""       ""       ""       ""       ""       ""      
    +#> [65] ""       ""       ""       ""       ""       "Female" "Female" "Female"
    +#> [73] "Female" "Female" "Female"
    +oTree$chatapp$gender
    +#>  [1] "Male"   "Female" "Male"   "Female" "Female" "Male"   ""       "Male"  
    +#>  [9] ""       "Female" "Female" ""       ""       "Male"   ""       "Female"
    +#> [17] "Female" "Female" "Male"   ""       ""       ""       ""       "Female"
    +#> [25] "Female"
    +
    +# The variable is now duplicated in app "survey" because it is obtained from
    +# there (This can be avoided by naming the new variable the same as the old
    +# variable)
    +oTree$survey$gender
    +#>  [1] "Male"   "Female" "Male"   "Female" "Female" "Male"   ""       "Male"  
    +#>  [9] ""       "Female" "Female" ""       ""       "Male"   ""       "Female"
    +#> [17] "Female" "Female" "Male"   ""       ""       ""       ""       "Female"
    +#> [25] "Female"
    +oTree$survey$player.gender
    +#>  [1] "Male"   "Female" "Male"   "Female" "Female" "Male"   ""       "Male"  
    +#>  [9] ""       "Female" "Female" ""       ""       "Male"   ""       "Female"
    +#> [17] "Female" "Female" "Male"   ""       ""       ""       ""       "Female"
    +#> [25] "Female"
    +
    +# In app "all_apps_wide," the variable is also there twice (This can be
    +# avoided by naming the new variable the same as the old variable)
    +oTree$all_apps_wide$gender
    +#>  [1] "Male"   "Female" "Male"   "Female" "Female" "Male"   ""       "Male"  
    +#>  [9] ""       "Female" "Female" ""       ""       "Male"   ""       "Female"
    +#> [17] "Female" "Female" "Male"   ""       ""       ""       ""       "Female"
    +#> [25] "Female" "Female" "Female" "Female" "Male"  
    +oTree$all_apps_wide$survey.1.player.gender
    +#>  [1] "Male"   "Female" "Male"   "Female" "Female" "Male"   ""       "Male"  
    +#>  [9] ""       "Female" "Female" ""       ""       "Male"   ""       "Female"
    +#> [17] "Female" "Female" "Male"   ""       ""       ""       ""       "Female"
    +#> [25] "Female" "Female" "Female" "Female" "Male"  
    +
    +
    +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/docs/reference/assignv_to_aaw.html b/docs/reference/assignv_to_aaw.html new file mode 100644 index 0000000..ecf684e --- /dev/null +++ b/docs/reference/assignv_to_aaw.html @@ -0,0 +1,170 @@ + +Assign a variable to all_apps_wide — assignv_to_aaw • gmoTree + + +
    +
    + + + +
    +
    + + +
    +

    Assign a variable from one of the app data frames to all_apps_wide.

    +
    + +
    +
    assignv_to_aaw(oTree, app, variable, newvar, resafter = NULL)
    +
    + +
    +

    Arguments

    +
    oTree
    +

    A list of data frames that were created by import_otree().

    + + +
    app
    +

    Character. The data frame from which the variable is taken.

    + + +
    variable
    +

    Character. +The name of the variable that should be assigned to all_apps_wide.

    + + +
    newvar
    +

    Character. +The name of the newly created variable in the all_apps_wide data frame.

    + + +
    resafter
    +

    Character. +The name of the variable that precedes the new variable. +If NULL, the new variable will be placed at the end of the data frame.

    + +
    +
    +

    Value

    + + +

    This function returns a duplicate of the original oTree list of +data frames but with an additional column in the all_apps_wide data frame +that contains the variable in question.

    +
    + +
    +

    Examples

    +
    # Use package-internal list of oTree data frames
    +oTree <- gmoTree::oTree
    +
    +# Create a new variable
    +oTree$survey$younger30 <- ifelse(oTree$survey$player.age < 30, 0, 1)
    +
    +# Assign the variable younger30 to all_apps_wide
    +oTree2 <- assignv_to_aaw(
    +  oTree = oTree,
    +  app = "survey",
    +  variable = "younger30",
    +  newvar = "younger30")
    +#> Warning: New variable is created. However, there is an unequal number of participants in "all_apps_wide" (29) and app "survey" (25). Did you forget to delete dropouts and empty cases or did you forget to import app data? Sometimes, this can happen if you import data from within a session or room where you can only import "all_apps_wide" but not the separate app data, time data or chat data.
    +
    +# Show the new variable in the all_apps_wide data frame
    +oTree2$all_apps_wide$younger30
    +#>  [1]  0  0  0  0  1  1 NA  1 NA  1  0 NA NA  0 NA  1  0  0  0 NA NA NA NA  1  0
    +#> [26] NA NA NA NA
    +
    +# Check the position of the new variable
    +match("younger30",names(oTree2$all_apps_wide))
    +#> [1] 56
    +
    +# Place the new variable immediately after the "survey.1.player.age" variable
    +oTree2 <- assignv_to_aaw(oTree,
    +                        app = "survey",
    +                        variable = "younger30",
    +                        newvar = "younger30",
    +                        resafter = "survey.1.player.age")
    +#> Warning: New variable is created. However, there is an unequal number of participants in "all_apps_wide" (29) and app "survey" (25). Did you forget to delete dropouts and empty cases or did you forget to import app data? Sometimes, this can happen if you import data from within a session or room where you can only import "all_apps_wide" but not the separate app data, time data or chat data.
    +
    +# Show the new variable in the all_apps_wide data frame
    +oTree2$all_apps_wide$younger30
    +#>  [1]  0  0  0  0  1  1 NA  1 NA  1  0 NA NA  0 NA  1  0  0  0 NA NA NA NA  1  0
    +#> [26] NA NA NA NA
    +
    +# Show the position of the new variable
    +match("younger30", names(oTree2$all_apps_wide))
    +#> [1] 50
    +
    +
    +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/docs/reference/delete_cases.html b/docs/reference/delete_cases.html new file mode 100644 index 0000000..ef2a417 --- /dev/null +++ b/docs/reference/delete_cases.html @@ -0,0 +1,259 @@ + +Delete specific cases — delete_cases • gmoTree + + +
    +
    + + + +
    +
    + + +
    +

    Delete specific cases from all data frames in the oTree list.

    +

    Caution 1: This function does not delete cases from the original +CSV and Excel files!

    +

    Caution 2: This function does not delete cases from custom exports +and custom data frames if these data frames do not have a variable +named participant.code!

    +

    Caution 3: This function does not delete any data from the Chats data frame! +(As the interpretation of chat data depends on how participants +engage with each other, the data must be deleted +with more care than deleting data in other apps. +Hence, this function does not delete data in this data frame. +Please do this manually if necessary!)

    +
    + +
    +
    delete_cases(
    +  oTree,
    +  pcodes = NULL,
    +  plabels = NULL,
    +  saved_vars = NULL,
    +  reason,
    +  omit = FALSE,
    +  info = FALSE
    +)
    +
    + +
    +

    Arguments

    +
    oTree
    +

    A list of data frames that were created by import_otree().

    + + +
    pcodes
    +

    Character. The value(s) of the participant.code variable of +the participants whose data should be removed.

    + + +
    plabels
    +

    Character. The value(s) of the participant.label variable of +the participants whose data should be removed.

    + + +
    saved_vars
    +

    Character. The name(s) of variable(s) that need(s) to be +stored in the list of information on deleted cases in $info$deleted_cases.

    + + +
    reason
    +

    Character. The reason for deletion that should be stored in +the list of information on deleted cases in $info$deleted_cases.

    + + +
    omit
    +

    Logical. TRUE if the deleted cases should not be added to +the information on deleted cases in $info$deleted_cases.

    + + +
    info
    +

    Logical. TRUE if a brief information on the case deletion +process should be printed.

    + +
    +
    +

    Value

    + + +

    This function returns a duplicate of the original oTree list +of data frames that do not include the deleted cases.

    + + +

    It adds information on the deleted cases to $info$deleted_cases. (This +list is also filled by other functions.)

    + + +

    In this list, you can find the following information:

    + + +

    $codes = A vector with the participant codes of all deleted cases.

    + + +

    $count = The number of participants in $codes.

    + + +

    $full and $unique = The data frames $full and $unique contain information +on each deleted participant and the reason why they were +deleted. The entries to the $full and the $unique data frames are the same. +Columns "end_app" and "end_page" are left empty intentionally +because they are only filled by the delete_dropouts() function.

    +
    + +
    +

    Examples

    +
    # Use package-internal list of oTree data frames
    +oTree <- gmoTree::oTree
    +
    +# First, show some row numbers
    +print(paste(nrow(oTree$all_apps_wide), nrow(oTree$survey),
    +nrow(oTree$Time), nrow(oTree$Chats)))
    +#> [1] "29 25 289 35"
    +
    +# Delete only one case
    +oTree2 <- delete_cases(oTree,
    +                       pcodes = "xmxl46rm",
    +                       reason = "requested")
    +
    +# Show row numbers again
    +print(paste(nrow(oTree2$all_apps_wide), nrow(oTree2$survey),
    +nrow(oTree2$Time), nrow(oTree2$Chats)))
    +#> [1] "28 24 275 35"
    +
    +# Delete several cases
    +deletionlist <- c("4zhzdmzo", "xmxl46rm")
    +oTree2 <- delete_cases(oTree,
    +                       pcodes = deletionlist,
    +                       reason = "requested")
    +
    +# Show row numbers again
    +print(paste(nrow(oTree2$all_apps_wide), nrow(oTree2$survey),
    +nrow(oTree2$Time), nrow(oTree2$Chats)))
    +#> [1] "27 23 258 35"
    +
    +# Show information on all deleted cases (also dropouts):
    +oTree2$info$deleted_cases$full
    +#>    participant.code  session end_app end_page    reason
    +#> 3          4zhzdmzo 7bfqtokx                  requested
    +#> 12         xmxl46rm vd1h01iv                  requested
    +
    +# Save one variable
    +oTree2 <- delete_cases(oTree,
    +  pcodes = deletionlist,
    +  reason = "requested",
    +  saved_vars = "participant._index_in_pages")
    +
    +# Show row numbers again
    +print(paste(nrow(oTree2$all_apps_wide), nrow(oTree2$survey),
    +nrow(oTree2$Time), nrow(oTree2$Chats)))
    +#> [1] "27 23 258 35"
    +
    +# Save some variables
    +oTree2 <- delete_cases(oTree,
    +  pcodes = deletionlist,
    +  reason = "requested",
    +  saved_vars = c(
    +    "participant._index_in_pages",
    +    "participant._max_page_index"))
    +
    +# Show row numbers again
    +print(paste(nrow(oTree2$all_apps_wide), nrow(oTree2$survey),
    +nrow(oTree2$Time), nrow(oTree2$Chats)))
    +#> [1] "27 23 258 35"
    +
    +# Get a list of all deleted cases
    +# (If there is already a list, the new list is added to it)
    +oTree2$info$deleted_cases$codes
    +#> [1] "4zhzdmzo" "xmxl46rm"
    +
    +# Show number of all deleted cases
    +length(oTree2$info$deleted_cases$codes)
    +#> [1] 2
    +oTree2$info$deleted_cases$count
    +#> [1] 2
    +
    +
    +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/docs/reference/delete_dropouts.html b/docs/reference/delete_dropouts.html new file mode 100644 index 0000000..a86f4b1 --- /dev/null +++ b/docs/reference/delete_dropouts.html @@ -0,0 +1,365 @@ + +Delete dropouts — delete_dropouts • gmoTree + + +
    +
    + + + +
    +
    + + +
    +

    Delete the data of all participants who did not end the experiment at (a) +certain page(s) and/or app(s).

    +

    Caution 1: This function does not delete cases from the original CSV and +Excel files!

    +

    Caution 2: This function does not delete cases from custom exports if the +custom exports do not have a variable named participant.code and a variable +named session.code!

    +

    Caution 3: This function does not delete any data from the Chats data frame! +(As the interpretation of chat data depends on how participants engage with +each other, the data must be deleted with more care than deleting data in +other apps. Hence, this function does not delete data in this data frame. +Please do this manually if necessary!)

    +
    + +
    +
    delete_dropouts(
    +  oTree,
    +  final_apps = NULL,
    +  final_pages = NULL,
    +  saved_vars = NULL,
    +  inconsistent = NULL,
    +  reason = "ENC",
    +  info = FALSE
    +)
    +
    + +
    +

    Arguments

    +
    oTree
    +

    A list of data frames that were created by import_otree().

    + + +
    final_apps
    +

    Character. +The name(s) of the app(s) at which the participants have to finish the +experiment.

    + + +
    final_pages
    +

    Character. +The name(s) of the page(s) at which the participants have to finish the +experiment.

    + + +
    saved_vars
    +

    Character. The name(s) of variable(s) that need(s) to be +stored in the list of information on deleted cases in $info$deleted_cases.

    + + +
    inconsistent
    +

    Character. Should the function continue or be stopped if +at least one participant has inconsistent end_pages, inconsistent end_apps, +or both? To continue, type "yes," +to stop the function, type "no."

    + + +
    reason
    +

    Character. The reason for deletion that should be stored in +the list of information on deleted cases in $info$deleted_cases.

    + + +
    info
    +

    Logical. TRUE if a brief information on the dropout deletion +process should be printed.

    + +
    +
    +

    Value

    + + +

    This function returns a duplicate of the original oTree list of data frames +but without the deleted cases.

    + + +

    It adds information on the deleted cases to $info$deleted_cases. (This +list is also filled by other functions.)

    + + +

    In this list, you can find the following information:

    + + +

    $full = A data frame that contains information +on all participants who did not finish the study; +it shows their participant codes, the names of the apps in which they +left the experiment, +the names of the pages in which they left the experiment, +the names of the app data frames in which this information was found, and +the dropout reason ("ENC," experiment not completed, combined +with the name of the data frame in which the dropout was observed). +Because participants usually appear in multiple app data frames, +the $info$deleted_cases$full data frame may contain several entries for +each person.

    + + +

    $unique = A data frame that contains similar information as the $full data +frame but with only one row per participant and no information on the data +frame in which the dropout was observed.

    + + +

    $all_end = A table that provides information on the app and page combinations +where participants ended the experiment. This table also includes +information for participants who did not drop out of the experiment. +The $all_end table is only shown if an all_apps_wide data frame exists.

    + + +

    $codes = A vector containing the participant codes of +all deleted participants.

    + + +

    $count = The number of all deleted participants.

    + + +

    It is important to note that if only the argument final_pages is set, +this function does not distinguish between page names that reoccur in +different apps.

    + + +

    If the columns end_app and end_page in the output are empty, +these variables were not saved by oTree for the specific participants. +This could be because empty rows were not deleted. This can be done +by using the argument "del_empty = TRUE" when using import_otree().

    +
    + +
    +

    Examples

    +
    # Use package-internal list of oTree data frames
    +oTree <- gmoTree::oTree
    +
    +# First, show some row numbers
    +print(paste(nrow(oTree$all_apps_wide), nrow(oTree$survey),
    +nrow(oTree$Time), nrow(oTree$Chats)))
    +#> [1] "29 25 289 35"
    +
    +# Delete all cases that didn't end the experiment on the page "Demographics"
    +# within the app "survey"
    +oTree2 <- delete_dropouts(oTree,
    +                         final_apps = c("survey"),
    +                         final_pages = c("Demographics"))
    +
    +# Show row numbers again
    +print(paste(nrow(oTree2$all_apps_wide), nrow(oTree2$survey),
    +nrow(oTree2$Time), nrow(oTree2$Chats)))
    +#> [1] "20 16 248 35"
    +
    +# Delete all cases that didn't end the experiment on the page "Demographics"
    +# This page can be in any app
    +oTree2 <- delete_dropouts(oTree, final_pages = "Demographics")
    +
    +# Show row numbers again
    +print(paste(nrow(oTree2$all_apps_wide), nrow(oTree2$survey),
    +nrow(oTree2$Time), nrow(oTree2$Chats)))
    +#> [1] "20 16 248 35"
    +
    +# Delete all cases that didn't end the experiment on
    +# any page in the app "survey"
    +oTree <- delete_dropouts(oTree, final_apps = "survey")
    +
    +# Show row numbers again
    +print(paste(nrow(oTree2$all_apps_wide), nrow(oTree2$survey),
    +nrow(oTree2$Time), nrow(oTree2$Chats)))
    +#> [1] "20 16 248 35"
    +
    +# Get list of information on all deleted cases
    +# (If there is already a list, the new list is added to it!)
    +oTree2$info$deleted_cases
    +#> $full
    +#>    participant.code session.code  end_app        end_page
    +#> 1          164r1hs4     7bfqtokx  chatapp            chat
    +#> 2          164r1hs4     7bfqtokx  chatapp            chat
    +#> 3          164r1hs4     7bfqtokx  chatapp            chat
    +#> 4          164r1hs4     7bfqtokx  chatapp            chat
    +#> 5          2scvem7a     vd1h01iv dictator ResultsWaitPage
    +#> 6          2scvem7a     vd1h01iv dictator ResultsWaitPage
    +#> 7          2scvem7a     vd1h01iv dictator ResultsWaitPage
    +#> 8          2scvem7a     vd1h01iv dictator ResultsWaitPage
    +#> 9          7wa8kk3d     l8ecm1uh dictator    Introduction
    +#> 10         7wa8kk3d     l8ecm1uh dictator    Introduction
    +#> 11         7wa8kk3d     l8ecm1uh dictator    Introduction
    +#> 12         7wa8kk3d     l8ecm1uh dictator    Introduction
    +#> 13         ao9kqvqn     l8ecm1uh dictator    Introduction
    +#> 14         ao9kqvqn     l8ecm1uh dictator    Introduction
    +#> 15         ao9kqvqn     l8ecm1uh dictator    Introduction
    +#> 16         ao9kqvqn     l8ecm1uh dictator    Introduction
    +#> 17         d4sq7zio     l8ecm1uh dictator    Introduction
    +#> 18         d4sq7zio     l8ecm1uh dictator    Introduction
    +#> 19         d4sq7zio     l8ecm1uh dictator    Introduction
    +#> 20         d4sq7zio     l8ecm1uh dictator    Introduction
    +#> 21         jxh15obl     t0rog7nz   survey           Offer
    +#> 22         jxh15obl     t0rog7nz   survey           Offer
    +#> 23         jxh15obl     t0rog7nz   survey           Offer
    +#> 24         jxh15obl     t0rog7nz   survey           Offer
    +#> 25         ktjz5jli     7bfqtokx dictator ResultsWaitPage
    +#> 26         ktjz5jli     7bfqtokx dictator ResultsWaitPage
    +#> 27         ktjz5jli     7bfqtokx dictator ResultsWaitPage
    +#> 28         ktjz5jli     7bfqtokx dictator ResultsWaitPage
    +#> 29         vbhvhozv     vd1h01iv dictator ResultsWaitPage
    +#> 30         vbhvhozv     vd1h01iv dictator ResultsWaitPage
    +#> 31         vbhvhozv     vd1h01iv dictator ResultsWaitPage
    +#> 32         vbhvhozv     vd1h01iv dictator ResultsWaitPage
    +#> 33         znri6myc     l8ecm1uh dictator    Introduction
    +#> 34         znri6myc     l8ecm1uh dictator    Introduction
    +#> 35         znri6myc     l8ecm1uh dictator    Introduction
    +#> 36         znri6myc     l8ecm1uh dictator    Introduction
    +#>                            reason
    +#> 1         ENC. Noticed at: survey
    +#> 2  ENC. Noticed at: all_apps_wide
    +#> 3        ENC. Noticed at: chatapp
    +#> 4       ENC. Noticed at: dictator
    +#> 5  ENC. Noticed at: all_apps_wide
    +#> 6        ENC. Noticed at: chatapp
    +#> 7       ENC. Noticed at: dictator
    +#> 8         ENC. Noticed at: survey
    +#> 9  ENC. Noticed at: all_apps_wide
    +#> 10       ENC. Noticed at: chatapp
    +#> 11      ENC. Noticed at: dictator
    +#> 12        ENC. Noticed at: survey
    +#> 13 ENC. Noticed at: all_apps_wide
    +#> 14       ENC. Noticed at: chatapp
    +#> 15      ENC. Noticed at: dictator
    +#> 16        ENC. Noticed at: survey
    +#> 17       ENC. Noticed at: chatapp
    +#> 18      ENC. Noticed at: dictator
    +#> 19        ENC. Noticed at: survey
    +#> 20 ENC. Noticed at: all_apps_wide
    +#> 21      ENC. Noticed at: dictator
    +#> 22        ENC. Noticed at: survey
    +#> 23 ENC. Noticed at: all_apps_wide
    +#> 24       ENC. Noticed at: chatapp
    +#> 25 ENC. Noticed at: all_apps_wide
    +#> 26       ENC. Noticed at: chatapp
    +#> 27      ENC. Noticed at: dictator
    +#> 28        ENC. Noticed at: survey
    +#> 29 ENC. Noticed at: all_apps_wide
    +#> 30       ENC. Noticed at: chatapp
    +#> 31      ENC. Noticed at: dictator
    +#> 32        ENC. Noticed at: survey
    +#> 33 ENC. Noticed at: all_apps_wide
    +#> 34       ENC. Noticed at: chatapp
    +#> 35      ENC. Noticed at: dictator
    +#> 36        ENC. Noticed at: survey
    +#> 
    +#> $unique
    +#>    participant.code session.code  end_app        end_page reason
    +#> 1          164r1hs4     7bfqtokx  chatapp            chat    ENC
    +#> 5          2scvem7a     vd1h01iv dictator ResultsWaitPage    ENC
    +#> 9          7wa8kk3d     l8ecm1uh dictator    Introduction    ENC
    +#> 13         ao9kqvqn     l8ecm1uh dictator    Introduction    ENC
    +#> 17         d4sq7zio     l8ecm1uh dictator    Introduction    ENC
    +#> 21         jxh15obl     t0rog7nz   survey           Offer    ENC
    +#> 25         ktjz5jli     7bfqtokx dictator ResultsWaitPage    ENC
    +#> 29         vbhvhozv     vd1h01iv dictator ResultsWaitPage    ENC
    +#> 33         znri6myc     l8ecm1uh dictator    Introduction    ENC
    +#> 
    +#> $all_end
    +#>           
    +#>            Demographics Introduction Offer ResultsWaitPage chat
    +#>   chatapp             0            0     0               0    1
    +#>   dictator            0            4     0               3    0
    +#>   survey             20            0     1               0    0
    +#> 
    +#> $codes
    +#> [1] "164r1hs4" "2scvem7a" "7wa8kk3d" "ao9kqvqn" "d4sq7zio" "jxh15obl" "ktjz5jli"
    +#> [8] "vbhvhozv" "znri6myc"
    +#> 
    +#> $count
    +#> [1] 9
    +#> 
    +
    +
    +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/docs/reference/delete_duplicate.html b/docs/reference/delete_duplicate.html new file mode 100644 index 0000000..4fd32cf --- /dev/null +++ b/docs/reference/delete_duplicate.html @@ -0,0 +1,141 @@ + +Delete duplicate data — delete_duplicate • gmoTree + + +
    +
    + + + +
    +
    + + +
    +

    Delete duplicate rows from all oTree app data frames and all_apps_wide.

    +
    + +
    +
    delete_duplicate(oTree)
    +
    + +
    +

    Arguments

    +
    oTree
    +

    A list of data frames that were created by import_otree().

    + +
    +
    +

    Value

    + + +

    This function returns a duplicate of the original oTree +list of data frames but without duplicate rows in all app data +frames and all_apps_wide. This function has no effect on the data +frames Time and Chats.

    + + +

    This function does NOT add information to $info$deleted_cases, +because it does not delete any important information but only +cleans up a messy data import.

    + + +

    However, the function adjusts info$initial_n, if an all_apps_wide +data frame exists.

    +
    + +
    +

    Examples

    +
    # Set data folder first
    +withr::with_dir(system.file("extdata", package = "gmoTree"), {
    +
    +# Import all oTree files in this folder and its subfolders
    +oTree <- import_otree()
    +})
    +#> Warning: You have stored all_apps_wide globally but also room-specific. This function will import both of them. (Globally, the files are saved as "all_apps_wide_." Room-specific, the files are saved as "All apps - wide-" or "all_apps_wide-.") After importing the data, make sure nothing is there twice! (Advice: You may use delete_duplicate() to remove duplicate rows of all oTree data frames.
    +
    +# First, show some row numbers
    +print(paste(nrow(oTree$all_apps_wide), nrow(oTree$survey),
    +nrow(oTree$Time), nrow(oTree$Chats)))
    +#> [1] "104 88 878 95"
    +
    +# Delete duplicate rows
    +oTree <- delete_duplicate(oTree)
    +
    +# Show row numbers again
    +print(paste(nrow(oTree$all_apps_wide), nrow(oTree$survey),
    +nrow(oTree$Time), nrow(oTree$Chats)))
    +#> [1] "59 55 878 95"
    +
    +
    +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/docs/reference/delete_plabels.html b/docs/reference/delete_plabels.html new file mode 100644 index 0000000..b057eb2 --- /dev/null +++ b/docs/reference/delete_plabels.html @@ -0,0 +1,154 @@ + +Delete participant labels in all apps — delete_plabels • gmoTree + + +
    +
    + + + +
    +
    + + +
    +

    If you work with MTurk, the MTurk IDs will be stored in the +participant labels variable. +This function deletes this variable in all_apps_wide and every app data frame +in the list of data frames that was created by import_otree() and/or all +variables referring to MTurk, such as participant.mturk_worker_id.

    +
    + +
    +
    delete_plabels(oTree, del_plabel = TRUE, del_mturk = TRUE)
    +
    + +
    +

    Arguments

    +
    oTree
    +

    A list of data frames that were created by import_otree().

    + + +
    del_plabel
    +

    Logical. +TRUE if all participant labels should be deleted.

    + + +
    del_mturk
    +

    Logical. +TRUE if all MTurk variables should be deleted.

    + +
    +
    +

    Value

    + + +

    This function returns a duplicate of the original oTree list of +data frames that do not include the participant labels and/or the MTurk +variables.

    +
    + +
    +

    Examples

    +
    # Use package-internal list of oTree data frames
    +oTree <- gmoTree::oTree
    +
    +# Show participant labels
    +oTree$all_apps_wide$participant.label
    +#>  [1] "Person1"  "Person2"  "Person4"  "Person5"  "Person6"  "Person7" 
    +#>  [7] "Person8"  "Person9"  "Person10" "Person1"  "Person2"  "Person3" 
    +#> [13] "Person4"  "Person1"  "Person2"  "Person3"  "Person4"  "Person5" 
    +#> [19] "Person6"  "Person1"  "Person2"  "Person3"  "Person4"  "Person2" 
    +#> [25] "Person3"  NA         NA         NA         NA        
    +oTree$survey$participant.label
    +#>  [1] "Person1"  "Person2"  "Person4"  "Person5"  "Person6"  "Person7" 
    +#>  [7] "Person8"  "Person9"  "Person10" "Person1"  "Person2"  "Person3" 
    +#> [13] "Person4"  "Person1"  "Person2"  "Person3"  "Person4"  "Person5" 
    +#> [19] "Person6"  "Person1"  "Person2"  "Person3"  "Person4"  "Person2" 
    +#> [25] "Person3" 
    +
    +# Delete all participant labels
    +oTree2 <- delete_plabels(oTree)
    +
    +# Show participant labels again
    +oTree2$all_apps_wide$participant.label
    +#> NULL
    +oTree2$survey$participant.label
    +#> NULL
    +
    +
    +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/docs/reference/delete_sessions.html b/docs/reference/delete_sessions.html new file mode 100644 index 0000000..77a8f1d --- /dev/null +++ b/docs/reference/delete_sessions.html @@ -0,0 +1,191 @@ + +Delete all cases of one session — delete_sessions • gmoTree + + +
    +
    + + + +
    +
    + + +
    +

    Delete cases from specific sessions in all data frames in the +oTree list of data frames.

    +

    Caution 1: This function does not delete cases from the +original CSV and Excel files!

    +

    Caution 2: This function does not delete cases from custom exports if the +custom exports do not have a variable named participant.code and a variable +named session.code!

    +
    + +
    +
    delete_sessions(oTree, scodes, saved_vars = NULL, reason, info = FALSE)
    +
    + +
    +

    Arguments

    +
    oTree
    +

    A list of data frames that were created by import_otree().

    + + +
    scodes
    +

    Character. The session.code(s) of the +session(s) whose data should be removed.

    + + +
    saved_vars
    +

    Character. The name(s) of variable(s) that need(s) to be +stored in the list of information on deleted cases in $info$deleted_cases.

    + + +
    reason
    +

    Character. The reason for deletion that should be stored in +the list of information on deleted cases in $info$deleted_cases.

    + + +
    info
    +

    Logical. TRUE if a brief information on the session +deletion process should be printed.

    + +
    +
    +

    Value

    + + +

    This function returns a duplicate of the original oTree list of +data frames that do not include the deleted sessions.

    + + +

    It adds information on the deleted cases to $info$deleted_cases. (This +list is also filled by other functions.)

    + + +

    In this list, you can find the following information:

    + + +

    $full and $unique = The data frames $full and $unique contain +information on all participants +whose data were deleted. The entries to the $full and the $unique data +frames in this list are the same. Columns "end_app" and "end_page" are left +empty intentionally because they are only filled by the delete_dropouts() +function. Columns "participant.code" and "reason" are filled.

    + + +

    $codes = A vector containing the participant codes of +all deleted participants.

    + + +

    $count = The number of all deleted participants.

    +
    + +
    +

    Examples

    +
    # Use package-internal list of oTree data frames
    +oTree <- gmoTree::oTree
    +
    +# First, show some row numbers
    +print(paste(nrow(oTree$all_apps_wide), nrow(oTree$survey),
    +nrow(oTree$Time), nrow(oTree$Chats)))
    +#> [1] "29 25 289 35"
    +
    +# Delete one session
    +oTree2 <- delete_sessions(oTree,
    +  scodes = "7bfqtokx",
    +  reason = "Only tests")
    +
    +# Show row numbers
    +print(paste(nrow(oTree2$all_apps_wide), nrow(oTree2$survey),
    +nrow(oTree2$Time), nrow(oTree2$Chats)))
    +#> [1] "20 16 166 14"
    +
    +# Delete two sessions
    +oTree2 <- delete_sessions(oTree,
    +  scodes = c("7bfqtokx", "vd1h01iv"),
    +  reason = "Only tests")
    +
    +# Show row numbers again
    +print(paste(nrow(oTree2$all_apps_wide), nrow(oTree2$survey),
    +nrow(oTree2$Time), nrow(oTree2$Chats)))
    +#> [1] "16 12 126 10"
    +
    +
    +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/docs/reference/extime.html b/docs/reference/extime.html new file mode 100644 index 0000000..bf29549 --- /dev/null +++ b/docs/reference/extime.html @@ -0,0 +1,256 @@ + +Calculate the time that was spent on the whole experiment — extime • gmoTree + + +
    +
    + + + +
    +
    + + +
    +

    Calculate the time spent on the experiment. +If not stated otherwise, the calculation only starts at the end of +the first page!

    +
    + +
    +
    extime(
    +  oTree,
    +  pcode = NULL,
    +  plabel = NULL,
    +  group_id = NULL,
    +  seconds = FALSE,
    +  rounded = TRUE,
    +  digits = 2,
    +  startat = 1,
    +  tz = "UTC",
    +  sinfo = "session_code",
    +  combine = TRUE
    +)
    +
    + +
    +

    Arguments

    +
    oTree
    +

    A list of data frames that were created by import_otree().

    + + +
    pcode
    +

    Character. The value of the participant.code variable if the +time should only be calculated for one specified participant.

    + + +
    plabel
    +

    Character. The value of the participant.label variable if the +time should only be calculated for one specified participant.

    + + +
    group_id
    +

    Integer. The value of the group_id variable if the +time should only be calculated for one specified group. The group_id +variable can be created with make_ids().

    + + +
    seconds
    +

    Logical. +TRUE if the output should be in seconds instead of minutes.

    + + +
    rounded
    +

    Logical. TRUE if the output should be rounded.

    + + +
    digits
    +

    Integer. The number of digits to which the output +should be rounded. +This parameter has no effect unless rounded = TRUE.

    + + +
    startat
    +

    Integer or character string "real". +Whether the start of the experiment should be taken from the time at +a certain index of each person's vector of page_indexes in the +Time data frame or from the "time_started" +variable in all_apps_wide ("real"). Important: If integer, +it represents the position within the page index sequence, +not the numeric value of the index.

    + + +
    tz
    +

    Character. Time zone.

    + + +
    sinfo
    +

    Character. +"session_id" to use session ID for additional information in the data frame +of single durations, "session_code" to use session codes, or NULL if no +session column should be shown.

    + + +
    combine
    +

    Logical. TRUE if all variables referring to epoch time should +be merged, and all variables referring to participant code should +be merged in case data of several versions of oTree are used. If FALSE, +the function returns an error if several oTree versions' data are present.

    + +
    +
    +

    Value

    + + +

    This function returns either a single value if only the data of one person +is calculated or a list of information on the time several participants +spent on the experiment.

    + + +

    In this list, you can find the following information:

    + + +

    $mean_duration = The experiment's average duration.

    + + +

    $min_duration = The experiment's minimum duration.

    + + +

    $max_duration = The experiment's maximum duration.

    + + +

    $single_durations = A data frame of all durations that +are used for calculating the min, max, and mean duration.

    + + +

    $messages = All important notes to the calculations.

    + + +

    $only_one_page = A vector of all individuals who only have one time stamp.

    +
    + +
    +

    Examples

    +
    # Use package-internal list of oTree data frames
    +oTree <- gmoTree::oTree
    +
    +# Make a data frame of durations
    +extime(oTree)
    +#> $mean_duration
    +#> [1] 2.81
    +#> 
    +#> $min_duration
    +#> [1] 0.4
    +#> 
    +#> $max_duration
    +#> [1] 6.93
    +#> 
    +#> $single_durations
    +#>    participant  session duration
    +#> 12    vbhvhozv vd1h01iv     0.40
    +#> 13    2scvem7a vd1h01iv     0.43
    +#> 20    7l0hmpcq qyu3qg0q     0.78
    +#> 10    xx78b3x0 vd1h01iv     1.08
    +#> 21    ia9rnfvc qyu3qg0q     1.20
    +#> 11    xmxl46rm vd1h01iv     1.25
    +#> 15    jxh15obl t0rog7nz     1.73
    +#> 16    a7dppel1 t0rog7nz     1.98
    +#> 19    1l5kal0r t0rog7nz     2.18
    +#> 1     46kxib6w 7bfqtokx     2.32
    +#> 18    xkobdvuh t0rog7nz     2.37
    +#> 17    wk247s9w t0rog7nz     2.50
    +#> 2     iay3dhkn 7bfqtokx     2.55
    +#> 14    iagvtslv t0rog7nz     2.82
    +#> 9     ktjz5jli 7bfqtokx     2.88
    +#> 7     164r1hs4 7bfqtokx     3.53
    +#> 8     lsl3vbij 7bfqtokx     4.18
    +#> 5     2d72mfgh 7bfqtokx     5.38
    +#> 6     rvce7958 7bfqtokx     5.67
    +#> 3     4zhzdmzo 7bfqtokx     6.78
    +#> 4     3ttf7yix 7bfqtokx     6.93
    +#> 
    +#> $messages
    +#> [1] "Warning: For at least one participant, the experiment only has one page. I.e., the indices for the first and the last page are the same. See $only_one_page for information on this participant/these participants! Participants in this list are not included in the output."
    +#> 
    +#> $only_one_page
    +#> [1] "7wa8kk3d" "znri6myc" "ao9kqvqn" "d4sq7zio"
    +#> 
    +
    +# Show time for one participant
    +extime(oTree, pcode = "wk247s9w")
    +#> [1] 2.5
    +
    +
    +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/docs/reference/import_otree.html b/docs/reference/import_otree.html new file mode 100644 index 0000000..0f1c20a --- /dev/null +++ b/docs/reference/import_otree.html @@ -0,0 +1,361 @@ + +Import oTree data — import_otree • gmoTree + + +
    +
    + + + +
    +
    + + +
    +

    Import data files that were created by oTree. +All files containing the pattern YYYY-MM-DD at the end +of their file names are considered oTree files. +Bot outputs are saved by oTree without the date included. Hence, to +import bot data, you must either rename the original bot files +using the YYYY-MM-DD format or use the argument "onlybots = TRUE." +By using the second option, only data of bot files are imported.

    +

    Caution! Data can be downloaded from within the +session and globally at the same time. If both files are downloaded, +this can lead to the all_apps_wide data being there twice! You can remove +duplicate data by using delete_duplicate().

    +

    Caution! When importing Excel files, this function does not check +for erroneous data structures +and will combine all data frames with the same file name patterns. +Before using the "CSV = FALSE" argument, clean up your data appropriately.

    +
    + +
    +
    import_otree(
    +  path = ".",
    +  file_names = NULL,
    +  final_apps = NULL,
    +  final_pages = NULL,
    +  recursive = TRUE,
    +  csv = TRUE,
    +  onlybots = FALSE,
    +  del_empty = TRUE,
    +  info = FALSE,
    +  encoding = "UTF-8"
    +)
    +
    + +
    +

    Arguments

    +
    path
    +

    Character. The path to the files (default is the +working directory).

    + + +
    file_names
    +

    Character. The name(s) of the file(s) to be imported. +If not specified, all files in the path and subfolders are imported.

    + + +
    final_apps
    +

    Character. +The name(s) of the app(s) at which the participants have to finish the +experiment. If the argument final_apps is left empty, you can still call +for deleting the participants who did not finish the experiment with +delete_dropouts().

    + + +
    final_pages
    +

    Character. +The name(s) of the page(s) at which the participants have to finish the +experiment. If the argument final_pages is left empty, you can still +call for deleting the participants who did not finish the experiment +with delete_dropouts().

    + + +
    recursive
    +

    Logical. TRUE if the files in the path's +subfolders should also be imported.

    + + +
    csv
    +

    Logical. +TRUE if only CSV files should be imported. +FALSE if only Excel files should be imported.

    + + +
    onlybots
    +

    Logical. TRUE if only bot-created files should be imported.

    + + +
    del_empty
    +

    Logical. TRUE if all empty cases should be deleted from the +all_apps_wide or normal app data frames (not Time or Chats).

    + + +
    info
    +

    Logical. TRUE if a brief information on the data import should be +printed.

    + + +
    encoding
    +

    Character. Encoding of the CSV files that are imported. +Default is "UTF-8".

    + +
    +
    +

    Value

    + + +

    Returns a list of data frames (one data frame for each app and +all_apps_wide) and a list of information on this list of data frames +in $info.

    + + +

    See detailed information on the imported files in $info$imported_files.

    + + +

    If all_apps_wide is imported, see the number of imported cases +in $info$initial_n. In this number, empty rows are +already considered. So, if empty rows are deleted with del_empty=TRUE, +initial_n counts all rows that are not empty. +Cases that are deleted because the participants did not make it to the +last page and/or app are not subtracted from this number.

    + + +

    Information: Empty rows are rows without the "participant._current_app_name" +variable set. Empty rows are deleted from all app data frames and +all_apps_wide when using del_empty=TRUE. Empty rows in the Chats and Time +data frames are not deleted.

    + + +

    If old and new oTree versions are combined, the Time data frame contains +variables called "participant_code" and "participant__code" +(the difference is in the underscores). +Caution! If there is an unusual amount of NAs, +check if everything got imported correctly. +Sometimes, the CSV or Excel file may be corrupted, and all information is +only found in one column.

    +
    + +
    +

    Examples

    +
    # Set data folder first
    +withr::with_dir(system.file("extdata", package = "gmoTree"), {
    +
    +# Import all oTree files in this folder and its subfolders
    +oTree <- import_otree()
    +
    +# Show the structure of the import
    +str(oTree, max.level = 1)
    +
    +# Show the names of all imported files
    +oTree$info$imported_files
    +
    +# Delete empty cases and delete every case of a person
    +# who didn't end the experiment in the app "survey"
    +oTree <- import_otree(
    +  del_empty = TRUE,
    +  final_apps = "survey",
    +  info = TRUE)
    +
    +# Show the structure of the import
    +str(oTree, max.level = 1)
    +
    +# Import bot files
    +import_otree(
    +  path = "./bot_data",
    +  onlybots = TRUE,
    +  csv = TRUE,
    +  info = TRUE)
    +
    +# Show the structure of the import
    +str(oTree, max.level = 1)
    +
    +# Import with file names (path separately)
    +oTree2 <- import_otree(
    +     del_empty = TRUE,
    +     path = "./exp_data",
    +     file_names = c("all_apps_wide-2023-03-27.csv",
    +                   "ChatMessages-2023-03-27.csv",
    +                   "PageTimes-2023-03-27.csv"),
    +     onlybots = FALSE,
    +     csv = TRUE,
    +     info = TRUE)
    +
    +# Show the structure of the import
    +str(oTree, max.level = 1)
    +
    +# Import with file names (without path separately)
    +oTree2 <- import_otree(
    +     del_empty = TRUE,
    +     file_names = c("exp_data/all_apps_wide-2023-03-27.csv",
    +                   "exp_data/ChatMessages-2023-03-27.csv",
    +                   "exp_data/PageTimes-2023-03-27.csv"),
    +     onlybots = FALSE,
    +     csv = TRUE,
    +     info = TRUE)
    +
    +# Show the structure of the import
    +str(oTree, max.level = 1)
    +})
    +#> Warning: You have stored all_apps_wide globally but also room-specific. This function will import both of them. (Globally, the files are saved as "all_apps_wide_." Room-specific, the files are saved as "All apps - wide-" or "all_apps_wide-.") After importing the data, make sure nothing is there twice! (Advice: You may use delete_duplicate() to remove duplicate rows of all oTree data frames.
    +#> List of 10
    +#>  $ all_apps_wide:'data.frame':	104 obs. of  68 variables:
    +#>  $ info         :List of 2
    +#>  $ chatapp      :'data.frame':	88 obs. of  28 variables:
    +#>  $ dictator     :'data.frame':	213 obs. of  30 variables:
    +#>  $ survey       :'data.frame':	88 obs. of  33 variables:
    +#>  $ start        :'data.frame':	38 obs. of  28 variables:
    +#>  $ 2chatapp     :'data.frame':	8 obs. of  24 variables:
    +#>  $ dictator2    :'data.frame':	24 obs. of  25 variables:
    +#>  $ Time         :'data.frame':	878 obs. of  18 variables:
    +#>  $ Chats        :'data.frame':	95 obs. of  11 variables:
    +#> Warning: You have stored all_apps_wide globally but also room-specific. This function will import both of them. (Globally, the files are saved as "all_apps_wide_." Room-specific, the files are saved as "All apps - wide-" or "all_apps_wide-.") After importing the data, make sure nothing is there twice! (Advice: You may use delete_duplicate() to remove duplicate rows of all oTree data frames.
    +#> Imported: 7 app(s) and/or all_apps_wide
    +#> Imported: Time file(s)
    +#> Imported: Chat file(s)
    +#> 26 case(s) deleted
    +#> Dropouts are deleted from all data frames. Except: The list of oTree data frames includes a chat. As the interpretation of chat data depends on how participants engage with each other, the data must be deleted with more care than deleting data in other apps. Hence, this function does not delete data in this data frame. Please do this manually if necessary!
    +#> 
    +#> Errors when importing these files:
    +#> File: ./exp_wrong_data/dictator_2023-03-27.csv: Error in read.table(file = file, header = header, sep = sep, quote = quote, : more columns than column names
    +#> List of 10
    +#>  $ all_apps_wide:'data.frame':	62 obs. of  68 variables:
    +#>  $ info         :List of 3
    +#>  $ chatapp      :'data.frame':	50 obs. of  28 variables:
    +#>  $ dictator     :'data.frame':	111 obs. of  30 variables:
    +#>  $ survey       :'data.frame':	50 obs. of  33 variables:
    +#>  $ start        :'data.frame':	16 obs. of  28 variables:
    +#>  $ 2chatapp     :'data.frame':	4 obs. of  24 variables:
    +#>  $ dictator2    :'data.frame':	12 obs. of  25 variables:
    +#>  $ Time         :'data.frame':	772 obs. of  18 variables:
    +#>  $ Chats        :'data.frame':	95 obs. of  11 variables:
    +#> Imported: 4 app(s) and/or all_apps_wide
    +#> No Time files available
    +#> No chat files available
    +#> List of 10
    +#>  $ all_apps_wide:'data.frame':	62 obs. of  68 variables:
    +#>  $ info         :List of 3
    +#>  $ chatapp      :'data.frame':	50 obs. of  28 variables:
    +#>  $ dictator     :'data.frame':	111 obs. of  30 variables:
    +#>  $ survey       :'data.frame':	50 obs. of  33 variables:
    +#>  $ start        :'data.frame':	16 obs. of  28 variables:
    +#>  $ 2chatapp     :'data.frame':	4 obs. of  24 variables:
    +#>  $ dictator2    :'data.frame':	12 obs. of  25 variables:
    +#>  $ Time         :'data.frame':	772 obs. of  18 variables:
    +#>  $ Chats        :'data.frame':	95 obs. of  11 variables:
    +#> Imported: 1 app(s) and/or all_apps_wide
    +#> Imported: Time file(s)
    +#> Imported: Chat file(s)
    +#> List of 10
    +#>  $ all_apps_wide:'data.frame':	62 obs. of  68 variables:
    +#>  $ info         :List of 3
    +#>  $ chatapp      :'data.frame':	50 obs. of  28 variables:
    +#>  $ dictator     :'data.frame':	111 obs. of  30 variables:
    +#>  $ survey       :'data.frame':	50 obs. of  33 variables:
    +#>  $ start        :'data.frame':	16 obs. of  28 variables:
    +#>  $ 2chatapp     :'data.frame':	4 obs. of  24 variables:
    +#>  $ dictator2    :'data.frame':	12 obs. of  25 variables:
    +#>  $ Time         :'data.frame':	772 obs. of  18 variables:
    +#>  $ Chats        :'data.frame':	95 obs. of  11 variables:
    +#> Imported: 1 app(s) and/or all_apps_wide
    +#> Imported: Time file(s)
    +#> Imported: Chat file(s)
    +#> List of 10
    +#>  $ all_apps_wide:'data.frame':	62 obs. of  68 variables:
    +#>  $ info         :List of 3
    +#>  $ chatapp      :'data.frame':	50 obs. of  28 variables:
    +#>  $ dictator     :'data.frame':	111 obs. of  30 variables:
    +#>  $ survey       :'data.frame':	50 obs. of  33 variables:
    +#>  $ start        :'data.frame':	16 obs. of  28 variables:
    +#>  $ 2chatapp     :'data.frame':	4 obs. of  24 variables:
    +#>  $ dictator2    :'data.frame':	12 obs. of  25 variables:
    +#>  $ Time         :'data.frame':	772 obs. of  18 variables:
    +#>  $ Chats        :'data.frame':	95 obs. of  11 variables:
    +
    +
    +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/docs/reference/index.html b/docs/reference/index.html new file mode 100644 index 0000000..408e6ad --- /dev/null +++ b/docs/reference/index.html @@ -0,0 +1,155 @@ + +Function reference • gmoTree + + +
    +
    + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +

    All functions

    +

    +
    +

    apptime()

    +

    Calculate the time that was spent on an app

    +

    assignv()

    +

    Assign a variable from all_apps_wide

    +

    assignv_to_aaw()

    +

    Assign a variable to all_apps_wide

    +

    delete_cases()

    +

    Delete specific cases

    +

    delete_dropouts()

    +

    Delete dropouts

    +

    delete_duplicate()

    +

    Delete duplicate data

    +

    delete_plabels()

    +

    Delete participant labels in all apps

    +

    delete_sessions()

    +

    Delete all cases of one session

    +

    extime()

    +

    Calculate the time that was spent on the whole experiment

    +

    import_otree()

    +

    Import oTree data

    +

    make_ids()

    +

    Make IDs

    +

    messy_chat()

    +

    Check if the Chats data frame is messy

    +

    messy_time()

    +

    Check if the Time data frame is messy

    +

    oTree

    +

    Sample experiment data

    +

    pagesec()

    +

    Calculate the seconds spent on each page

    +

    show_constant()

    +

    Show constant columns

    +

    show_dropouts()

    +

    Show participants who did not finish the experiment

    + + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/docs/reference/make_ids.html b/docs/reference/make_ids.html new file mode 100644 index 0000000..0780606 --- /dev/null +++ b/docs/reference/make_ids.html @@ -0,0 +1,226 @@ + +Make IDs — make_ids • gmoTree + + +
    +
    + + + +
    +
    + + +
    +

    Make session IDs and, optionally, group IDs and participant IDs +that span across all data frames created by +import_otree(). Information for these IDs is taken from all_apps_wide +but can be defined otherwise.

    +

    Note: Older versions of oTree may already contain a +variable called session_id in their Time data frames. +This variable is overwritten by this function!

    +

    Important: Combine duplicate data before running this function!

    +
    + +
    +
    make_ids(
    +  oTree,
    +  gmake = FALSE,
    +  pmake = TRUE,
    +  from_app = "all_apps_wide",
    +  from_var = NULL,
    +  sstart = 1,
    +  gstart = 1,
    +  pstart = 1,
    +  emptyrows = NULL,
    +  icw = FALSE
    +)
    +
    + +
    +

    Arguments

    +
    oTree
    +

    A list of data frames that were created by import_otree().

    + + +
    gmake
    +

    Logical. TRUE if a variable called group_id should be made. +If from_var is not NULL, gmake is automatically set to TRUE.

    + + +
    pmake
    +

    Logical. TRUE if a variable called participant_id +should be made.

    + + +
    from_app
    +

    Character. Name of the data frame from which the session, +group, and participant information should be taken. +All normal app data frames and all_apps_wide are allowed.

    + + +
    from_var
    +

    Character. Name of the variable from which the group +information should be taken. This argument is only relevant when +all_apps_wide is used as from_app and has group information that contradicts +each other.

    + + +
    sstart
    +

    Integer. +The number that serves as a starting point for session IDs.

    + + +
    gstart
    +

    Integer. +The number that serves as a starting point for group IDs.

    + + +
    pstart
    +

    Integer. +The number that serves as a starting point for participant IDs.

    + + +
    emptyrows
    +

    Character. "no" if the function should stop if there are +empty rows in from_app. "yes" if the function should continue to make IDs.

    + + +
    icw
    +

    Logical. TRUE if the warning message should be +ignored that states that IDs cannot be made because of an oTree bug.

    + +
    +
    +

    Value

    + + +

    ID variables are made in all_apps_wide, all app data frames, +the Time data frame, and the Chats data frame. +See list of the additional ID variables in $info$additional_variables.

    +
    + +
    +

    Examples

    +
    # Use package-internal list of oTree data frames
    +oTree <- gmoTree::oTree
    +
    +# Make session IDs only
    +oTree2 <- make_ids(oTree)
    +
    +# Show new variables
    +oTree2$all_apps_wide$session_id
    +#>  [1] 1 1 1 1 1 1 1 1 1 2 2 2 2 3 3 3 3 3 3 4 4 4 4 5 5 6 6 6 6
    +
    +# Make session IDs and group IDs #
    +# Not working with this data set because group ID is not the same in all apps
    +# oTree2 <- make_ids(oTree, gmake = TRUE)
    +
    +# Show new variables
    +# oTree2$all_apps_wide$session_id
    +# oTree2$all_apps_wide$group_id
    +
    +# Get IDs from variable "dictator.1.group.id_in_subsession"
    +# in the data frame "all_apps_wide"
    +oTree2 <- make_ids(oTree,
    +                   gmake = TRUE,
    +                   from_var = "dictator.1.group.id_in_subsession")
    +
    +# Show new variables
    +oTree2$all_apps_wide$session_id
    +#>  [1] 1 1 1 1 1 1 1 1 1 2 2 2 2 3 3 3 3 3 3 4 4 4 4 5 5 6 6 6 6
    +oTree2$all_apps_wide$group_id
    +#>  [1]  1  1  2  2  3  3  4  4  5  6  6  7  7  8  8  9  9 10 10 11 11 12 12 13 13
    +#> [26] 14 14 15 15
    +
    +# Get IDs from another app than all_apps_wide
    +oTree2 <- make_ids(oTree, gmake = TRUE, from_app = "dictator")
    +#> Warning: Data frame "all_apps_wide" has more participants than dictator: 6cim3a5i, 1mn1kzs7, zdki96d6, byxco6zo
    +
    +# Show new variables
    +oTree2$all_apps_wide$session_id
    +#>  [1]  1  1  1  1  1  1  1  1  1  2  2  2  2  3  3  3  3  3  3  4  4  4  4  5  5
    +#> [26] NA NA NA NA
    +oTree2$all_apps_wide$group_id
    +#>  [1]  1  1  2  2  3  3  4  4  5  6  6  7  7  8  8  9  9 10 10 11 11 12 12 13 13
    +#> [26] NA NA NA NA
    +
    +
    +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/docs/reference/messy_chat.html b/docs/reference/messy_chat.html new file mode 100644 index 0000000..67d5c70 --- /dev/null +++ b/docs/reference/messy_chat.html @@ -0,0 +1,188 @@ + +Check if the Chats data frame is messy — messy_chat • gmoTree + + +
    +
    + + + +
    +
    + + +
    +

    Check if the Chats data frame includes both +session-related variables and participant-related variables that +appear multiple times. This may occur when data from different +oTree versions, which use different variable names, are combined.

    +

    If desired, the function can merge these variables, +storing the data using the newer oTree version's variable names +and removing the outdated variables.

    +
    + +
    +
    messy_chat(
    +  oTree,
    +  combine = FALSE,
    +  session = TRUE,
    +  participant = TRUE,
    +  info = FALSE
    +)
    +
    + +
    +

    Arguments

    +
    oTree
    +

    A list of data frames that were created by import_otree().

    + + +
    combine
    +

    Logical. TRUE if all variables referring to +the session code should be merged and/or all variables referring +to participant code should be merged in case data of several versions +of oTree are used.

    + + +
    session
    +

    Logical. TRUE if all variables referring to the session code +should be checked and merged. Merging only works if combine = TRUE.

    + + +
    participant
    +

    Logical. TRUE if all variables referring to the +participant code should be checked and merged. Merging only works if +combine = TRUE.

    + + +
    info
    +

    Logical. TRUE if a brief information on the process should +be printed.

    + +
    +
    +

    Value

    + + +

    This function returns an oTree list of data frames that is +an exact copy of the original oTree list of data frames but - if the user +wishes to do so - combines the participant code and session code +variables in the Chats data frame if several variables are referring to +those because of the +combination of different oTree versions. The final variables are called +participant_code and session_code.

    + + +

    If combine = FALSE, the function only checks for the existence of several +variables referring to the participant code and session code and throws an +error if yes.

    +
    + +
    +

    Examples

    +
    # Set data folder first
    +withr::with_dir(system.file("extdata", package = "gmoTree"), {
    +
    +# Import all oTree files in this folder and its subfolders
    +oTree <- import_otree()
    +})
    +#> Warning: You have stored all_apps_wide globally but also room-specific. This function will import both of them. (Globally, the files are saved as "all_apps_wide_." Room-specific, the files are saved as "All apps - wide-" or "all_apps_wide-.") After importing the data, make sure nothing is there twice! (Advice: You may use delete_duplicate() to remove duplicate rows of all oTree data frames.
    +
    +# Show all Chats column names
    +print(colnames(oTree$Chats))
    +#>  [1] "session_code"               "id_in_session"             
    +#>  [3] "participant_code"           "channel"                   
    +#>  [5] "nickname"                   "body"                      
    +#>  [7] "timestamp"                  "participant__session__code"
    +#>  [9] "participant__session_id"    "participant__id_in_session"
    +#> [11] "participant__code"         
    +
    +# Run function
    +oTree <- messy_chat(oTree, combine = TRUE)
    +
    +# Show all Chats column names again
    +print(colnames(oTree$Chats))
    +#> [1] "session_code"               "id_in_session"             
    +#> [3] "participant_code"           "channel"                   
    +#> [5] "nickname"                   "body"                      
    +#> [7] "timestamp"                  "participant__session_id"   
    +#> [9] "participant__id_in_session"
    +
    +
    +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/docs/reference/messy_time.html b/docs/reference/messy_time.html new file mode 100644 index 0000000..7c02528 --- /dev/null +++ b/docs/reference/messy_time.html @@ -0,0 +1,192 @@ + +Check if the Time data frame is messy — messy_time • gmoTree + + +
    +
    + + + +
    +
    + + +
    +

    Check if the Time data frame includes both participant-related variables +and time stamp variables that appear multiple times. This may occur when +data from different oTree versions, which use different variable names, +are combined.

    +

    If desired, the function can merge these variables, +storing the data using the newer oTree version's variable names +and removing the outdated variables.

    +
    + +
    +
    messy_time(
    +  oTree,
    +  combine = FALSE,
    +  epoch_time = TRUE,
    +  participant = TRUE,
    +  info = FALSE
    +)
    +
    + +
    +

    Arguments

    +
    oTree
    +

    A list of data frames that were created by import_otree().

    + + +
    combine
    +

    Logical. TRUE if all variables referring to epoch time should +be merged and/or all variables referring to participant code should be merged +in case data of several versions of oTree are used.

    + + +
    epoch_time
    +

    Logical. TRUE if all variables referring to the time stamp +should be checked and merged. Only works if combine = TRUE.

    + + +
    participant
    +

    Logical. TRUE if all variables referring to the +participant code should be checked and merged. Only works if combine = TRUE.

    + + +
    info
    +

    Logical. TRUE if a brief information on the process should +be printed.

    + +
    +
    +

    Value

    + + +

    This function returns an oTree list of data frames that is +an exact copy of the original oTree list of data frames but - if the user +wishes to do so - combines the +time tamps and participant codes in the Time data frame if several variables +are referring to those because of the +combination of different oTree versions. The final variables are called +epoch_time_completed and participant_code.

    + + +

    If combine = FALSE, the function only checks for the existence of several +variables referring to the time stamp or the participant code and throws an +error if yes.

    +
    + +
    +

    Examples

    +
    # Set data folder first
    +withr::with_dir(system.file("extdata", package = "gmoTree"), {
    +
    +# Import all oTree files in this folder and its subfolders
    +oTree <- import_otree()
    +})
    +#> Warning: You have stored all_apps_wide globally but also room-specific. This function will import both of them. (Globally, the files are saved as "all_apps_wide_." Room-specific, the files are saved as "All apps - wide-" or "all_apps_wide-.") After importing the data, make sure nothing is there twice! (Advice: You may use delete_duplicate() to remove duplicate rows of all oTree data frames.
    +
    +# Show all Time column names
    +print(colnames(oTree$Time))
    +#>  [1] "session_code"               "participant_id_in_session" 
    +#>  [3] "participant_code"           "page_index"                
    +#>  [5] "app_name"                   "page_name"                 
    +#>  [7] "epoch_time"                 "round_number"              
    +#>  [9] "timeout_happened"           "is_wait_page"              
    +#> [11] "epoch_time_completed"       "session_id"                
    +#> [13] "participant__id_in_session" "participant__code"         
    +#> [15] "time_stamp"                 "seconds_on_page"           
    +#> [17] "subsession_pk"              "auto_submitted"            
    +
    +# Run function
    +oTree <- messy_time(oTree, combine = TRUE)
    +
    +# Show all Time column names again
    +print(colnames(oTree$Time))
    +#>  [1] "session_code"               "participant_id_in_session" 
    +#>  [3] "participant_code"           "page_index"                
    +#>  [5] "app_name"                   "page_name"                 
    +#>  [7] "round_number"               "timeout_happened"          
    +#>  [9] "is_wait_page"               "epoch_time_completed"      
    +#> [11] "session_id"                 "participant__id_in_session"
    +#> [13] "seconds_on_page"            "subsession_pk"             
    +#> [15] "auto_submitted"            
    +
    +
    +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/docs/reference/oTree.html b/docs/reference/oTree.html new file mode 100644 index 0000000..e0bcedb --- /dev/null +++ b/docs/reference/oTree.html @@ -0,0 +1,103 @@ + +Sample experiment data — oTree • gmoTree + + +
    +
    + + + +
    +
    + + +
    +

    Sample experiment data

    +
    + +
    +
    oTree
    +
    + +
    +

    Format

    +

    A list of data frames created by import_otree().

    +
    +
    +

    Source

    +

    The data set was created by using modified versions of the official +oTree sample experiments that can be downloaded when installing oTree. +In detail, the following apps were used: "dictator," "chatapp," "survey."

    +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/docs/reference/pagesec.html b/docs/reference/pagesec.html new file mode 100644 index 0000000..75521e5 --- /dev/null +++ b/docs/reference/pagesec.html @@ -0,0 +1,235 @@ + +Calculate the seconds spent on each page — pagesec • gmoTree + + +
    +
    + + + +
    +
    + + +
    +

    Create a new variable in the Time data frame that contains the time +spent on each page.

    +
    + +
    +
    pagesec(oTree, rounded = TRUE, digits = 2, minutes = FALSE, combine = FALSE)
    +
    + +
    +

    Arguments

    +
    oTree
    +

    A list of data frames that were created by import_otree().

    + + +
    rounded
    +

    Logical. TRUE if the output should be rounded.

    + + +
    digits
    +

    Integer. The number of digits to which the +output should be rounded. +This parameter has no effect unless rounded = TRUE.

    + + +
    minutes
    +

    Logical. TRUE if the output should be +minutes instead of seconds.

    + + +
    combine
    +

    Logical. TRUE if all variables referring to epoch time should +be merged, and all variables referring to participant code should be +merged in case data of several versions of oTree are used.

    + +
    +
    +

    Value

    + + +

    This function returns a duplicate of the original oTree list of +data frames that also contains a column in the Time data frame named +seconds_on_page2 or minutes_on_page.

    +
    + +
    +

    Examples

    +
    # Use package-internal list of oTree data frames
    +oTree <- gmoTree::oTree
    +
    +# Create two new columns: seconds_on_page2 and minutes_on_page
    +oTree <- pagesec(oTree, rounded = TRUE, minutes = TRUE)
    +
    +# Show the Time data frame
    +head(oTree$Time, n = 30)
    +#>    session_code participant_id_in_session participant_code page_index app_name
    +#> 1      7bfqtokx                         1         46kxib6w          0         
    +#> 2      7bfqtokx                         2         iay3dhkn          0         
    +#> 3      7bfqtokx                         3         4zhzdmzo          0         
    +#> 4      7bfqtokx                         4         3ttf7yix          0         
    +#> 5      7bfqtokx                         5         2d72mfgh          0         
    +#> 6      7bfqtokx                         6         rvce7958          0         
    +#> 7      7bfqtokx                         7         164r1hs4          0         
    +#> 8      7bfqtokx                         8         lsl3vbij          0         
    +#> 9      7bfqtokx                         9         ktjz5jli          0         
    +#> 10     7bfqtokx                         1         46kxib6w          1 dictator
    +#> 11     7bfqtokx                         1         46kxib6w          2 dictator
    +#> 12     7bfqtokx                         2         iay3dhkn          1 dictator
    +#> 13     7bfqtokx                         1         46kxib6w          3 dictator
    +#> 14     7bfqtokx                         2         iay3dhkn          3 dictator
    +#> 15     7bfqtokx                         2         iay3dhkn          4 dictator
    +#> 16     7bfqtokx                         2         iay3dhkn          5 dictator
    +#> 17     7bfqtokx                         1         46kxib6w          4 dictator
    +#> 18     7bfqtokx                         1         46kxib6w          5 dictator
    +#> 19     7bfqtokx                         1         46kxib6w          6 dictator
    +#> 20     7bfqtokx                         1         46kxib6w          7 dictator
    +#> 21     7bfqtokx                         2         iay3dhkn          7 dictator
    +#> 22     7bfqtokx                         1         46kxib6w          8 dictator
    +#> 23     7bfqtokx                         1         46kxib6w          9 dictator
    +#> 24     7bfqtokx                         1         46kxib6w         10 dictator
    +#> 25     7bfqtokx                         2         iay3dhkn          8 dictator
    +#> 26     7bfqtokx                         2         iay3dhkn          9 dictator
    +#> 27     7bfqtokx                         1         46kxib6w         11 dictator
    +#> 28     7bfqtokx                         2         iay3dhkn         11 dictator
    +#> 29     7bfqtokx                         2         iay3dhkn         12 dictator
    +#> 30     7bfqtokx                         1         46kxib6w         12 dictator
    +#>                page_name epoch_time_completed round_number timeout_happened
    +#> 1  InitializeParticipant           1679926144            1                0
    +#> 2  InitializeParticipant           1679926145            1                0
    +#> 3  InitializeParticipant           1679926146            1                0
    +#> 4  InitializeParticipant           1679926146            1                0
    +#> 5  InitializeParticipant           1679926147            1                0
    +#> 6  InitializeParticipant           1679926147            1                0
    +#> 7  InitializeParticipant           1679926148            1                0
    +#> 8  InitializeParticipant           1679926148            1                0
    +#> 9  InitializeParticipant           1679926149            1                0
    +#> 10          Introduction           1679926151            1                0
    +#> 11                 Offer           1679926154            1                0
    +#> 12          Introduction           1679926156            1                0
    +#> 13       ResultsWaitPage           1679926156            1                0
    +#> 14       ResultsWaitPage           1679926156            1                0
    +#> 15               Results           1679926157            1                0
    +#> 16          Introduction           1679926158            2                0
    +#> 17               Results           1679926160            1                0
    +#> 18          Introduction           1679926162            2                0
    +#> 19                 Offer           1679926165            2                0
    +#> 20       ResultsWaitPage           1679926165            2                0
    +#> 21       ResultsWaitPage           1679926165            2                0
    +#> 22               Results           1679926166            2                0
    +#> 23          Introduction           1679926167            3                0
    +#> 24                 Offer           1679926169            3                0
    +#> 25               Results           1679926171            2                0
    +#> 26          Introduction           1679926172            3                0
    +#> 27       ResultsWaitPage           1679926172            3                0
    +#> 28       ResultsWaitPage           1679926172            3                0
    +#> 29               Results           1679926173            3                0
    +#> 30               Results           1679926178            3                0
    +#>    is_wait_page minutes_on_page
    +#> 1             0              NA
    +#> 2             0              NA
    +#> 3             0              NA
    +#> 4             0              NA
    +#> 5             0              NA
    +#> 6             0              NA
    +#> 7             0              NA
    +#> 8             0              NA
    +#> 9             0              NA
    +#> 10            0            0.12
    +#> 11            0            0.05
    +#> 12            0            0.18
    +#> 13            1            0.03
    +#> 14            1            0.00
    +#> 15            0            0.02
    +#> 16            0            0.02
    +#> 17            0            0.07
    +#> 18            0            0.03
    +#> 19            0            0.05
    +#> 20            1            0.00
    +#> 21            1            0.12
    +#> 22            0            0.02
    +#> 23            0            0.02
    +#> 24            0            0.03
    +#> 25            0            0.10
    +#> 26            0            0.02
    +#> 27            1            0.05
    +#> 28            1            0.00
    +#> 29            0            0.02
    +#> 30            0            0.10
    +
    +
    +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/docs/reference/show_constant.html b/docs/reference/show_constant.html new file mode 100644 index 0000000..f14b313 --- /dev/null +++ b/docs/reference/show_constant.html @@ -0,0 +1,247 @@ + +Show constant columns — show_constant • gmoTree + + +
    +
    + + + +
    +
    + + +
    +

    Show all columns with no variation in their values for each data frame +in the oTree list of data frames (except the ones in the info list). +This function is helpful before running an experiment to check if there +are unnecessary variables. +You can check for columns that have any unchanging possible value +or for columns containing only a specific value.

    +
    + +
    +
    show_constant(oTree, value = "any")
    +
    + +
    +

    Arguments

    +
    oTree
    +

    A list of data frames that were created by import_otree().

    + + +
    value
    +

    The value that is controlled to be the same within a column. +The default is NA. If the value is set to "any," the function checks for +columns where any possible values are identical.

    + +
    +
    +

    Value

    + + +

    This function returns a list of vectors, one for each app, +all_apps_wide, the Time and/or the Chats data frame. +Each vector contains the names of all variables with constant values. +If there are no variables with constant values, the vector is empty.

    +
    + +
    +

    Examples

    +
    # Use package-internal list of oTree data frames
    +oTree <- gmoTree::oTree
    +
    +# Show all columns that contain only NAs
    +show_constant(oTree = oTree)
    +#> $all_apps_wide
    +#>  [1] "participant._is_bot"                         
    +#>  [2] "participant._max_page_index"                 
    +#>  [3] "participant.visited"                         
    +#>  [4] "participant.mturk_worker_id"                 
    +#>  [5] "participant.mturk_assignment_id"             
    +#>  [6] "session.label"                               
    +#>  [7] "session.mturk_HITId"                         
    +#>  [8] "session.mturk_HITGroupId"                    
    +#>  [9] "session.comment"                             
    +#> [10] "session.is_demo"                             
    +#> [11] "session.config.name"                         
    +#> [12] "session.config.real_world_currency_per_point"
    +#> [13] "session.config.participation_fee"            
    +#> [14] "dictator.1.player.role"                      
    +#> [15] "dictator.1.subsession.round_number"          
    +#> [16] "dictator.2.player.role"                      
    +#> [17] "dictator.2.subsession.round_number"          
    +#> [18] "dictator.3.player.role"                      
    +#> [19] "dictator.3.subsession.round_number"          
    +#> [20] "chatapp.1.player.role"                       
    +#> [21] "chatapp.1.player.payoff"                     
    +#> [22] "chatapp.1.subsession.round_number"           
    +#> [23] "survey.1.player.role"                        
    +#> [24] "survey.1.player.payoff"                      
    +#> [25] "survey.1.group.id_in_subsession"             
    +#> [26] "survey.1.subsession.round_number"            
    +#> 
    +#> $chatapp
    +#>  [1] "participant._is_bot"             "participant._max_page_index"    
    +#>  [3] "participant.visited"             "participant.mturk_worker_id"    
    +#>  [5] "participant.mturk_assignment_id" "player.role"                    
    +#>  [7] "player.payoff"                   "subsession.round_number"        
    +#>  [9] "session.label"                   "session.mturk_HITId"            
    +#> [11] "session.mturk_HITGroupId"        "session.comment"                
    +#> [13] "session.is_demo"                
    +#> 
    +#> $dictator
    +#>  [1] "participant._is_bot"             "participant._max_page_index"    
    +#>  [3] "participant.visited"             "participant.mturk_worker_id"    
    +#>  [5] "participant.mturk_assignment_id" "player.role"                    
    +#>  [7] "session.label"                   "session.mturk_HITId"            
    +#>  [9] "session.mturk_HITGroupId"        "session.comment"                
    +#> [11] "session.is_demo"                
    +#> 
    +#> $survey
    +#>  [1] "participant._is_bot"             "participant._max_page_index"    
    +#>  [3] "participant.visited"             "participant.mturk_worker_id"    
    +#>  [5] "participant.mturk_assignment_id" "player.role"                    
    +#>  [7] "player.payoff"                   "group.id_in_subsession"         
    +#>  [9] "subsession.round_number"         "session.label"                  
    +#> [11] "session.mturk_HITId"             "session.mturk_HITGroupId"       
    +#> [13] "session.comment"                 "session.is_demo"                
    +#> 
    +#> $Time
    +#> [1] "timeout_happened"
    +#> 
    +#> $Chats
    +#> character(0)
    +#> 
    +show_constant(oTree = oTree, value = NA)
    +#> $all_apps_wide
    +#>  [1] "participant.mturk_worker_id"     "participant.mturk_assignment_id"
    +#>  [3] "session.label"                   "session.mturk_HITId"            
    +#>  [5] "session.mturk_HITGroupId"        "session.comment"                
    +#>  [7] "dictator.1.player.role"          "dictator.2.player.role"         
    +#>  [9] "dictator.3.player.role"          "chatapp.1.player.role"          
    +#> [11] "survey.1.player.role"           
    +#> 
    +#> $chatapp
    +#> [1] "participant.mturk_worker_id"     "participant.mturk_assignment_id"
    +#> [3] "player.role"                     "session.label"                  
    +#> [5] "session.mturk_HITId"             "session.mturk_HITGroupId"       
    +#> [7] "session.comment"                
    +#> 
    +#> $dictator
    +#> [1] "participant.mturk_worker_id"     "participant.mturk_assignment_id"
    +#> [3] "player.role"                     "session.label"                  
    +#> [5] "session.mturk_HITId"             "session.mturk_HITGroupId"       
    +#> [7] "session.comment"                
    +#> 
    +#> $survey
    +#> [1] "participant.mturk_worker_id"     "participant.mturk_assignment_id"
    +#> [3] "player.role"                     "session.label"                  
    +#> [5] "session.mturk_HITId"             "session.mturk_HITGroupId"       
    +#> [7] "session.comment"                
    +#> 
    +#> $Time
    +#> character(0)
    +#> 
    +#> $Chats
    +#> character(0)
    +#> 
    +
    +# Show all columns that contain only -99
    +show_constant(oTree = oTree, value = -99)
    +#> $all_apps_wide
    +#> character(0)
    +#> 
    +#> $chatapp
    +#> character(0)
    +#> 
    +#> $dictator
    +#> character(0)
    +#> 
    +#> $survey
    +#> character(0)
    +#> 
    +#> $Time
    +#> character(0)
    +#> 
    +#> $Chats
    +#> character(0)
    +#> 
    +
    +
    +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/docs/reference/show_dropouts.html b/docs/reference/show_dropouts.html new file mode 100644 index 0000000..c8b3238 --- /dev/null +++ b/docs/reference/show_dropouts.html @@ -0,0 +1,683 @@ + +Show participants who did not finish the experiment — show_dropouts • gmoTree + + +
    +
    + + + +
    +
    + + +
    +

    Show information on the people who did not finish the experiment at (a) +certain page(s) and/or app(s).

    +
    + +
    +
    show_dropouts(oTree, final_apps = NULL, final_pages = NULL, saved_vars = NULL)
    +
    + +
    +

    Arguments

    +
    oTree
    +

    A list of data frames that were created by import_otree().

    + + +
    final_apps
    +

    Character. +The name(s) of the app(s) at which the participants have to finish the +experiment.

    + + +
    final_pages
    +

    Character. +The name(s) of the page(s) at which the participants have to finish the +experiment.

    + + +
    saved_vars
    +

    The name(s) of variable(s) that need(s) to be +shown in the list of information on dropout cases.

    + +
    +
    +

    Value

    + + +

    This function returns a list of information on participants who did not +finish the experiment.

    + + +

    In this list, you can find the following information:

    + + +

    $full = A data frame that contains information +on all participants who did not finish the study; +it shows their participant codes, the names of the apps in which they +left the experiment, +the names of the pages in which they left the experiment, +the names of the app data frames in which this information was found, and +the dropout reason ("ENC," experiment not completed, combined +with the name of the data frame in which the dropout was observed). +Because participants usually appear in multiple app data frames, +the $full data frame may contain several entries for +each person.

    + + +

    $unique = A data frame that contains similar information as the $full data +frame but with only one row per participant and no information on the data +frame in which the dropout was observed.

    + + +

    $all_end = A table that provides information on the app and page combinations +where participants ended the experiment. This table also includes +information on participants who did not drop out of the experiment. +The $all_end table is only shown if an all_apps_wide data frame exists.

    + + +

    $codes = A vector containing the participant codes of +all participants who did not finish the experiment.

    + + +

    $count = The number of all participants who did not finish the experiment.

    + + +

    It is important to note that if only the argument final_pages is set, +this function does not distinguish between page names that reoccur in +different apps.

    + + +

    If the columns end_app and end_page in the output are empty, +these variables were not saved by oTree for the specific participants. +This could be because empty rows were not deleted. This can be done +by using the argument "del_empty = TRUE" when using import_otree().

    +
    + +
    +

    Examples

    +
    # Use package-internal list of oTree data frames
    +oTree <- gmoTree::oTree
    +
    +# Show everyone who did not finish with the app "survey"
    +show_dropouts(oTree, final_apps = "survey")
    +#> $full
    +#>    participant.code session.code  end_app        end_page
    +#> 1          164r1hs4     7bfqtokx  chatapp            chat
    +#> 2          164r1hs4     7bfqtokx  chatapp            chat
    +#> 3          164r1hs4     7bfqtokx  chatapp            chat
    +#> 4          164r1hs4     7bfqtokx  chatapp            chat
    +#> 5          2scvem7a     vd1h01iv dictator ResultsWaitPage
    +#> 6          2scvem7a     vd1h01iv dictator ResultsWaitPage
    +#> 7          2scvem7a     vd1h01iv dictator ResultsWaitPage
    +#> 8          2scvem7a     vd1h01iv dictator ResultsWaitPage
    +#> 9          7wa8kk3d     l8ecm1uh dictator    Introduction
    +#> 10         7wa8kk3d     l8ecm1uh dictator    Introduction
    +#> 11         7wa8kk3d     l8ecm1uh dictator    Introduction
    +#> 12         7wa8kk3d     l8ecm1uh dictator    Introduction
    +#> 13         ao9kqvqn     l8ecm1uh dictator    Introduction
    +#> 14         ao9kqvqn     l8ecm1uh dictator    Introduction
    +#> 15         ao9kqvqn     l8ecm1uh dictator    Introduction
    +#> 16         ao9kqvqn     l8ecm1uh dictator    Introduction
    +#> 17         d4sq7zio     l8ecm1uh dictator    Introduction
    +#> 18         d4sq7zio     l8ecm1uh dictator    Introduction
    +#> 19         d4sq7zio     l8ecm1uh dictator    Introduction
    +#> 20         d4sq7zio     l8ecm1uh dictator    Introduction
    +#> 21         ktjz5jli     7bfqtokx dictator ResultsWaitPage
    +#> 22         ktjz5jli     7bfqtokx dictator ResultsWaitPage
    +#> 23         ktjz5jli     7bfqtokx dictator ResultsWaitPage
    +#> 24         ktjz5jli     7bfqtokx dictator ResultsWaitPage
    +#> 25         vbhvhozv     vd1h01iv dictator ResultsWaitPage
    +#> 26         vbhvhozv     vd1h01iv dictator ResultsWaitPage
    +#> 27         vbhvhozv     vd1h01iv dictator ResultsWaitPage
    +#> 28         vbhvhozv     vd1h01iv dictator ResultsWaitPage
    +#> 29         znri6myc     l8ecm1uh dictator    Introduction
    +#> 30         znri6myc     l8ecm1uh dictator    Introduction
    +#> 31         znri6myc     l8ecm1uh dictator    Introduction
    +#> 32         znri6myc     l8ecm1uh dictator    Introduction
    +#>                                                 reason
    +#> 1  Experiment not completed. Noticed at: all_apps_wide
    +#> 2        Experiment not completed. Noticed at: chatapp
    +#> 3       Experiment not completed. Noticed at: dictator
    +#> 4         Experiment not completed. Noticed at: survey
    +#> 5  Experiment not completed. Noticed at: all_apps_wide
    +#> 6        Experiment not completed. Noticed at: chatapp
    +#> 7       Experiment not completed. Noticed at: dictator
    +#> 8         Experiment not completed. Noticed at: survey
    +#> 9  Experiment not completed. Noticed at: all_apps_wide
    +#> 10       Experiment not completed. Noticed at: chatapp
    +#> 11      Experiment not completed. Noticed at: dictator
    +#> 12        Experiment not completed. Noticed at: survey
    +#> 13 Experiment not completed. Noticed at: all_apps_wide
    +#> 14       Experiment not completed. Noticed at: chatapp
    +#> 15      Experiment not completed. Noticed at: dictator
    +#> 16        Experiment not completed. Noticed at: survey
    +#> 17 Experiment not completed. Noticed at: all_apps_wide
    +#> 18       Experiment not completed. Noticed at: chatapp
    +#> 19      Experiment not completed. Noticed at: dictator
    +#> 20        Experiment not completed. Noticed at: survey
    +#> 21 Experiment not completed. Noticed at: all_apps_wide
    +#> 22       Experiment not completed. Noticed at: chatapp
    +#> 23      Experiment not completed. Noticed at: dictator
    +#> 24        Experiment not completed. Noticed at: survey
    +#> 25 Experiment not completed. Noticed at: all_apps_wide
    +#> 26       Experiment not completed. Noticed at: chatapp
    +#> 27      Experiment not completed. Noticed at: dictator
    +#> 28        Experiment not completed. Noticed at: survey
    +#> 29 Experiment not completed. Noticed at: all_apps_wide
    +#> 30       Experiment not completed. Noticed at: chatapp
    +#> 31      Experiment not completed. Noticed at: dictator
    +#> 32        Experiment not completed. Noticed at: survey
    +#> 
    +#> $unique
    +#>    participant.code session.code  end_app        end_page
    +#> 1          164r1hs4     7bfqtokx  chatapp            chat
    +#> 5          2scvem7a     vd1h01iv dictator ResultsWaitPage
    +#> 9          7wa8kk3d     l8ecm1uh dictator    Introduction
    +#> 13         ao9kqvqn     l8ecm1uh dictator    Introduction
    +#> 17         d4sq7zio     l8ecm1uh dictator    Introduction
    +#> 21         ktjz5jli     7bfqtokx dictator ResultsWaitPage
    +#> 25         vbhvhozv     vd1h01iv dictator ResultsWaitPage
    +#> 29         znri6myc     l8ecm1uh dictator    Introduction
    +#>                      reason
    +#> 1  Experiment not completed
    +#> 5  Experiment not completed
    +#> 9  Experiment not completed
    +#> 13 Experiment not completed
    +#> 17 Experiment not completed
    +#> 21 Experiment not completed
    +#> 25 Experiment not completed
    +#> 29 Experiment not completed
    +#> 
    +#> $all_end
    +#>           
    +#>            Demographics Introduction Offer ResultsWaitPage chat
    +#>   chatapp             0            0     0               0    1
    +#>   dictator            0            4     0               3    0
    +#>   survey             20            0     1               0    0
    +#> 
    +#> $codes
    +#> [1] "164r1hs4" "2scvem7a" "7wa8kk3d" "ao9kqvqn" "d4sq7zio" "ktjz5jli" "vbhvhozv"
    +#> [8] "znri6myc"
    +#> 
    +#> $count
    +#> [1] 8
    +#> 
    +
    +# Show everyone who did not finish with the page "Demographics"
    +show_dropouts(oTree, final_pages = "Demographics")
    +#> $full
    +#>    participant.code session.code  end_app        end_page
    +#> 1          164r1hs4     7bfqtokx  chatapp            chat
    +#> 2          164r1hs4     7bfqtokx  chatapp            chat
    +#> 3          164r1hs4     7bfqtokx  chatapp            chat
    +#> 4          164r1hs4     7bfqtokx  chatapp            chat
    +#> 5          2scvem7a     vd1h01iv dictator ResultsWaitPage
    +#> 6          2scvem7a     vd1h01iv dictator ResultsWaitPage
    +#> 7          2scvem7a     vd1h01iv dictator ResultsWaitPage
    +#> 8          2scvem7a     vd1h01iv dictator ResultsWaitPage
    +#> 9          7wa8kk3d     l8ecm1uh dictator    Introduction
    +#> 10         7wa8kk3d     l8ecm1uh dictator    Introduction
    +#> 11         7wa8kk3d     l8ecm1uh dictator    Introduction
    +#> 12         7wa8kk3d     l8ecm1uh dictator    Introduction
    +#> 13         ao9kqvqn     l8ecm1uh dictator    Introduction
    +#> 14         ao9kqvqn     l8ecm1uh dictator    Introduction
    +#> 15         ao9kqvqn     l8ecm1uh dictator    Introduction
    +#> 16         ao9kqvqn     l8ecm1uh dictator    Introduction
    +#> 17         d4sq7zio     l8ecm1uh dictator    Introduction
    +#> 18         d4sq7zio     l8ecm1uh dictator    Introduction
    +#> 19         d4sq7zio     l8ecm1uh dictator    Introduction
    +#> 20         d4sq7zio     l8ecm1uh dictator    Introduction
    +#> 21         jxh15obl     t0rog7nz   survey           Offer
    +#> 22         jxh15obl     t0rog7nz   survey           Offer
    +#> 23         jxh15obl     t0rog7nz   survey           Offer
    +#> 24         jxh15obl     t0rog7nz   survey           Offer
    +#> 25         ktjz5jli     7bfqtokx dictator ResultsWaitPage
    +#> 26         ktjz5jli     7bfqtokx dictator ResultsWaitPage
    +#> 27         ktjz5jli     7bfqtokx dictator ResultsWaitPage
    +#> 28         ktjz5jli     7bfqtokx dictator ResultsWaitPage
    +#> 29         vbhvhozv     vd1h01iv dictator ResultsWaitPage
    +#> 30         vbhvhozv     vd1h01iv dictator ResultsWaitPage
    +#> 31         vbhvhozv     vd1h01iv dictator ResultsWaitPage
    +#> 32         vbhvhozv     vd1h01iv dictator ResultsWaitPage
    +#> 33         znri6myc     l8ecm1uh dictator    Introduction
    +#> 34         znri6myc     l8ecm1uh dictator    Introduction
    +#> 35         znri6myc     l8ecm1uh dictator    Introduction
    +#> 36         znri6myc     l8ecm1uh dictator    Introduction
    +#>                                                 reason
    +#> 1  Experiment not completed. Noticed at: all_apps_wide
    +#> 2         Experiment not completed. Noticed at: survey
    +#> 3       Experiment not completed. Noticed at: dictator
    +#> 4        Experiment not completed. Noticed at: chatapp
    +#> 5         Experiment not completed. Noticed at: survey
    +#> 6       Experiment not completed. Noticed at: dictator
    +#> 7        Experiment not completed. Noticed at: chatapp
    +#> 8  Experiment not completed. Noticed at: all_apps_wide
    +#> 9         Experiment not completed. Noticed at: survey
    +#> 10      Experiment not completed. Noticed at: dictator
    +#> 11       Experiment not completed. Noticed at: chatapp
    +#> 12 Experiment not completed. Noticed at: all_apps_wide
    +#> 13        Experiment not completed. Noticed at: survey
    +#> 14      Experiment not completed. Noticed at: dictator
    +#> 15       Experiment not completed. Noticed at: chatapp
    +#> 16 Experiment not completed. Noticed at: all_apps_wide
    +#> 17      Experiment not completed. Noticed at: dictator
    +#> 18       Experiment not completed. Noticed at: chatapp
    +#> 19 Experiment not completed. Noticed at: all_apps_wide
    +#> 20        Experiment not completed. Noticed at: survey
    +#> 21       Experiment not completed. Noticed at: chatapp
    +#> 22 Experiment not completed. Noticed at: all_apps_wide
    +#> 23        Experiment not completed. Noticed at: survey
    +#> 24      Experiment not completed. Noticed at: dictator
    +#> 25        Experiment not completed. Noticed at: survey
    +#> 26      Experiment not completed. Noticed at: dictator
    +#> 27       Experiment not completed. Noticed at: chatapp
    +#> 28 Experiment not completed. Noticed at: all_apps_wide
    +#> 29        Experiment not completed. Noticed at: survey
    +#> 30      Experiment not completed. Noticed at: dictator
    +#> 31       Experiment not completed. Noticed at: chatapp
    +#> 32 Experiment not completed. Noticed at: all_apps_wide
    +#> 33        Experiment not completed. Noticed at: survey
    +#> 34      Experiment not completed. Noticed at: dictator
    +#> 35       Experiment not completed. Noticed at: chatapp
    +#> 36 Experiment not completed. Noticed at: all_apps_wide
    +#> 
    +#> $unique
    +#>    participant.code session.code  end_app        end_page
    +#> 1          164r1hs4     7bfqtokx  chatapp            chat
    +#> 5          2scvem7a     vd1h01iv dictator ResultsWaitPage
    +#> 9          7wa8kk3d     l8ecm1uh dictator    Introduction
    +#> 13         ao9kqvqn     l8ecm1uh dictator    Introduction
    +#> 17         d4sq7zio     l8ecm1uh dictator    Introduction
    +#> 21         jxh15obl     t0rog7nz   survey           Offer
    +#> 25         ktjz5jli     7bfqtokx dictator ResultsWaitPage
    +#> 29         vbhvhozv     vd1h01iv dictator ResultsWaitPage
    +#> 33         znri6myc     l8ecm1uh dictator    Introduction
    +#>                      reason
    +#> 1  Experiment not completed
    +#> 5  Experiment not completed
    +#> 9  Experiment not completed
    +#> 13 Experiment not completed
    +#> 17 Experiment not completed
    +#> 21 Experiment not completed
    +#> 25 Experiment not completed
    +#> 29 Experiment not completed
    +#> 33 Experiment not completed
    +#> 
    +#> $all_end
    +#>           
    +#>            Demographics Introduction Offer ResultsWaitPage chat
    +#>   chatapp             0            0     0               0    1
    +#>   dictator            0            4     0               3    0
    +#>   survey             20            0     1               0    0
    +#> 
    +#> $codes
    +#> [1] "164r1hs4" "2scvem7a" "7wa8kk3d" "ao9kqvqn" "d4sq7zio" "jxh15obl" "ktjz5jli"
    +#> [8] "vbhvhozv" "znri6myc"
    +#> 
    +#> $count
    +#> [1] 9
    +#> 
    +
    +# Show everyone who finished with the following apps: "survey," "dictator"
    +final_apps <- unique(oTree$all_apps_wide$participant._current_app_name)
    +final_apps <- final_apps[final_apps != "survey"]
    +final_apps <- final_apps[final_apps != "dictator"]
    +show_dropouts(oTree, final_apps = final_apps)
    +#> $full
    +#>     participant.code session.code  end_app        end_page
    +#> 1           1l5kal0r     t0rog7nz   survey    Demographics
    +#> 2           1l5kal0r     t0rog7nz   survey    Demographics
    +#> 3           1l5kal0r     t0rog7nz   survey    Demographics
    +#> 4           1l5kal0r     t0rog7nz   survey    Demographics
    +#> 5           1mn1kzs7     gii59rga   survey    Demographics
    +#> 6           2d72mfgh     7bfqtokx   survey    Demographics
    +#> 7           2d72mfgh     7bfqtokx   survey    Demographics
    +#> 8           2d72mfgh     7bfqtokx   survey    Demographics
    +#> 9           2d72mfgh     7bfqtokx   survey    Demographics
    +#> 10          2scvem7a     vd1h01iv dictator ResultsWaitPage
    +#> 11          2scvem7a     vd1h01iv dictator ResultsWaitPage
    +#> 12          2scvem7a     vd1h01iv dictator ResultsWaitPage
    +#> 13          2scvem7a     vd1h01iv dictator ResultsWaitPage
    +#> 14          3ttf7yix     7bfqtokx   survey    Demographics
    +#> 15          3ttf7yix     7bfqtokx   survey    Demographics
    +#> 16          3ttf7yix     7bfqtokx   survey    Demographics
    +#> 17          3ttf7yix     7bfqtokx   survey    Demographics
    +#> 18          46kxib6w     7bfqtokx   survey    Demographics
    +#> 19          46kxib6w     7bfqtokx   survey    Demographics
    +#> 20          46kxib6w     7bfqtokx   survey    Demographics
    +#> 21          46kxib6w     7bfqtokx   survey    Demographics
    +#> 22          4zhzdmzo     7bfqtokx   survey    Demographics
    +#> 23          4zhzdmzo     7bfqtokx   survey    Demographics
    +#> 24          4zhzdmzo     7bfqtokx   survey    Demographics
    +#> 25          4zhzdmzo     7bfqtokx   survey    Demographics
    +#> 26          6cim3a5i     gii59rga   survey    Demographics
    +#> 27          7l0hmpcq     qyu3qg0q   survey    Demographics
    +#> 28          7l0hmpcq     qyu3qg0q   survey    Demographics
    +#> 29          7l0hmpcq     qyu3qg0q   survey    Demographics
    +#> 30          7l0hmpcq     qyu3qg0q   survey    Demographics
    +#> 31          7wa8kk3d     l8ecm1uh dictator    Introduction
    +#> 32          7wa8kk3d     l8ecm1uh dictator    Introduction
    +#> 33          7wa8kk3d     l8ecm1uh dictator    Introduction
    +#> 34          7wa8kk3d     l8ecm1uh dictator    Introduction
    +#> 35          a7dppel1     t0rog7nz   survey    Demographics
    +#> 36          a7dppel1     t0rog7nz   survey    Demographics
    +#> 37          a7dppel1     t0rog7nz   survey    Demographics
    +#> 38          a7dppel1     t0rog7nz   survey    Demographics
    +#> 39          ao9kqvqn     l8ecm1uh dictator    Introduction
    +#> 40          ao9kqvqn     l8ecm1uh dictator    Introduction
    +#> 41          ao9kqvqn     l8ecm1uh dictator    Introduction
    +#> 42          ao9kqvqn     l8ecm1uh dictator    Introduction
    +#> 43          byxco6zo     gii59rga   survey    Demographics
    +#> 44          d4sq7zio     l8ecm1uh dictator    Introduction
    +#> 45          d4sq7zio     l8ecm1uh dictator    Introduction
    +#> 46          d4sq7zio     l8ecm1uh dictator    Introduction
    +#> 47          d4sq7zio     l8ecm1uh dictator    Introduction
    +#> 48          ia9rnfvc     qyu3qg0q   survey    Demographics
    +#> 49          ia9rnfvc     qyu3qg0q   survey    Demographics
    +#> 50          ia9rnfvc     qyu3qg0q   survey    Demographics
    +#> 51          ia9rnfvc     qyu3qg0q   survey    Demographics
    +#> 52          iagvtslv     t0rog7nz   survey    Demographics
    +#> 53          iagvtslv     t0rog7nz   survey    Demographics
    +#> 54          iagvtslv     t0rog7nz   survey    Demographics
    +#> 55          iagvtslv     t0rog7nz   survey    Demographics
    +#> 56          iay3dhkn     7bfqtokx   survey    Demographics
    +#> 57          iay3dhkn     7bfqtokx   survey    Demographics
    +#> 58          iay3dhkn     7bfqtokx   survey    Demographics
    +#> 59          iay3dhkn     7bfqtokx   survey    Demographics
    +#> 60          jxh15obl     t0rog7nz   survey           Offer
    +#> 61          jxh15obl     t0rog7nz   survey           Offer
    +#> 62          jxh15obl     t0rog7nz   survey           Offer
    +#> 63          jxh15obl     t0rog7nz   survey           Offer
    +#> 64          ktjz5jli     7bfqtokx dictator ResultsWaitPage
    +#> 65          ktjz5jli     7bfqtokx dictator ResultsWaitPage
    +#> 66          ktjz5jli     7bfqtokx dictator ResultsWaitPage
    +#> 67          ktjz5jli     7bfqtokx dictator ResultsWaitPage
    +#> 68          lsl3vbij     7bfqtokx   survey    Demographics
    +#> 69          lsl3vbij     7bfqtokx   survey    Demographics
    +#> 70          lsl3vbij     7bfqtokx   survey    Demographics
    +#> 71          lsl3vbij     7bfqtokx   survey    Demographics
    +#> 72          rvce7958     7bfqtokx   survey    Demographics
    +#> 73          rvce7958     7bfqtokx   survey    Demographics
    +#> 74          rvce7958     7bfqtokx   survey    Demographics
    +#> 75          rvce7958     7bfqtokx   survey    Demographics
    +#> 76          vbhvhozv     vd1h01iv dictator ResultsWaitPage
    +#> 77          vbhvhozv     vd1h01iv dictator ResultsWaitPage
    +#> 78          vbhvhozv     vd1h01iv dictator ResultsWaitPage
    +#> 79          vbhvhozv     vd1h01iv dictator ResultsWaitPage
    +#> 80          wk247s9w     t0rog7nz   survey    Demographics
    +#> 81          wk247s9w     t0rog7nz   survey    Demographics
    +#> 82          wk247s9w     t0rog7nz   survey    Demographics
    +#> 83          wk247s9w     t0rog7nz   survey    Demographics
    +#> 84          xkobdvuh     t0rog7nz   survey    Demographics
    +#> 85          xkobdvuh     t0rog7nz   survey    Demographics
    +#> 86          xkobdvuh     t0rog7nz   survey    Demographics
    +#> 87          xkobdvuh     t0rog7nz   survey    Demographics
    +#> 88          xmxl46rm     vd1h01iv   survey    Demographics
    +#> 89          xmxl46rm     vd1h01iv   survey    Demographics
    +#> 90          xmxl46rm     vd1h01iv   survey    Demographics
    +#> 91          xmxl46rm     vd1h01iv   survey    Demographics
    +#> 92          xx78b3x0     vd1h01iv   survey    Demographics
    +#> 93          xx78b3x0     vd1h01iv   survey    Demographics
    +#> 94          xx78b3x0     vd1h01iv   survey    Demographics
    +#> 95          xx78b3x0     vd1h01iv   survey    Demographics
    +#> 96          zdki96d6     gii59rga   survey    Demographics
    +#> 97          znri6myc     l8ecm1uh dictator    Introduction
    +#> 98          znri6myc     l8ecm1uh dictator    Introduction
    +#> 99          znri6myc     l8ecm1uh dictator    Introduction
    +#> 100         znri6myc     l8ecm1uh dictator    Introduction
    +#>                                                  reason
    +#> 1         Experiment not completed. Noticed at: chatapp
    +#> 2   Experiment not completed. Noticed at: all_apps_wide
    +#> 3        Experiment not completed. Noticed at: dictator
    +#> 4          Experiment not completed. Noticed at: survey
    +#> 5   Experiment not completed. Noticed at: all_apps_wide
    +#> 6         Experiment not completed. Noticed at: chatapp
    +#> 7   Experiment not completed. Noticed at: all_apps_wide
    +#> 8        Experiment not completed. Noticed at: dictator
    +#> 9          Experiment not completed. Noticed at: survey
    +#> 10         Experiment not completed. Noticed at: survey
    +#> 11  Experiment not completed. Noticed at: all_apps_wide
    +#> 12       Experiment not completed. Noticed at: dictator
    +#> 13        Experiment not completed. Noticed at: chatapp
    +#> 14        Experiment not completed. Noticed at: chatapp
    +#> 15       Experiment not completed. Noticed at: dictator
    +#> 16         Experiment not completed. Noticed at: survey
    +#> 17  Experiment not completed. Noticed at: all_apps_wide
    +#> 18  Experiment not completed. Noticed at: all_apps_wide
    +#> 19       Experiment not completed. Noticed at: dictator
    +#> 20        Experiment not completed. Noticed at: chatapp
    +#> 21         Experiment not completed. Noticed at: survey
    +#> 22        Experiment not completed. Noticed at: chatapp
    +#> 23         Experiment not completed. Noticed at: survey
    +#> 24  Experiment not completed. Noticed at: all_apps_wide
    +#> 25       Experiment not completed. Noticed at: dictator
    +#> 26  Experiment not completed. Noticed at: all_apps_wide
    +#> 27       Experiment not completed. Noticed at: dictator
    +#> 28        Experiment not completed. Noticed at: chatapp
    +#> 29  Experiment not completed. Noticed at: all_apps_wide
    +#> 30         Experiment not completed. Noticed at: survey
    +#> 31        Experiment not completed. Noticed at: chatapp
    +#> 32  Experiment not completed. Noticed at: all_apps_wide
    +#> 33       Experiment not completed. Noticed at: dictator
    +#> 34         Experiment not completed. Noticed at: survey
    +#> 35         Experiment not completed. Noticed at: survey
    +#> 36  Experiment not completed. Noticed at: all_apps_wide
    +#> 37       Experiment not completed. Noticed at: dictator
    +#> 38        Experiment not completed. Noticed at: chatapp
    +#> 39        Experiment not completed. Noticed at: chatapp
    +#> 40  Experiment not completed. Noticed at: all_apps_wide
    +#> 41       Experiment not completed. Noticed at: dictator
    +#> 42         Experiment not completed. Noticed at: survey
    +#> 43  Experiment not completed. Noticed at: all_apps_wide
    +#> 44        Experiment not completed. Noticed at: chatapp
    +#> 45  Experiment not completed. Noticed at: all_apps_wide
    +#> 46       Experiment not completed. Noticed at: dictator
    +#> 47         Experiment not completed. Noticed at: survey
    +#> 48  Experiment not completed. Noticed at: all_apps_wide
    +#> 49       Experiment not completed. Noticed at: dictator
    +#> 50        Experiment not completed. Noticed at: chatapp
    +#> 51         Experiment not completed. Noticed at: survey
    +#> 52        Experiment not completed. Noticed at: chatapp
    +#> 53         Experiment not completed. Noticed at: survey
    +#> 54  Experiment not completed. Noticed at: all_apps_wide
    +#> 55       Experiment not completed. Noticed at: dictator
    +#> 56         Experiment not completed. Noticed at: survey
    +#> 57  Experiment not completed. Noticed at: all_apps_wide
    +#> 58       Experiment not completed. Noticed at: dictator
    +#> 59        Experiment not completed. Noticed at: chatapp
    +#> 60  Experiment not completed. Noticed at: all_apps_wide
    +#> 61       Experiment not completed. Noticed at: dictator
    +#> 62        Experiment not completed. Noticed at: chatapp
    +#> 63         Experiment not completed. Noticed at: survey
    +#> 64        Experiment not completed. Noticed at: chatapp
    +#> 65  Experiment not completed. Noticed at: all_apps_wide
    +#> 66       Experiment not completed. Noticed at: dictator
    +#> 67         Experiment not completed. Noticed at: survey
    +#> 68        Experiment not completed. Noticed at: chatapp
    +#> 69       Experiment not completed. Noticed at: dictator
    +#> 70  Experiment not completed. Noticed at: all_apps_wide
    +#> 71         Experiment not completed. Noticed at: survey
    +#> 72        Experiment not completed. Noticed at: chatapp
    +#> 73  Experiment not completed. Noticed at: all_apps_wide
    +#> 74       Experiment not completed. Noticed at: dictator
    +#> 75         Experiment not completed. Noticed at: survey
    +#> 76  Experiment not completed. Noticed at: all_apps_wide
    +#> 77       Experiment not completed. Noticed at: dictator
    +#> 78        Experiment not completed. Noticed at: chatapp
    +#> 79         Experiment not completed. Noticed at: survey
    +#> 80        Experiment not completed. Noticed at: chatapp
    +#> 81         Experiment not completed. Noticed at: survey
    +#> 82  Experiment not completed. Noticed at: all_apps_wide
    +#> 83       Experiment not completed. Noticed at: dictator
    +#> 84        Experiment not completed. Noticed at: chatapp
    +#> 85       Experiment not completed. Noticed at: dictator
    +#> 86         Experiment not completed. Noticed at: survey
    +#> 87  Experiment not completed. Noticed at: all_apps_wide
    +#> 88       Experiment not completed. Noticed at: dictator
    +#> 89        Experiment not completed. Noticed at: chatapp
    +#> 90  Experiment not completed. Noticed at: all_apps_wide
    +#> 91         Experiment not completed. Noticed at: survey
    +#> 92        Experiment not completed. Noticed at: chatapp
    +#> 93  Experiment not completed. Noticed at: all_apps_wide
    +#> 94       Experiment not completed. Noticed at: dictator
    +#> 95         Experiment not completed. Noticed at: survey
    +#> 96  Experiment not completed. Noticed at: all_apps_wide
    +#> 97        Experiment not completed. Noticed at: chatapp
    +#> 98       Experiment not completed. Noticed at: dictator
    +#> 99  Experiment not completed. Noticed at: all_apps_wide
    +#> 100        Experiment not completed. Noticed at: survey
    +#> 
    +#> $unique
    +#>    participant.code session.code  end_app        end_page
    +#> 1          1l5kal0r     t0rog7nz   survey    Demographics
    +#> 5          1mn1kzs7     gii59rga   survey    Demographics
    +#> 6          2d72mfgh     7bfqtokx   survey    Demographics
    +#> 10         2scvem7a     vd1h01iv dictator ResultsWaitPage
    +#> 14         3ttf7yix     7bfqtokx   survey    Demographics
    +#> 18         46kxib6w     7bfqtokx   survey    Demographics
    +#> 22         4zhzdmzo     7bfqtokx   survey    Demographics
    +#> 26         6cim3a5i     gii59rga   survey    Demographics
    +#> 27         7l0hmpcq     qyu3qg0q   survey    Demographics
    +#> 31         7wa8kk3d     l8ecm1uh dictator    Introduction
    +#> 35         a7dppel1     t0rog7nz   survey    Demographics
    +#> 39         ao9kqvqn     l8ecm1uh dictator    Introduction
    +#> 43         byxco6zo     gii59rga   survey    Demographics
    +#> 44         d4sq7zio     l8ecm1uh dictator    Introduction
    +#> 48         ia9rnfvc     qyu3qg0q   survey    Demographics
    +#> 52         iagvtslv     t0rog7nz   survey    Demographics
    +#> 56         iay3dhkn     7bfqtokx   survey    Demographics
    +#> 60         jxh15obl     t0rog7nz   survey           Offer
    +#> 64         ktjz5jli     7bfqtokx dictator ResultsWaitPage
    +#> 68         lsl3vbij     7bfqtokx   survey    Demographics
    +#> 72         rvce7958     7bfqtokx   survey    Demographics
    +#> 76         vbhvhozv     vd1h01iv dictator ResultsWaitPage
    +#> 80         wk247s9w     t0rog7nz   survey    Demographics
    +#> 84         xkobdvuh     t0rog7nz   survey    Demographics
    +#> 88         xmxl46rm     vd1h01iv   survey    Demographics
    +#> 92         xx78b3x0     vd1h01iv   survey    Demographics
    +#> 96         zdki96d6     gii59rga   survey    Demographics
    +#> 97         znri6myc     l8ecm1uh dictator    Introduction
    +#>                      reason
    +#> 1  Experiment not completed
    +#> 5  Experiment not completed
    +#> 6  Experiment not completed
    +#> 10 Experiment not completed
    +#> 14 Experiment not completed
    +#> 18 Experiment not completed
    +#> 22 Experiment not completed
    +#> 26 Experiment not completed
    +#> 27 Experiment not completed
    +#> 31 Experiment not completed
    +#> 35 Experiment not completed
    +#> 39 Experiment not completed
    +#> 43 Experiment not completed
    +#> 44 Experiment not completed
    +#> 48 Experiment not completed
    +#> 52 Experiment not completed
    +#> 56 Experiment not completed
    +#> 60 Experiment not completed
    +#> 64 Experiment not completed
    +#> 68 Experiment not completed
    +#> 72 Experiment not completed
    +#> 76 Experiment not completed
    +#> 80 Experiment not completed
    +#> 84 Experiment not completed
    +#> 88 Experiment not completed
    +#> 92 Experiment not completed
    +#> 96 Experiment not completed
    +#> 97 Experiment not completed
    +#> 
    +#> $all_end
    +#>           
    +#>            Demographics Introduction Offer ResultsWaitPage chat
    +#>   chatapp             0            0     0               0    1
    +#>   dictator            0            4     0               3    0
    +#>   survey             20            0     1               0    0
    +#> 
    +#> $codes
    +#>  [1] "1l5kal0r" "1mn1kzs7" "2d72mfgh" "2scvem7a" "3ttf7yix" "46kxib6w"
    +#>  [7] "4zhzdmzo" "6cim3a5i" "7l0hmpcq" "7wa8kk3d" "a7dppel1" "ao9kqvqn"
    +#> [13] "byxco6zo" "d4sq7zio" "ia9rnfvc" "iagvtslv" "iay3dhkn" "jxh15obl"
    +#> [19] "ktjz5jli" "lsl3vbij" "rvce7958" "vbhvhozv" "wk247s9w" "xkobdvuh"
    +#> [25] "xmxl46rm" "xx78b3x0" "zdki96d6" "znri6myc"
    +#> 
    +#> $count
    +#> [1] 28
    +#> 
    +
    +
    +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/docs/sitemap.xml b/docs/sitemap.xml new file mode 100644 index 0000000..5fee01f --- /dev/null +++ b/docs/sitemap.xml @@ -0,0 +1,75 @@ + + + + https://zauchnerp.github.io/gmoTree/404.html + + + https://zauchnerp.github.io/gmoTree/articles/index.html + + + https://zauchnerp.github.io/gmoTree/articles/intro_to_gmoTree.html + + + https://zauchnerp.github.io/gmoTree/authors.html + + + https://zauchnerp.github.io/gmoTree/index.html + + + https://zauchnerp.github.io/gmoTree/news/index.html + + + https://zauchnerp.github.io/gmoTree/reference/apptime.html + + + https://zauchnerp.github.io/gmoTree/reference/assignv.html + + + https://zauchnerp.github.io/gmoTree/reference/assignv_to_aaw.html + + + https://zauchnerp.github.io/gmoTree/reference/delete_cases.html + + + https://zauchnerp.github.io/gmoTree/reference/delete_dropouts.html + + + https://zauchnerp.github.io/gmoTree/reference/delete_duplicate.html + + + https://zauchnerp.github.io/gmoTree/reference/delete_plabels.html + + + https://zauchnerp.github.io/gmoTree/reference/delete_sessions.html + + + https://zauchnerp.github.io/gmoTree/reference/extime.html + + + https://zauchnerp.github.io/gmoTree/reference/import_otree.html + + + https://zauchnerp.github.io/gmoTree/reference/index.html + + + https://zauchnerp.github.io/gmoTree/reference/make_ids.html + + + https://zauchnerp.github.io/gmoTree/reference/messy_chat.html + + + https://zauchnerp.github.io/gmoTree/reference/messy_time.html + + + https://zauchnerp.github.io/gmoTree/reference/oTree.html + + + https://zauchnerp.github.io/gmoTree/reference/pagesec.html + + + https://zauchnerp.github.io/gmoTree/reference/show_constant.html + + + https://zauchnerp.github.io/gmoTree/reference/show_dropouts.html + + diff --git a/gmoTree.Rproj b/gmoTree.Rproj new file mode 100644 index 0000000..21a4da0 --- /dev/null +++ b/gmoTree.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 diff --git a/inst/CITATION b/inst/CITATION new file mode 100644 index 0000000..4b5cfea --- /dev/null +++ b/inst/CITATION @@ -0,0 +1,9 @@ +bibentry( + bibtype = "Manual", + title = "gmoTree: oTree Data Manipulation Tool", + author = "Patricia F. Zauchner", + year = "2023", + note = "R package version 0.0.1", + url = "https://github.com/ZauchnerP/gmoTree", + textVersion = "Zauchner, Patricia F. (2023). gmoTree: oTree Data Manipulation Tool. R package version 0.0.1, " +) diff --git a/inst/WORDLIST b/inst/WORDLIST new file mode 100644 index 0000000..d0ef034 --- /dev/null +++ b/inst/WORDLIST @@ -0,0 +1,11 @@ +oTree +YYYY +MTurk +pagesec +pagenames +extime +aaw +del +durations +assignv +import_otree \ No newline at end of file diff --git a/inst/extdata/bot_data/__temp_bots_Apr06_22h26m22.3s/all_apps_wide.csv b/inst/extdata/bot_data/__temp_bots_Apr06_22h26m22.3s/all_apps_wide.csv new file mode 100644 index 0000000..c32ee4e --- /dev/null +++ b/inst/extdata/bot_data/__temp_bots_Apr06_22h26m22.3s/all_apps_wide.csv @@ -0,0 +1,3 @@ +participant.id_in_session,participant.code,participant.label,participant._is_bot,participant._index_in_pages,participant._max_page_index,participant._current_app_name,participant._current_page_name,participant.ip_address,participant.time_started,participant.visited,participant.mturk_worker_id,participant.mturk_assignment_id,participant.payoff,participant.payoff_plus_participation_fee,session.code,session.label,session.experimenter_name,session.mturk_HITId,session.mturk_HITGroupId,session.comment,session.is_demo,session.config.real_world_currency_per_point,session.config.participation_fee,dictator.1.player.id_in_group,dictator.1.player.payoff,dictator.1.group.id_in_subsession,dictator.1.group.kept,dictator.1.subsession.round_number,dictator.2.player.id_in_group,dictator.2.player.payoff,dictator.2.group.id_in_subsession,dictator.2.group.kept,dictator.2.subsession.round_number,dictator.3.player.id_in_group,dictator.3.player.payoff,dictator.3.group.id_in_subsession,dictator.3.group.kept,dictator.3.subsession.round_number,chatapp.1.player.id_in_group,chatapp.1.player.payoff,chatapp.1.group.id_in_subsession,chatapp.1.subsession.round_number,survey.1.player.id_in_group,survey.1.player.age,survey.1.player.gender,survey.1.player.crt_bat,survey.1.player.crt_widget,survey.1.player.crt_lake,survey.1.player.payoff,survey.1.group.id_in_subsession,survey.1.subsession.round_number +1,nbz8a11o,,1,17,16,survey,Demographics,127.0.0.1,2023-04-06 20:26:21.719433+00:00,1,,,297,297.00,xym04r43,,,,,,0,1.0,0.00,1,99,1,99,1,1,99,1,99,2,1,99,1,99,3,1,0,1,1,1,20,Male,1,0,1,0,1,1 +2,wtxqect9,,1,17,16,survey,Demographics,127.0.0.1,2023-04-06 20:26:21.738162+00:00,1,,,3,3.00,xym04r43,,,,,,0,1.0,0.00,2,1,1,99,1,2,1,1,99,2,2,1,1,99,3,2,0,1,1,2,20,Male,1,0,1,0,1,1 diff --git a/inst/extdata/bot_data/__temp_bots_Apr06_22h26m22.3s/chatapp.csv b/inst/extdata/bot_data/__temp_bots_Apr06_22h26m22.3s/chatapp.csv new file mode 100644 index 0000000..6f87605 --- /dev/null +++ b/inst/extdata/bot_data/__temp_bots_Apr06_22h26m22.3s/chatapp.csv @@ -0,0 +1,3 @@ +participant.id_in_session,participant.code,participant.label,participant._is_bot,participant._index_in_pages,participant._max_page_index,participant._current_app_name,participant._current_page_name,participant.ip_address,participant.time_started,participant.visited,participant.mturk_worker_id,participant.mturk_assignment_id,participant.payoff,player.id_in_group,player.payoff,group.id_in_subsession,subsession.round_number,session.code,session.label,session.experimenter_name,session.mturk_HITId,session.mturk_HITGroupId,session.comment,session.is_demo +1,nbz8a11o,,1,17,16,survey,Demographics,127.0.0.1,2023-04-06 20:26:21.719433+00:00,1,,,297,1,0,1,1,xym04r43,,,,,,0 +2,wtxqect9,,1,17,16,survey,Demographics,127.0.0.1,2023-04-06 20:26:21.738162+00:00,1,,,3,2,0,1,1,xym04r43,,,,,,0 diff --git a/inst/extdata/bot_data/__temp_bots_Apr06_22h26m22.3s/dictator.csv b/inst/extdata/bot_data/__temp_bots_Apr06_22h26m22.3s/dictator.csv new file mode 100644 index 0000000..3ff8742 --- /dev/null +++ b/inst/extdata/bot_data/__temp_bots_Apr06_22h26m22.3s/dictator.csv @@ -0,0 +1,7 @@ +participant.id_in_session,participant.code,participant.label,participant._is_bot,participant._index_in_pages,participant._max_page_index,participant._current_app_name,participant._current_page_name,participant.ip_address,participant.time_started,participant.visited,participant.mturk_worker_id,participant.mturk_assignment_id,participant.payoff,player.id_in_group,player.payoff,group.id_in_subsession,group.kept,subsession.round_number,session.code,session.label,session.experimenter_name,session.mturk_HITId,session.mturk_HITGroupId,session.comment,session.is_demo +1,nbz8a11o,,1,17,16,survey,Demographics,127.0.0.1,2023-04-06 20:26:21.719433+00:00,1,,,297,1,99,1,99,1,xym04r43,,,,,,0 +2,wtxqect9,,1,17,16,survey,Demographics,127.0.0.1,2023-04-06 20:26:21.738162+00:00,1,,,3,2,1,1,99,1,xym04r43,,,,,,0 +1,nbz8a11o,,1,17,16,survey,Demographics,127.0.0.1,2023-04-06 20:26:21.719433+00:00,1,,,297,1,99,1,99,2,xym04r43,,,,,,0 +2,wtxqect9,,1,17,16,survey,Demographics,127.0.0.1,2023-04-06 20:26:21.738162+00:00,1,,,3,2,1,1,99,2,xym04r43,,,,,,0 +1,nbz8a11o,,1,17,16,survey,Demographics,127.0.0.1,2023-04-06 20:26:21.719433+00:00,1,,,297,1,99,1,99,3,xym04r43,,,,,,0 +2,wtxqect9,,1,17,16,survey,Demographics,127.0.0.1,2023-04-06 20:26:21.738162+00:00,1,,,3,2,1,1,99,3,xym04r43,,,,,,0 diff --git a/inst/extdata/bot_data/__temp_bots_Apr06_22h26m22.3s/survey.csv b/inst/extdata/bot_data/__temp_bots_Apr06_22h26m22.3s/survey.csv new file mode 100644 index 0000000..f2edbef --- /dev/null +++ b/inst/extdata/bot_data/__temp_bots_Apr06_22h26m22.3s/survey.csv @@ -0,0 +1,3 @@ +participant.id_in_session,participant.code,participant.label,participant._is_bot,participant._index_in_pages,participant._max_page_index,participant._current_app_name,participant._current_page_name,participant.ip_address,participant.time_started,participant.visited,participant.mturk_worker_id,participant.mturk_assignment_id,participant.payoff,player.id_in_group,player.age,player.gender,player.crt_bat,player.crt_widget,player.crt_lake,player.payoff,group.id_in_subsession,subsession.round_number,session.code,session.label,session.experimenter_name,session.mturk_HITId,session.mturk_HITGroupId,session.comment,session.is_demo +1,nbz8a11o,,1,17,16,survey,Demographics,127.0.0.1,2023-04-06 20:26:21.719433+00:00,1,,,297,1,20,Male,1,0,1,0,1,1,xym04r43,,,,,,0 +2,wtxqect9,,1,17,16,survey,Demographics,127.0.0.1,2023-04-06 20:26:21.738162+00:00,1,,,3,2,20,Male,1,0,1,0,1,1,xym04r43,,,,,,0 diff --git a/inst/extdata/empty/empty.txt b/inst/extdata/empty/empty.txt new file mode 100644 index 0000000..fcf00ba --- /dev/null +++ b/inst/extdata/empty/empty.txt @@ -0,0 +1 @@ +This is an empty note so that the folder is included in the package. \ No newline at end of file diff --git a/inst/extdata/exp_data/ChatMessages-2023-03-27.csv b/inst/extdata/exp_data/ChatMessages-2023-03-27.csv new file mode 100644 index 0000000..0c0feb5 --- /dev/null +++ b/inst/extdata/exp_data/ChatMessages-2023-03-27.csv @@ -0,0 +1,36 @@ +session_code,id_in_session,participant_code,channel,nickname,body,timestamp +7bfqtokx,2,iay3dhkn,1-chatapp-1,Participant 2,Hello,1679926176.8622322 +7bfqtokx,1,46kxib6w,1-chatapp-1,Participant 1,Hello,1679926186.2184594 +7bfqtokx,2,iay3dhkn,1-chatapp-1,Participant 2,Sample text 1,1679926199.8832426 +7bfqtokx,1,46kxib6w,1-chatapp-1,Participant 1,Sample text 2,1679926204.4859912 +7bfqtokx,2,iay3dhkn,1-chatapp-1,Participant 2,Goodbye,1679926209.9444165 +7bfqtokx,1,46kxib6w,1-chatapp-1,Participant 1,Goodbye,1679926213.9743862 +7bfqtokx,7,164r1hs4,1-chatapp-4,Participant 1,Hello ,1679926363.357307 +7bfqtokx,8,lsl3vbij,1-chatapp-4,Participant 2,"Hello, how are you? ",1679926369.4993718 +7bfqtokx,7,164r1hs4,1-chatapp-4,Participant 1,I am fine. Sorry for not giving you enough money!,1679926379.5320628 +7bfqtokx,8,lsl3vbij,1-chatapp-4,Participant 2,It's okay,1679926390.1915042 +7bfqtokx,6,rvce7958,1-chatapp-3,Participant 2,Hello,1679926414.5550432 +7bfqtokx,5,2d72mfgh,1-chatapp-3,Participant 1,Hi,1679926418.8008356 +7bfqtokx,6,rvce7958,1-chatapp-3,Participant 2,Sample text^1,1679926423.8744936 +7bfqtokx,5,2d72mfgh,1-chatapp-3,Participant 1,Sample text 2,1679926428.452823 +7bfqtokx,6,rvce7958,1-chatapp-3,Participant 2,Another sample,1679926438.0092793 +7bfqtokx,5,2d72mfgh,1-chatapp-3,Participant 1,yes!!!,1679926443.3187451 +7bfqtokx,3,4zhzdmzo,1-chatapp-2,Participant 1,Hello ,1679926501.626914 +7bfqtokx,4,3ttf7yix,1-chatapp-2,Participant 2,Hello ,1679926505.6700084 +7bfqtokx,3,4zhzdmzo,1-chatapp-2,Participant 1,This ! is my first sample text ^123,1679926515.960473 +7bfqtokx,4,3ttf7yix,1-chatapp-2,Participant 2,This is my second sample text,1679926524.1675825 +7bfqtokx,4,3ttf7yix,1-chatapp-2,Participant 2,"Oh no, my first!!!",1679926530.765887 +vd1h01iv,2,xmxl46rm,2-chatapp-6,Participant 2,Hello,1679926629.190523 +vd1h01iv,1,xx78b3x0,2-chatapp-6,Participant 1,Hello ,1679926632.9810913 +vd1h01iv,2,xmxl46rm,2-chatapp-6,Participant 2,Bye,1679926635.8345468 +vd1h01iv,1,xx78b3x0,2-chatapp-6,Participant 1,Bye,1679926640.3718634 +t0rog7nz,5,xkobdvuh,3-chatapp-10,Participant 1,Helo,1679926744.3719845 +t0rog7nz,6,1l5kal0r,3-chatapp-10,Participant 2,HI,1679926748.6160805 +t0rog7nz,3,a7dppel1,3-chatapp-9,Participant 1,Hello,1679926758.7965178 +t0rog7nz,4,wk247s9w,3-chatapp-9,Participant 2,Hi,1679926762.8595996 +t0rog7nz,2,jxh15obl,3-chatapp-8,Participant 2,67,1679926782.945577 +t0rog7nz,4,wk247s9w,3-chatapp-9,Participant 2,Bye,1679926792.9370947 +qyu3qg0q,1,7l0hmpcq,5-chatapp-14,Participant 1,Hey,1679926951.7375157 +qyu3qg0q,2,ia9rnfvc,5-chatapp-14,Participant 2,Hey,1679926955.5151262 +qyu3qg0q,2,ia9rnfvc,5-chatapp-14,Participant 2,Bye,1679926957.2808733 +qyu3qg0q,1,7l0hmpcq,5-chatapp-14,Participant 1,Bye,1679926960.5997083 diff --git a/inst/extdata/exp_data/PageTimes-2023-03-27.csv b/inst/extdata/exp_data/PageTimes-2023-03-27.csv new file mode 100644 index 0000000..fa7e9e2 --- /dev/null +++ b/inst/extdata/exp_data/PageTimes-2023-03-27.csv @@ -0,0 +1,290 @@ +session_code,participant_id_in_session,participant_code,page_index,app_name,page_name,epoch_time_completed,round_number,timeout_happened,is_wait_page +7bfqtokx,1,46kxib6w,0,,InitializeParticipant,1679926144,1,0,0 +7bfqtokx,2,iay3dhkn,0,,InitializeParticipant,1679926145,1,0,0 +7bfqtokx,3,4zhzdmzo,0,,InitializeParticipant,1679926146,1,0,0 +7bfqtokx,4,3ttf7yix,0,,InitializeParticipant,1679926146,1,0,0 +7bfqtokx,5,2d72mfgh,0,,InitializeParticipant,1679926147,1,0,0 +7bfqtokx,6,rvce7958,0,,InitializeParticipant,1679926147,1,0,0 +7bfqtokx,7,164r1hs4,0,,InitializeParticipant,1679926148,1,0,0 +7bfqtokx,8,lsl3vbij,0,,InitializeParticipant,1679926148,1,0,0 +7bfqtokx,9,ktjz5jli,0,,InitializeParticipant,1679926149,1,0,0 +7bfqtokx,1,46kxib6w,1,dictator,Introduction,1679926151,1,0,0 +7bfqtokx,1,46kxib6w,2,dictator,Offer,1679926154,1,0,0 +7bfqtokx,2,iay3dhkn,1,dictator,Introduction,1679926156,1,0,0 +7bfqtokx,1,46kxib6w,3,dictator,ResultsWaitPage,1679926156,1,0,1 +7bfqtokx,2,iay3dhkn,3,dictator,ResultsWaitPage,1679926156,1,0,1 +7bfqtokx,2,iay3dhkn,4,dictator,Results,1679926157,1,0,0 +7bfqtokx,2,iay3dhkn,5,dictator,Introduction,1679926158,2,0,0 +7bfqtokx,1,46kxib6w,4,dictator,Results,1679926160,1,0,0 +7bfqtokx,1,46kxib6w,5,dictator,Introduction,1679926162,2,0,0 +7bfqtokx,1,46kxib6w,6,dictator,Offer,1679926165,2,0,0 +7bfqtokx,1,46kxib6w,7,dictator,ResultsWaitPage,1679926165,2,0,1 +7bfqtokx,2,iay3dhkn,7,dictator,ResultsWaitPage,1679926165,2,0,1 +7bfqtokx,1,46kxib6w,8,dictator,Results,1679926166,2,0,0 +7bfqtokx,1,46kxib6w,9,dictator,Introduction,1679926167,3,0,0 +7bfqtokx,1,46kxib6w,10,dictator,Offer,1679926169,3,0,0 +7bfqtokx,2,iay3dhkn,8,dictator,Results,1679926171,2,0,0 +7bfqtokx,2,iay3dhkn,9,dictator,Introduction,1679926172,3,0,0 +7bfqtokx,1,46kxib6w,11,dictator,ResultsWaitPage,1679926172,3,0,1 +7bfqtokx,2,iay3dhkn,11,dictator,ResultsWaitPage,1679926172,3,0,1 +7bfqtokx,2,iay3dhkn,12,dictator,Results,1679926173,3,0,0 +7bfqtokx,1,46kxib6w,12,dictator,Results,1679926178,3,0,0 +7bfqtokx,3,4zhzdmzo,1,dictator,Introduction,1679926188,1,0,0 +7bfqtokx,3,4zhzdmzo,2,dictator,Offer,1679926190,1,0,0 +7bfqtokx,1,46kxib6w,13,chatapp,chat,1679926215,1,0,0 +7bfqtokx,1,46kxib6w,14,survey,CognitiveReflectionTest,1679926276,1,0,0 +7bfqtokx,1,46kxib6w,15,survey,Offer,1679926277,1,0,0 +7bfqtokx,1,46kxib6w,16,survey,Demographics,1679926283,1,0,0 +7bfqtokx,2,iay3dhkn,13,chatapp,chat,1679926285,1,0,0 +7bfqtokx,2,iay3dhkn,14,survey,CognitiveReflectionTest,1679926291,1,0,0 +7bfqtokx,2,iay3dhkn,15,survey,Offer,1679926293,1,0,0 +7bfqtokx,2,iay3dhkn,16,survey,Demographics,1679926298,1,0,0 +7bfqtokx,4,3ttf7yix,1,dictator,Introduction,1679926301,1,0,0 +7bfqtokx,3,4zhzdmzo,3,dictator,ResultsWaitPage,1679926301,1,0,1 +7bfqtokx,4,3ttf7yix,3,dictator,ResultsWaitPage,1679926301,1,0,1 +7bfqtokx,4,3ttf7yix,4,dictator,Results,1679926303,1,0,0 +7bfqtokx,4,3ttf7yix,5,dictator,Introduction,1679926304,2,0,0 +7bfqtokx,5,2d72mfgh,1,dictator,Introduction,1679926306,1,0,0 +7bfqtokx,5,2d72mfgh,2,dictator,Offer,1679926308,1,0,0 +7bfqtokx,6,rvce7958,1,dictator,Introduction,1679926309,1,0,0 +7bfqtokx,5,2d72mfgh,3,dictator,ResultsWaitPage,1679926309,1,0,1 +7bfqtokx,6,rvce7958,3,dictator,ResultsWaitPage,1679926309,1,0,1 +7bfqtokx,7,164r1hs4,1,dictator,Introduction,1679926311,1,0,0 +7bfqtokx,7,164r1hs4,2,dictator,Offer,1679926314,1,0,0 +7bfqtokx,8,lsl3vbij,1,dictator,Introduction,1679926315,1,0,0 +7bfqtokx,7,164r1hs4,3,dictator,ResultsWaitPage,1679926315,1,0,1 +7bfqtokx,8,lsl3vbij,3,dictator,ResultsWaitPage,1679926315,1,0,1 +7bfqtokx,8,lsl3vbij,4,dictator,Results,1679926316,1,0,0 +7bfqtokx,8,lsl3vbij,5,dictator,Introduction,1679926317,2,0,0 +7bfqtokx,9,ktjz5jli,1,dictator,Introduction,1679926319,1,0,0 +7bfqtokx,9,ktjz5jli,2,dictator,Offer,1679926322,1,0,0 +7bfqtokx,7,164r1hs4,4,dictator,Results,1679926325,1,0,0 +7bfqtokx,7,164r1hs4,5,dictator,Introduction,1679926327,2,0,0 +7bfqtokx,7,164r1hs4,6,dictator,Offer,1679926329,2,0,0 +7bfqtokx,7,164r1hs4,7,dictator,ResultsWaitPage,1679926330,2,0,1 +7bfqtokx,8,lsl3vbij,7,dictator,ResultsWaitPage,1679926330,2,0,1 +7bfqtokx,6,rvce7958,4,dictator,Results,1679926331,1,0,0 +7bfqtokx,6,rvce7958,5,dictator,Introduction,1679926332,2,0,0 +7bfqtokx,5,2d72mfgh,4,dictator,Results,1679926334,1,0,0 +7bfqtokx,5,2d72mfgh,5,dictator,Introduction,1679926335,2,0,0 +7bfqtokx,5,2d72mfgh,6,dictator,Offer,1679926341,2,0,0 +7bfqtokx,5,2d72mfgh,7,dictator,ResultsWaitPage,1679926341,2,0,1 +7bfqtokx,6,rvce7958,7,dictator,ResultsWaitPage,1679926341,2,0,1 +7bfqtokx,5,2d72mfgh,8,dictator,Results,1679926342,2,0,0 +7bfqtokx,6,rvce7958,8,dictator,Results,1679926344,2,0,0 +7bfqtokx,6,rvce7958,9,dictator,Introduction,1679926345,3,0,0 +7bfqtokx,7,164r1hs4,8,dictator,Results,1679926347,2,0,0 +7bfqtokx,7,164r1hs4,9,dictator,Introduction,1679926348,3,0,0 +7bfqtokx,7,164r1hs4,10,dictator,Offer,1679926351,3,0,0 +7bfqtokx,8,lsl3vbij,8,dictator,Results,1679926352,2,0,0 +7bfqtokx,8,lsl3vbij,9,dictator,Introduction,1679926353,3,0,0 +7bfqtokx,7,164r1hs4,11,dictator,ResultsWaitPage,1679926353,3,0,1 +7bfqtokx,8,lsl3vbij,11,dictator,ResultsWaitPage,1679926353,3,0,1 +7bfqtokx,8,lsl3vbij,12,dictator,Results,1679926355,3,0,0 +7bfqtokx,7,164r1hs4,12,dictator,Results,1679926360,3,0,0 +7bfqtokx,8,lsl3vbij,13,chatapp,chat,1679926391,1,0,0 +7bfqtokx,8,lsl3vbij,14,survey,CognitiveReflectionTest,1679926394,1,0,0 +7bfqtokx,8,lsl3vbij,15,survey,Offer,1679926396,1,0,0 +7bfqtokx,8,lsl3vbij,16,survey,Demographics,1679926399,1,0,0 +7bfqtokx,5,2d72mfgh,9,dictator,Introduction,1679926403,3,0,0 +7bfqtokx,5,2d72mfgh,10,dictator,Offer,1679926407,3,0,0 +7bfqtokx,5,2d72mfgh,11,dictator,ResultsWaitPage,1679926407,3,0,1 +7bfqtokx,6,rvce7958,11,dictator,ResultsWaitPage,1679926407,3,0,1 +7bfqtokx,6,rvce7958,12,dictator,Results,1679926409,3,0,0 +7bfqtokx,5,2d72mfgh,12,dictator,Results,1679926416,3,0,0 +7bfqtokx,3,4zhzdmzo,4,dictator,Results,1679926446,1,0,0 +7bfqtokx,3,4zhzdmzo,5,dictator,Introduction,1679926447,2,0,0 +7bfqtokx,3,4zhzdmzo,6,dictator,Offer,1679926449,2,0,0 +7bfqtokx,3,4zhzdmzo,7,dictator,ResultsWaitPage,1679926449,2,0,1 +7bfqtokx,4,3ttf7yix,7,dictator,ResultsWaitPage,1679926449,2,0,1 +7bfqtokx,3,4zhzdmzo,8,dictator,Results,1679926450,2,0,0 +7bfqtokx,3,4zhzdmzo,9,dictator,Introduction,1679926451,3,0,0 +7bfqtokx,4,3ttf7yix,8,dictator,Results,1679926455,2,0,0 +7bfqtokx,4,3ttf7yix,9,dictator,Introduction,1679926456,3,0,0 +7bfqtokx,5,2d72mfgh,13,chatapp,chat,1679926462,1,0,0 +7bfqtokx,5,2d72mfgh,14,survey,CognitiveReflectionTest,1679926465,1,0,0 +7bfqtokx,5,2d72mfgh,15,survey,Offer,1679926467,1,0,0 +7bfqtokx,5,2d72mfgh,16,survey,Demographics,1679926470,1,0,0 +7bfqtokx,6,rvce7958,13,chatapp,chat,1679926474,1,0,0 +7bfqtokx,6,rvce7958,14,survey,CognitiveReflectionTest,1679926480,1,0,0 +7bfqtokx,6,rvce7958,15,survey,Offer,1679926482,1,0,0 +7bfqtokx,6,rvce7958,16,survey,Demographics,1679926487,1,0,0 +7bfqtokx,3,4zhzdmzo,10,dictator,Offer,1679926497,3,0,0 +7bfqtokx,3,4zhzdmzo,11,dictator,ResultsWaitPage,1679926497,3,0,1 +7bfqtokx,4,3ttf7yix,11,dictator,ResultsWaitPage,1679926497,3,0,1 +7bfqtokx,3,4zhzdmzo,12,dictator,Results,1679926498,3,0,0 +7bfqtokx,4,3ttf7yix,12,dictator,Results,1679926503,3,0,0 +7bfqtokx,4,3ttf7yix,13,chatapp,chat,1679926537,1,0,0 +7bfqtokx,4,3ttf7yix,14,survey,CognitiveReflectionTest,1679926542,1,0,0 +7bfqtokx,3,4zhzdmzo,13,chatapp,chat,1679926544,1,0,0 +7bfqtokx,3,4zhzdmzo,14,survey,CognitiveReflectionTest,1679926548,1,0,0 +7bfqtokx,3,4zhzdmzo,15,survey,Offer,1679926549,1,0,0 +7bfqtokx,3,4zhzdmzo,16,survey,Demographics,1679926553,1,0,0 +7bfqtokx,4,3ttf7yix,15,survey,Offer,1679926558,1,0,0 +7bfqtokx,4,3ttf7yix,16,survey,Demographics,1679926562,1,0,0 +vd1h01iv,1,xx78b3x0,0,,InitializeParticipant,1679926587,1,0,0 +vd1h01iv,2,xmxl46rm,0,,InitializeParticipant,1679926587,1,0,0 +vd1h01iv,3,vbhvhozv,0,,InitializeParticipant,1679926588,1,0,0 +vd1h01iv,4,2scvem7a,0,,InitializeParticipant,1679926588,1,0,0 +vd1h01iv,1,xx78b3x0,1,dictator,Introduction,1679926590,1,0,0 +vd1h01iv,1,xx78b3x0,2,dictator,Offer,1679926594,1,0,0 +vd1h01iv,2,xmxl46rm,1,dictator,Introduction,1679926597,1,0,0 +vd1h01iv,1,xx78b3x0,3,dictator,ResultsWaitPage,1679926597,1,0,1 +vd1h01iv,2,xmxl46rm,3,dictator,ResultsWaitPage,1679926597,1,0,1 +vd1h01iv,2,xmxl46rm,4,dictator,Results,1679926598,1,0,0 +vd1h01iv,2,xmxl46rm,5,dictator,Introduction,1679926599,2,0,0 +vd1h01iv,3,vbhvhozv,1,dictator,Introduction,1679926603,1,0,0 +vd1h01iv,3,vbhvhozv,2,dictator,Offer,1679926606,1,0,0 +vd1h01iv,1,xx78b3x0,4,dictator,Results,1679926607,1,0,0 +vd1h01iv,1,xx78b3x0,5,dictator,Introduction,1679926608,2,0,0 +vd1h01iv,4,2scvem7a,1,dictator,Introduction,1679926612,1,0,0 +vd1h01iv,3,vbhvhozv,3,dictator,ResultsWaitPage,1679926612,1,0,1 +vd1h01iv,4,2scvem7a,3,dictator,ResultsWaitPage,1679926612,1,0,1 +vd1h01iv,4,2scvem7a,4,dictator,Results,1679926613,1,0,0 +vd1h01iv,4,2scvem7a,5,dictator,Introduction,1679926614,2,0,0 +vd1h01iv,1,xx78b3x0,6,dictator,Offer,1679926617,2,0,0 +vd1h01iv,1,xx78b3x0,7,dictator,ResultsWaitPage,1679926618,2,0,1 +vd1h01iv,2,xmxl46rm,7,dictator,ResultsWaitPage,1679926618,2,0,1 +vd1h01iv,1,xx78b3x0,8,dictator,Results,1679926618,2,0,0 +vd1h01iv,1,xx78b3x0,9,dictator,Introduction,1679926619,3,0,0 +vd1h01iv,1,xx78b3x0,10,dictator,Offer,1679926622,3,0,0 +vd1h01iv,2,xmxl46rm,8,dictator,Results,1679926624,2,0,0 +vd1h01iv,2,xmxl46rm,9,dictator,Introduction,1679926625,3,0,0 +vd1h01iv,1,xx78b3x0,11,dictator,ResultsWaitPage,1679926625,3,0,1 +vd1h01iv,2,xmxl46rm,11,dictator,ResultsWaitPage,1679926625,3,0,1 +vd1h01iv,2,xmxl46rm,12,dictator,Results,1679926626,3,0,0 +vd1h01iv,1,xx78b3x0,12,dictator,Results,1679926630,3,0,0 +vd1h01iv,1,xx78b3x0,13,chatapp,chat,1679926642,1,0,0 +vd1h01iv,1,xx78b3x0,14,survey,CognitiveReflectionTest,1679926647,1,0,0 +vd1h01iv,1,xx78b3x0,15,survey,Offer,1679926648,1,0,0 +vd1h01iv,1,xx78b3x0,16,survey,Demographics,1679926652,1,0,0 +vd1h01iv,2,xmxl46rm,13,chatapp,chat,1679926653,1,0,0 +vd1h01iv,2,xmxl46rm,14,survey,CognitiveReflectionTest,1679926657,1,0,0 +vd1h01iv,2,xmxl46rm,15,survey,Offer,1679926658,1,0,0 +vd1h01iv,2,xmxl46rm,16,survey,Demographics,1679926662,1,0,0 +t0rog7nz,1,iagvtslv,0,,InitializeParticipant,1679926684,1,0,0 +t0rog7nz,2,jxh15obl,0,,InitializeParticipant,1679926684,1,0,0 +t0rog7nz,3,a7dppel1,0,,InitializeParticipant,1679926685,1,0,0 +t0rog7nz,4,wk247s9w,0,,InitializeParticipant,1679926688,1,0,0 +t0rog7nz,5,xkobdvuh,0,,InitializeParticipant,1679926688,1,0,0 +t0rog7nz,6,1l5kal0r,0,,InitializeParticipant,1679926689,1,0,0 +t0rog7nz,1,iagvtslv,1,dictator,Introduction,1679926691,1,0,0 +t0rog7nz,1,iagvtslv,2,dictator,Offer,1679926694,1,0,0 +t0rog7nz,2,jxh15obl,1,dictator,Introduction,1679926696,1,0,0 +t0rog7nz,1,iagvtslv,3,dictator,ResultsWaitPage,1679926696,1,0,1 +t0rog7nz,2,jxh15obl,3,dictator,ResultsWaitPage,1679926696,1,0,1 +t0rog7nz,3,a7dppel1,1,dictator,Introduction,1679926697,1,0,0 +t0rog7nz,4,wk247s9w,1,dictator,Introduction,1679926699,1,0,0 +t0rog7nz,5,xkobdvuh,1,dictator,Introduction,1679926700,1,0,0 +t0rog7nz,6,1l5kal0r,1,dictator,Introduction,1679926701,1,0,0 +t0rog7nz,5,xkobdvuh,2,dictator,Offer,1679926704,1,0,0 +t0rog7nz,5,xkobdvuh,3,dictator,ResultsWaitPage,1679926704,1,0,1 +t0rog7nz,6,1l5kal0r,3,dictator,ResultsWaitPage,1679926704,1,0,1 +t0rog7nz,5,xkobdvuh,4,dictator,Results,1679926705,1,0,0 +t0rog7nz,5,xkobdvuh,5,dictator,Introduction,1679926706,2,0,0 +t0rog7nz,5,xkobdvuh,6,dictator,Offer,1679926712,2,0,0 +t0rog7nz,3,a7dppel1,2,dictator,Offer,1679926717,1,0,0 +t0rog7nz,3,a7dppel1,3,dictator,ResultsWaitPage,1679926717,1,0,1 +t0rog7nz,4,wk247s9w,3,dictator,ResultsWaitPage,1679926717,1,0,1 +t0rog7nz,3,a7dppel1,4,dictator,Results,1679926718,1,0,0 +t0rog7nz,3,a7dppel1,5,dictator,Introduction,1679926720,2,0,0 +t0rog7nz,3,a7dppel1,6,dictator,Offer,1679926722,2,0,0 +t0rog7nz,4,wk247s9w,4,dictator,Results,1679926724,1,0,0 +t0rog7nz,4,wk247s9w,5,dictator,Introduction,1679926725,2,0,0 +t0rog7nz,3,a7dppel1,7,dictator,ResultsWaitPage,1679926725,2,0,1 +t0rog7nz,4,wk247s9w,7,dictator,ResultsWaitPage,1679926725,2,0,1 +t0rog7nz,4,wk247s9w,8,dictator,Results,1679926727,2,0,0 +t0rog7nz,6,1l5kal0r,4,dictator,Results,1679926728,1,0,0 +t0rog7nz,6,1l5kal0r,5,dictator,Introduction,1679926730,2,0,0 +t0rog7nz,5,xkobdvuh,7,dictator,ResultsWaitPage,1679926730,2,0,1 +t0rog7nz,6,1l5kal0r,7,dictator,ResultsWaitPage,1679926730,2,0,1 +t0rog7nz,6,1l5kal0r,8,dictator,Results,1679926731,2,0,0 +t0rog7nz,6,1l5kal0r,9,dictator,Introduction,1679926733,3,0,0 +t0rog7nz,5,xkobdvuh,8,dictator,Results,1679926734,2,0,0 +t0rog7nz,4,wk247s9w,9,dictator,Introduction,1679926735,3,0,0 +t0rog7nz,5,xkobdvuh,9,dictator,Introduction,1679926737,3,0,0 +t0rog7nz,5,xkobdvuh,10,dictator,Offer,1679926739,3,0,0 +t0rog7nz,5,xkobdvuh,11,dictator,ResultsWaitPage,1679926739,3,0,1 +t0rog7nz,6,1l5kal0r,11,dictator,ResultsWaitPage,1679926739,3,0,1 +t0rog7nz,5,xkobdvuh,12,dictator,Results,1679926742,3,0,0 +t0rog7nz,6,1l5kal0r,12,dictator,Results,1679926746,3,0,0 +t0rog7nz,3,a7dppel1,8,dictator,Results,1679926751,2,0,0 +t0rog7nz,3,a7dppel1,9,dictator,Introduction,1679926752,3,0,0 +t0rog7nz,3,a7dppel1,10,dictator,Offer,1679926754,3,0,0 +t0rog7nz,3,a7dppel1,11,dictator,ResultsWaitPage,1679926754,3,0,1 +t0rog7nz,4,wk247s9w,11,dictator,ResultsWaitPage,1679926754,3,0,1 +t0rog7nz,3,a7dppel1,12,dictator,Results,1679926755,3,0,0 +t0rog7nz,4,wk247s9w,12,dictator,Results,1679926760,3,0,0 +t0rog7nz,2,jxh15obl,4,dictator,Results,1679926764,1,0,0 +t0rog7nz,2,jxh15obl,5,dictator,Introduction,1679926765,2,0,0 +t0rog7nz,1,iagvtslv,4,dictator,Results,1679926767,1,0,0 +t0rog7nz,1,iagvtslv,5,dictator,Introduction,1679926768,2,0,0 +t0rog7nz,1,iagvtslv,6,dictator,Offer,1679926770,2,0,0 +t0rog7nz,1,iagvtslv,7,dictator,ResultsWaitPage,1679926770,2,0,1 +t0rog7nz,2,jxh15obl,7,dictator,ResultsWaitPage,1679926770,2,0,1 +t0rog7nz,1,iagvtslv,8,dictator,Results,1679926771,2,0,0 +t0rog7nz,1,iagvtslv,9,dictator,Introduction,1679926772,3,0,0 +t0rog7nz,1,iagvtslv,10,dictator,Offer,1679926774,3,0,0 +t0rog7nz,2,jxh15obl,8,dictator,Results,1679926777,2,0,0 +t0rog7nz,2,jxh15obl,9,dictator,Introduction,1679926778,3,0,0 +t0rog7nz,1,iagvtslv,11,dictator,ResultsWaitPage,1679926778,3,0,1 +t0rog7nz,2,jxh15obl,11,dictator,ResultsWaitPage,1679926778,3,0,1 +t0rog7nz,2,jxh15obl,12,dictator,Results,1679926779,3,0,0 +t0rog7nz,2,jxh15obl,13,chatapp,chat,1679926783,1,0,0 +t0rog7nz,2,jxh15obl,14,survey,CognitiveReflectionTest,1679926788,1,0,0 +t0rog7nz,3,a7dppel1,13,chatapp,chat,1679926790,1,0,0 +t0rog7nz,4,wk247s9w,13,chatapp,chat,1679926794,1,0,0 +t0rog7nz,3,a7dppel1,14,survey,CognitiveReflectionTest,1679926799,1,0,0 +t0rog7nz,3,a7dppel1,15,survey,Offer,1679926800,1,0,0 +t0rog7nz,3,a7dppel1,16,survey,Demographics,1679926804,1,0,0 +t0rog7nz,5,xkobdvuh,13,chatapp,chat,1679926806,1,0,0 +t0rog7nz,4,wk247s9w,14,survey,CognitiveReflectionTest,1679926810,1,0,0 +t0rog7nz,6,1l5kal0r,13,chatapp,chat,1679926812,1,0,0 +t0rog7nz,6,1l5kal0r,14,survey,CognitiveReflectionTest,1679926816,1,0,0 +t0rog7nz,6,1l5kal0r,15,survey,Offer,1679926817,1,0,0 +t0rog7nz,6,1l5kal0r,16,survey,Demographics,1679926820,1,0,0 +t0rog7nz,5,xkobdvuh,14,survey,CognitiveReflectionTest,1679926825,1,0,0 +t0rog7nz,5,xkobdvuh,15,survey,Offer,1679926826,1,0,0 +t0rog7nz,5,xkobdvuh,16,survey,Demographics,1679926830,1,0,0 +t0rog7nz,4,wk247s9w,15,survey,Offer,1679926832,1,0,0 +t0rog7nz,4,wk247s9w,16,survey,Demographics,1679926838,1,0,0 +t0rog7nz,1,iagvtslv,12,dictator,Results,1679926843,3,0,0 +t0rog7nz,1,iagvtslv,13,chatapp,chat,1679926844,1,0,0 +t0rog7nz,1,iagvtslv,14,survey,CognitiveReflectionTest,1679926848,1,0,0 +t0rog7nz,1,iagvtslv,15,survey,Offer,1679926849,1,0,0 +t0rog7nz,1,iagvtslv,16,survey,Demographics,1679926853,1,0,0 +l8ecm1uh,1,7wa8kk3d,0,,InitializeParticipant,1679926871,1,0,0 +l8ecm1uh,2,znri6myc,0,,InitializeParticipant,1679926872,1,0,0 +l8ecm1uh,3,ao9kqvqn,0,,InitializeParticipant,1679926872,1,0,0 +l8ecm1uh,4,d4sq7zio,0,,InitializeParticipant,1679926873,1,0,0 +qyu3qg0q,1,7l0hmpcq,0,,InitializeParticipant,1679926923,1,0,0 +qyu3qg0q,2,ia9rnfvc,0,,InitializeParticipant,1679926923,1,0,0 +qyu3qg0q,2,ia9rnfvc,1,dictator,Introduction,1679926930,1,0,0 +qyu3qg0q,1,7l0hmpcq,1,dictator,Introduction,1679926932,1,0,0 +qyu3qg0q,1,7l0hmpcq,2,dictator,Offer,1679926935,1,0,0 +qyu3qg0q,1,7l0hmpcq,3,dictator,ResultsWaitPage,1679926935,1,0,1 +qyu3qg0q,2,ia9rnfvc,3,dictator,ResultsWaitPage,1679926935,1,0,1 +qyu3qg0q,1,7l0hmpcq,4,dictator,Results,1679926935,1,0,0 +qyu3qg0q,1,7l0hmpcq,5,dictator,Introduction,1679926936,2,0,0 +qyu3qg0q,1,7l0hmpcq,6,dictator,Offer,1679926938,2,0,0 +qyu3qg0q,2,ia9rnfvc,4,dictator,Results,1679926940,1,0,0 +qyu3qg0q,2,ia9rnfvc,5,dictator,Introduction,1679926941,2,0,0 +qyu3qg0q,1,7l0hmpcq,7,dictator,ResultsWaitPage,1679926941,2,0,1 +qyu3qg0q,2,ia9rnfvc,7,dictator,ResultsWaitPage,1679926941,2,0,1 +qyu3qg0q,2,ia9rnfvc,8,dictator,Results,1679926942,2,0,0 +qyu3qg0q,2,ia9rnfvc,9,dictator,Introduction,1679926943,3,0,0 +qyu3qg0q,1,7l0hmpcq,8,dictator,Results,1679926945,2,0,0 +qyu3qg0q,1,7l0hmpcq,9,dictator,Introduction,1679926946,3,0,0 +qyu3qg0q,1,7l0hmpcq,10,dictator,Offer,1679926948,3,0,0 +qyu3qg0q,1,7l0hmpcq,11,dictator,ResultsWaitPage,1679926948,3,0,1 +qyu3qg0q,2,ia9rnfvc,11,dictator,ResultsWaitPage,1679926948,3,0,1 +qyu3qg0q,1,7l0hmpcq,12,dictator,Results,1679926949,3,0,0 +qyu3qg0q,2,ia9rnfvc,12,dictator,Results,1679926953,3,0,0 +qyu3qg0q,1,7l0hmpcq,13,chatapp,chat,1679926961,1,0,0 +qyu3qg0q,1,7l0hmpcq,14,survey,CognitiveReflectionTest,1679926966,1,0,0 +qyu3qg0q,1,7l0hmpcq,15,survey,Offer,1679926967,1,0,0 +qyu3qg0q,1,7l0hmpcq,16,survey,Demographics,1679926970,1,0,0 +qyu3qg0q,2,ia9rnfvc,13,chatapp,chat,1679926986,1,0,0 +qyu3qg0q,2,ia9rnfvc,14,survey,CognitiveReflectionTest,1679926990,1,0,0 +qyu3qg0q,2,ia9rnfvc,15,survey,Offer,1679926991,1,0,0 +qyu3qg0q,2,ia9rnfvc,16,survey,Demographics,1679926995,1,0,0 diff --git a/inst/extdata/exp_data/all_apps_wide-2023-03-27.csv b/inst/extdata/exp_data/all_apps_wide-2023-03-27.csv new file mode 100644 index 0000000..13eb3af --- /dev/null +++ b/inst/extdata/exp_data/all_apps_wide-2023-03-27.csv @@ -0,0 +1,5 @@ +participant.id_in_session,participant.code,participant.label,participant._is_bot,participant._index_in_pages,participant._max_page_index,participant._current_app_name,participant._current_page_name,participant.time_started_utc,participant.visited,participant.mturk_worker_id,participant.mturk_assignment_id,participant.payoff,session.code,session.label,session.mturk_HITId,session.mturk_HITGroupId,session.comment,session.is_demo,session.config.name,session.config.real_world_currency_per_point,session.config.participation_fee,dictator.1.player.id_in_group,dictator.1.player.role,dictator.1.player.payoff,dictator.1.group.id_in_subsession,dictator.1.group.kept,dictator.1.subsession.round_number,dictator.2.player.id_in_group,dictator.2.player.role,dictator.2.player.payoff,dictator.2.group.id_in_subsession,dictator.2.group.kept,dictator.2.subsession.round_number,dictator.3.player.id_in_group,dictator.3.player.role,dictator.3.player.payoff,dictator.3.group.id_in_subsession,dictator.3.group.kept,dictator.3.subsession.round_number,chatapp.1.player.id_in_group,chatapp.1.player.role,chatapp.1.player.payoff,chatapp.1.group.id_in_subsession,chatapp.1.subsession.round_number,survey.1.player.id_in_group,survey.1.player.role,survey.1.player.payoff,survey.1.player.age,survey.1.player.gender,survey.1.player.crt_bat,survey.1.player.crt_widget,survey.1.player.crt_lake,survey.1.group.id_in_subsession,survey.1.subsession.round_number +1,6cim3a5i,,0,17,16,survey,Demographics,2023-03-27 14:31:59.669977,1,,,140.0,gii59rga,,,,,0,dictator,1.0,0.0,1,,23.0,1,23.0,1,1,,50.0,1,50.0,2,1,,67.0,1,67.0,3,1,,0.0,1,1,1,,0.0,23,Female,1,2,3,1,1 +2,1mn1kzs7,,0,17,16,survey,Demographics,2023-03-27 14:32:00.061250,1,,,160.0,gii59rga,,,,,0,dictator,1.0,0.0,2,,77.0,1,23.0,1,2,,50.0,1,50.0,2,2,,33.0,1,67.0,3,2,,0.0,1,1,2,,0.0,23,Female,1,1,46,1,1 +3,zdki96d6,,0,17,16,survey,Demographics,2023-03-27 14:32:00.421416,1,,,167.0,gii59rga,,,,,0,dictator,1.0,0.0,1,,67.0,2,67.0,1,1,,45.0,2,45.0,2,1,,55.0,2,55.0,3,1,,0.0,2,1,3,,0.0,20,Female,1,1,47,1,1 +4,byxco6zo,,0,17,16,survey,Demographics,2023-03-27 14:32:00.766282,1,,,133.0,gii59rga,,,,,0,dictator,1.0,0.0,2,,33.0,2,67.0,1,2,,55.0,2,45.0,2,2,,45.0,2,55.0,3,2,,0.0,2,1,4,,0.0,23,Male,1,1,34,1,1 diff --git a/inst/extdata/exp_data/all_apps_wide_2023-03-27.csv b/inst/extdata/exp_data/all_apps_wide_2023-03-27.csv new file mode 100644 index 0000000..da75d36 --- /dev/null +++ b/inst/extdata/exp_data/all_apps_wide_2023-03-27.csv @@ -0,0 +1,31 @@ +participant.id_in_session,participant.code,participant.label,participant._is_bot,participant._index_in_pages,participant._max_page_index,participant._current_app_name,participant._current_page_name,participant.time_started_utc,participant.visited,participant.mturk_worker_id,participant.mturk_assignment_id,participant.payoff,session.code,session.label,session.mturk_HITId,session.mturk_HITGroupId,session.comment,session.is_demo,session.config.name,session.config.real_world_currency_per_point,session.config.participation_fee,dictator.1.player.id_in_group,dictator.1.player.role,dictator.1.player.payoff,dictator.1.group.id_in_subsession,dictator.1.group.kept,dictator.1.subsession.round_number,dictator.2.player.id_in_group,dictator.2.player.role,dictator.2.player.payoff,dictator.2.group.id_in_subsession,dictator.2.group.kept,dictator.2.subsession.round_number,dictator.3.player.id_in_group,dictator.3.player.role,dictator.3.player.payoff,dictator.3.group.id_in_subsession,dictator.3.group.kept,dictator.3.subsession.round_number,chatapp.1.player.id_in_group,chatapp.1.player.role,chatapp.1.player.payoff,chatapp.1.group.id_in_subsession,chatapp.1.subsession.round_number,survey.1.player.id_in_group,survey.1.player.role,survey.1.player.payoff,survey.1.player.age,survey.1.player.gender,survey.1.player.crt_bat,survey.1.player.crt_widget,survey.1.player.crt_lake,survey.1.group.id_in_subsession,survey.1.subsession.round_number +1,46kxib6w,Person1,0,17,16,survey,Demographics,2023-03-27 14:09:04.640153,1,,,80.0,7bfqtokx,,,,,0,dictator,1.0,0.0,1,,10.0,1,10.0,1,1,,20.0,1,20.0,2,1,,50.0,1,50.0,3,1,,0.0,1,1,1,,0.0,22,Male,1,1,47,1,1 +2,iay3dhkn,Person2,0,17,16,survey,Demographics,2023-03-27 14:09:05.096409,1,,,220.0,7bfqtokx,,,,,0,dictator,1.0,0.0,2,,90.0,1,10.0,1,2,,80.0,1,20.0,2,2,,50.0,1,50.0,3,2,,0.0,1,1,2,,0.0,22,Female,1,1,2,1,1 +3,4zhzdmzo,Person4,0,17,16,survey,Demographics,2023-03-27 14:09:06.305467,1,,,144.0,7bfqtokx,,,,,0,dictator,1.0,0.0,1,,20.0,2,20.0,1,1,,90.0,2,90.0,2,1,,34.0,2,34.0,3,1,,0.0,2,1,3,,0.0,23,Male,2,4,23,1,1 +4,3ttf7yix,Person5,0,17,16,survey,Demographics,2023-03-27 14:09:06.993953,1,,,156.0,7bfqtokx,,,,,0,dictator,1.0,0.0,2,,80.0,2,20.0,1,2,,10.0,2,90.0,2,2,,66.0,2,34.0,3,2,,0.0,2,1,4,,0.0,23,Female,2,5,47,1,1 +5,2d72mfgh,Person6,0,17,16,survey,Demographics,2023-03-27 14:09:07.592067,1,,,188.0,7bfqtokx,,,,,0,dictator,1.0,0.0,1,,22.0,3,22.0,1,1,,80.0,3,80.0,2,1,,86.0,3,86.0,3,1,,0.0,3,1,5,,0.0,33,Female,1,1,33,1,1 +6,rvce7958,Person7,0,17,16,survey,Demographics,2023-03-27 14:09:07.984583,1,,,112.0,7bfqtokx,,,,,0,dictator,1.0,0.0,2,,78.0,3,22.0,1,2,,20.0,3,80.0,2,2,,14.0,3,86.0,3,2,,0.0,3,1,6,,0.0,45,Male,2,5,77,1,1 +7,164r1hs4,Person8,0,13,16,chatapp,chat,2023-03-27 14:09:08.412382,1,,,166.0,7bfqtokx,,,,,0,dictator,1.0,0.0,1,,44.0,4,44.0,1,1,,55.0,4,55.0,2,1,,67.0,4,67.0,3,1,,0.0,4,1,7,,0.0,,,,,,1,1 +8,lsl3vbij,Person9,0,17,16,survey,Demographics,2023-03-27 14:09:08.942393,1,,,134.0,7bfqtokx,,,,,0,dictator,1.0,0.0,2,,56.0,4,44.0,1,2,,45.0,4,55.0,2,2,,33.0,4,67.0,3,2,,0.0,4,1,8,,0.0,44,Male,1,1,2,1,1 +9,ktjz5jli,Person10,0,3,16,dictator,ResultsWaitPage,2023-03-27 14:09:09.570515,1,,,0.0,7bfqtokx,,,,,0,dictator,1.0,0.0,1,,0.0,5,22.0,1,1,,0.0,5,,2,1,,0.0,5,,3,1,,0.0,5,1,9,,0.0,,,,,,1,1 +10,x0mrpuux,,0,0,16,,,,0,,,0.0,7bfqtokx,,,,,0,dictator,1.0,0.0,2,,0.0,5,22.0,1,2,,0.0,5,,2,2,,0.0,5,,3,2,,0.0,5,1,10,,0.0,,,,,,1,1 +1,xx78b3x0,Person1,0,17,16,survey,Demographics,2023-03-27 14:16:27.265131,1,,,162.0,vd1h01iv,,,,,0,dictator,1.0,0.0,1,,56.0,1,56.0,1,1,,56.0,1,56.0,2,1,,50.0,1,50.0,3,1,,0.0,1,1,1,,0.0,33,Female,5,2,47,1,1 +2,xmxl46rm,Person2,0,17,16,survey,Demographics,2023-03-27 14:16:27.736155,1,,,138.0,vd1h01iv,,,,,0,dictator,1.0,0.0,2,,44.0,1,56.0,1,2,,44.0,1,56.0,2,2,,50.0,1,50.0,3,2,,0.0,1,1,2,,0.0,23,Female,1,1,47,1,1 +3,vbhvhozv,Person3,0,3,16,dictator,ResultsWaitPage,2023-03-27 14:16:28.285839,1,,,67.0,vd1h01iv,,,,,0,dictator,1.0,0.0,1,,67.0,2,67.0,1,1,,0.0,2,,2,1,,0.0,2,,3,1,,0.0,2,1,3,,0.0,,,,,,1,1 +4,2scvem7a,Person4,0,7,16,dictator,ResultsWaitPage,2023-03-27 14:16:28.673152,1,,,33.0,vd1h01iv,,,,,0,dictator,1.0,0.0,2,,33.0,2,67.0,1,2,,0.0,2,,2,2,,0.0,2,,3,2,,0.0,2,1,4,,0.0,,,,,,1,1 +1,iagvtslv,Person1,0,17,16,survey,Demographics,2023-03-27 14:18:04.608853,1,,,179.0,t0rog7nz,,,,,0,dictator,1.0,0.0,1,,78.0,1,78.0,1,1,,45.0,1,45.0,2,1,,56.0,1,56.0,3,1,,0.0,1,1,1,,0.0,23,Male,1,1,47,1,1 +2,jxh15obl,Person2,0,15,16,survey,Offer,2023-03-27 14:18:04.992824,1,,,121.0,t0rog7nz,,,,,0,dictator,1.0,0.0,2,,22.0,1,78.0,1,2,,55.0,1,45.0,2,2,,44.0,1,56.0,3,2,,0.0,1,1,2,,0.0,,,1,1,47,1,1 +3,a7dppel1,Person3,0,17,16,survey,Demographics,2023-03-27 14:18:05.456749,1,,,129.0,t0rog7nz,,,,,0,dictator,1.0,0.0,1,,55.0,2,55.0,1,1,,51.0,2,51.0,2,1,,23.0,2,23.0,3,1,,0.0,2,1,3,,0.0,44,Female,4,2,7,1,1 +4,wk247s9w,Person4,0,17,16,survey,Demographics,2023-03-27 14:18:08.192504,1,,,171.0,t0rog7nz,,,,,0,dictator,1.0,0.0,2,,45.0,2,55.0,1,2,,49.0,2,51.0,2,2,,77.0,2,23.0,3,2,,0.0,2,1,4,,0.0,21,Female,1,23,56,1,1 +5,xkobdvuh,Person5,0,17,16,survey,Demographics,2023-03-27 14:18:08.930555,1,,,150.0,t0rog7nz,,,,,0,dictator,1.0,0.0,1,,56.0,3,56.0,1,1,,60.0,3,60.0,2,1,,34.0,3,34.0,3,1,,0.0,3,1,5,,0.0,23,Female,1,1,34,1,1 +6,1l5kal0r,Person6,0,17,16,survey,Demographics,2023-03-27 14:18:09.598918,1,,,150.0,t0rog7nz,,,,,0,dictator,1.0,0.0,2,,44.0,3,56.0,1,2,,40.0,3,60.0,2,2,,66.0,3,34.0,3,2,,0.0,3,1,6,,0.0,23,Male,1,23,34,1,1 +1,7wa8kk3d,Person1,0,1,16,dictator,Introduction,2023-03-27 14:21:11.807202,1,,,0.0,l8ecm1uh,,,,,0,dictator,1.0,0.0,1,,0.0,1,,1,1,,0.0,1,,2,1,,0.0,1,,3,1,,0.0,1,1,1,,0.0,,,,,,1,1 +2,znri6myc,Person2,0,1,16,dictator,Introduction,2023-03-27 14:21:12.340856,1,,,0.0,l8ecm1uh,,,,,0,dictator,1.0,0.0,2,,0.0,1,,1,2,,0.0,1,,2,2,,0.0,1,,3,2,,0.0,1,1,2,,0.0,,,,,,1,1 +3,ao9kqvqn,Person3,0,1,16,dictator,Introduction,2023-03-27 14:21:12.797378,1,,,0.0,l8ecm1uh,,,,,0,dictator,1.0,0.0,1,,0.0,2,,1,1,,0.0,2,,2,1,,0.0,2,,3,1,,0.0,2,1,3,,0.0,,,,,,1,1 +4,d4sq7zio,Person4,0,1,16,dictator,Introduction,2023-03-27 14:21:13.126738,1,,,0.0,l8ecm1uh,,,,,0,dictator,1.0,0.0,2,,0.0,2,,1,2,,0.0,2,,2,2,,0.0,2,,3,2,,0.0,2,1,4,,0.0,,,,,,1,1 +5,n38k7owj,,0,0,16,,,,0,,,0.0,l8ecm1uh,,,,,0,dictator,1.0,0.0,1,,0.0,3,,1,1,,0.0,3,,2,1,,0.0,3,,3,1,,0.0,3,1,5,,0.0,,,,,,1,1 +6,ft1whkoy,,0,0,16,,,,0,,,0.0,l8ecm1uh,,,,,0,dictator,1.0,0.0,2,,0.0,3,,1,2,,0.0,3,,2,2,,0.0,3,,3,2,,0.0,3,1,6,,0.0,,,,,,1,1 +1,7l0hmpcq,Person2,0,17,16,survey,Demographics,2023-03-27 14:22:03.278253,1,,,201.0,qyu3qg0q,,,,,0,dictator,1.0,0.0,1,,45.0,1,45.0,1,1,,100.0,1,100.0,2,1,,56.0,1,56.0,3,1,,0.0,1,1,1,,0.0,34,Female,1,1,47,1,1 +2,ia9rnfvc,Person3,0,17,16,survey,Demographics,2023-03-27 14:22:03.285265,1,,,99.0,qyu3qg0q,,,,,0,dictator,1.0,0.0,2,,55.0,1,45.0,1,2,,0.0,1,100.0,2,2,,44.0,1,56.0,3,2,,0.0,1,1,2,,0.0,20,Female,34,1,45,1,1 +1,sik9o0t0,,0,0,16,,,,0,,,0.0,87k2lr4z,,,,,1,dictator,1.0,0.0,1,,0.0,1,,1,1,,0.0,1,,2,1,,0.0,1,,3,1,,0.0,1,1,1,,0.0,,,,,,1,1 +2,z2mym2bh,,0,0,16,,,,0,,,0.0,87k2lr4z,,,,,1,dictator,1.0,0.0,2,,0.0,1,,1,2,,0.0,1,,2,2,,0.0,1,,3,2,,0.0,1,1,2,,0.0,,,,,,1,1 diff --git a/inst/extdata/exp_data/chatapp_2023-03-27.csv b/inst/extdata/exp_data/chatapp_2023-03-27.csv new file mode 100644 index 0000000..7bd81b1 --- /dev/null +++ b/inst/extdata/exp_data/chatapp_2023-03-27.csv @@ -0,0 +1,31 @@ +participant.id_in_session,participant.code,participant.label,participant._is_bot,participant._index_in_pages,participant._max_page_index,participant._current_app_name,participant._current_page_name,participant.time_started_utc,participant.visited,participant.mturk_worker_id,participant.mturk_assignment_id,participant.payoff,player.id_in_group,player.role,player.payoff,group.id_in_subsession,subsession.round_number,session.code,session.label,session.mturk_HITId,session.mturk_HITGroupId,session.comment,session.is_demo +1,46kxib6w,Person1,0,17,16,survey,Demographics,2023-03-27 14:09:04.640153,1,,,80.0,1,,0.0,1,1,7bfqtokx,,,,,0 +2,iay3dhkn,Person2,0,17,16,survey,Demographics,2023-03-27 14:09:05.096409,1,,,220.0,2,,0.0,1,1,7bfqtokx,,,,,0 +3,4zhzdmzo,Person4,0,17,16,survey,Demographics,2023-03-27 14:09:06.305467,1,,,144.0,1,,0.0,2,1,7bfqtokx,,,,,0 +4,3ttf7yix,Person5,0,17,16,survey,Demographics,2023-03-27 14:09:06.993953,1,,,156.0,2,,0.0,2,1,7bfqtokx,,,,,0 +5,2d72mfgh,Person6,0,17,16,survey,Demographics,2023-03-27 14:09:07.592067,1,,,188.0,1,,0.0,3,1,7bfqtokx,,,,,0 +6,rvce7958,Person7,0,17,16,survey,Demographics,2023-03-27 14:09:07.984583,1,,,112.0,2,,0.0,3,1,7bfqtokx,,,,,0 +7,164r1hs4,Person8,0,13,16,chatapp,chat,2023-03-27 14:09:08.412382,1,,,166.0,1,,0.0,4,1,7bfqtokx,,,,,0 +8,lsl3vbij,Person9,0,17,16,survey,Demographics,2023-03-27 14:09:08.942393,1,,,134.0,2,,0.0,4,1,7bfqtokx,,,,,0 +9,ktjz5jli,Person10,0,3,16,dictator,ResultsWaitPage,2023-03-27 14:09:09.570515,1,,,0.0,1,,0.0,5,1,7bfqtokx,,,,,0 +10,x0mrpuux,,0,0,16,,,,0,,,0.0,2,,0.0,5,1,7bfqtokx,,,,,0 +1,xx78b3x0,Person1,0,17,16,survey,Demographics,2023-03-27 14:16:27.265131,1,,,162.0,1,,0.0,1,1,vd1h01iv,,,,,0 +2,xmxl46rm,Person2,0,17,16,survey,Demographics,2023-03-27 14:16:27.736155,1,,,138.0,2,,0.0,1,1,vd1h01iv,,,,,0 +3,vbhvhozv,Person3,0,3,16,dictator,ResultsWaitPage,2023-03-27 14:16:28.285839,1,,,67.0,1,,0.0,2,1,vd1h01iv,,,,,0 +4,2scvem7a,Person4,0,7,16,dictator,ResultsWaitPage,2023-03-27 14:16:28.673152,1,,,33.0,2,,0.0,2,1,vd1h01iv,,,,,0 +1,iagvtslv,Person1,0,17,16,survey,Demographics,2023-03-27 14:18:04.608853,1,,,179.0,1,,0.0,1,1,t0rog7nz,,,,,0 +2,jxh15obl,Person2,0,15,16,survey,Offer,2023-03-27 14:18:04.992824,1,,,121.0,2,,0.0,1,1,t0rog7nz,,,,,0 +3,a7dppel1,Person3,0,17,16,survey,Demographics,2023-03-27 14:18:05.456749,1,,,129.0,1,,0.0,2,1,t0rog7nz,,,,,0 +4,wk247s9w,Person4,0,17,16,survey,Demographics,2023-03-27 14:18:08.192504,1,,,171.0,2,,0.0,2,1,t0rog7nz,,,,,0 +5,xkobdvuh,Person5,0,17,16,survey,Demographics,2023-03-27 14:18:08.930555,1,,,150.0,1,,0.0,3,1,t0rog7nz,,,,,0 +6,1l5kal0r,Person6,0,17,16,survey,Demographics,2023-03-27 14:18:09.598918,1,,,150.0,2,,0.0,3,1,t0rog7nz,,,,,0 +1,7wa8kk3d,Person1,0,1,16,dictator,Introduction,2023-03-27 14:21:11.807202,1,,,0.0,1,,0.0,1,1,l8ecm1uh,,,,,0 +2,znri6myc,Person2,0,1,16,dictator,Introduction,2023-03-27 14:21:12.340856,1,,,0.0,2,,0.0,1,1,l8ecm1uh,,,,,0 +3,ao9kqvqn,Person3,0,1,16,dictator,Introduction,2023-03-27 14:21:12.797378,1,,,0.0,1,,0.0,2,1,l8ecm1uh,,,,,0 +4,d4sq7zio,Person4,0,1,16,dictator,Introduction,2023-03-27 14:21:13.126738,1,,,0.0,2,,0.0,2,1,l8ecm1uh,,,,,0 +5,n38k7owj,,0,0,16,,,,0,,,0.0,1,,0.0,3,1,l8ecm1uh,,,,,0 +6,ft1whkoy,,0,0,16,,,,0,,,0.0,2,,0.0,3,1,l8ecm1uh,,,,,0 +1,7l0hmpcq,Person2,0,17,16,survey,Demographics,2023-03-27 14:22:03.278253,1,,,201.0,1,,0.0,1,1,qyu3qg0q,,,,,0 +2,ia9rnfvc,Person3,0,17,16,survey,Demographics,2023-03-27 14:22:03.285265,1,,,99.0,2,,0.0,1,1,qyu3qg0q,,,,,0 +1,sik9o0t0,,0,0,16,,,,0,,,0.0,1,,0.0,1,1,87k2lr4z,,,,,1 +2,z2mym2bh,,0,0,16,,,,0,,,0.0,2,,0.0,1,1,87k2lr4z,,,,,1 diff --git a/inst/extdata/exp_data/dictator_2023-03-27.csv b/inst/extdata/exp_data/dictator_2023-03-27.csv new file mode 100644 index 0000000..4767eec --- /dev/null +++ b/inst/extdata/exp_data/dictator_2023-03-27.csv @@ -0,0 +1,91 @@ +participant.id_in_session,participant.code,participant.label,participant._is_bot,participant._index_in_pages,participant._max_page_index,participant._current_app_name,participant._current_page_name,participant.time_started_utc,participant.visited,participant.mturk_worker_id,participant.mturk_assignment_id,participant.payoff,player.id_in_group,player.role,player.payoff,group.id_in_subsession,group.kept,subsession.round_number,session.code,session.label,session.mturk_HITId,session.mturk_HITGroupId,session.comment,session.is_demo +1,46kxib6w,Person1,0,17,16,survey,Demographics,2023-03-27 14:09:04.640153,1,,,80.0,1,,10.0,1,10.0,1,7bfqtokx,,,,,0 +2,iay3dhkn,Person2,0,17,16,survey,Demographics,2023-03-27 14:09:05.096409,1,,,220.0,2,,90.0,1,10.0,1,7bfqtokx,,,,,0 +3,4zhzdmzo,Person4,0,17,16,survey,Demographics,2023-03-27 14:09:06.305467,1,,,144.0,1,,20.0,2,20.0,1,7bfqtokx,,,,,0 +4,3ttf7yix,Person5,0,17,16,survey,Demographics,2023-03-27 14:09:06.993953,1,,,156.0,2,,80.0,2,20.0,1,7bfqtokx,,,,,0 +5,2d72mfgh,Person6,0,17,16,survey,Demographics,2023-03-27 14:09:07.592067,1,,,188.0,1,,22.0,3,22.0,1,7bfqtokx,,,,,0 +6,rvce7958,Person7,0,17,16,survey,Demographics,2023-03-27 14:09:07.984583,1,,,112.0,2,,78.0,3,22.0,1,7bfqtokx,,,,,0 +7,164r1hs4,Person8,0,13,16,chatapp,chat,2023-03-27 14:09:08.412382,1,,,166.0,1,,44.0,4,44.0,1,7bfqtokx,,,,,0 +8,lsl3vbij,Person9,0,17,16,survey,Demographics,2023-03-27 14:09:08.942393,1,,,134.0,2,,56.0,4,44.0,1,7bfqtokx,,,,,0 +9,ktjz5jli,Person10,0,3,16,dictator,ResultsWaitPage,2023-03-27 14:09:09.570515,1,,,0.0,1,,0.0,5,22.0,1,7bfqtokx,,,,,0 +10,x0mrpuux,,0,0,16,,,,0,,,0.0,2,,0.0,5,22.0,1,7bfqtokx,,,,,0 +1,46kxib6w,Person1,0,17,16,survey,Demographics,2023-03-27 14:09:04.640153,1,,,80.0,1,,20.0,1,20.0,2,7bfqtokx,,,,,0 +2,iay3dhkn,Person2,0,17,16,survey,Demographics,2023-03-27 14:09:05.096409,1,,,220.0,2,,80.0,1,20.0,2,7bfqtokx,,,,,0 +3,4zhzdmzo,Person4,0,17,16,survey,Demographics,2023-03-27 14:09:06.305467,1,,,144.0,1,,90.0,2,90.0,2,7bfqtokx,,,,,0 +4,3ttf7yix,Person5,0,17,16,survey,Demographics,2023-03-27 14:09:06.993953,1,,,156.0,2,,10.0,2,90.0,2,7bfqtokx,,,,,0 +5,2d72mfgh,Person6,0,17,16,survey,Demographics,2023-03-27 14:09:07.592067,1,,,188.0,1,,80.0,3,80.0,2,7bfqtokx,,,,,0 +6,rvce7958,Person7,0,17,16,survey,Demographics,2023-03-27 14:09:07.984583,1,,,112.0,2,,20.0,3,80.0,2,7bfqtokx,,,,,0 +7,164r1hs4,Person8,0,13,16,chatapp,chat,2023-03-27 14:09:08.412382,1,,,166.0,1,,55.0,4,55.0,2,7bfqtokx,,,,,0 +8,lsl3vbij,Person9,0,17,16,survey,Demographics,2023-03-27 14:09:08.942393,1,,,134.0,2,,45.0,4,55.0,2,7bfqtokx,,,,,0 +9,ktjz5jli,Person10,0,3,16,dictator,ResultsWaitPage,2023-03-27 14:09:09.570515,1,,,0.0,1,,0.0,5,,2,7bfqtokx,,,,,0 +10,x0mrpuux,,0,0,16,,,,0,,,0.0,2,,0.0,5,,2,7bfqtokx,,,,,0 +1,46kxib6w,Person1,0,17,16,survey,Demographics,2023-03-27 14:09:04.640153,1,,,80.0,1,,50.0,1,50.0,3,7bfqtokx,,,,,0 +2,iay3dhkn,Person2,0,17,16,survey,Demographics,2023-03-27 14:09:05.096409,1,,,220.0,2,,50.0,1,50.0,3,7bfqtokx,,,,,0 +3,4zhzdmzo,Person4,0,17,16,survey,Demographics,2023-03-27 14:09:06.305467,1,,,144.0,1,,34.0,2,34.0,3,7bfqtokx,,,,,0 +4,3ttf7yix,Person5,0,17,16,survey,Demographics,2023-03-27 14:09:06.993953,1,,,156.0,2,,66.0,2,34.0,3,7bfqtokx,,,,,0 +5,2d72mfgh,Person6,0,17,16,survey,Demographics,2023-03-27 14:09:07.592067,1,,,188.0,1,,86.0,3,86.0,3,7bfqtokx,,,,,0 +6,rvce7958,Person7,0,17,16,survey,Demographics,2023-03-27 14:09:07.984583,1,,,112.0,2,,14.0,3,86.0,3,7bfqtokx,,,,,0 +7,164r1hs4,Person8,0,13,16,chatapp,chat,2023-03-27 14:09:08.412382,1,,,166.0,1,,67.0,4,67.0,3,7bfqtokx,,,,,0 +8,lsl3vbij,Person9,0,17,16,survey,Demographics,2023-03-27 14:09:08.942393,1,,,134.0,2,,33.0,4,67.0,3,7bfqtokx,,,,,0 +9,ktjz5jli,Person10,0,3,16,dictator,ResultsWaitPage,2023-03-27 14:09:09.570515,1,,,0.0,1,,0.0,5,,3,7bfqtokx,,,,,0 +10,x0mrpuux,,0,0,16,,,,0,,,0.0,2,,0.0,5,,3,7bfqtokx,,,,,0 +1,xx78b3x0,Person1,0,17,16,survey,Demographics,2023-03-27 14:16:27.265131,1,,,162.0,1,,56.0,1,56.0,1,vd1h01iv,,,,,0 +2,xmxl46rm,Person2,0,17,16,survey,Demographics,2023-03-27 14:16:27.736155,1,,,138.0,2,,44.0,1,56.0,1,vd1h01iv,,,,,0 +3,vbhvhozv,Person3,0,3,16,dictator,ResultsWaitPage,2023-03-27 14:16:28.285839,1,,,67.0,1,,67.0,2,67.0,1,vd1h01iv,,,,,0 +4,2scvem7a,Person4,0,7,16,dictator,ResultsWaitPage,2023-03-27 14:16:28.673152,1,,,33.0,2,,33.0,2,67.0,1,vd1h01iv,,,,,0 +1,xx78b3x0,Person1,0,17,16,survey,Demographics,2023-03-27 14:16:27.265131,1,,,162.0,1,,56.0,1,56.0,2,vd1h01iv,,,,,0 +2,xmxl46rm,Person2,0,17,16,survey,Demographics,2023-03-27 14:16:27.736155,1,,,138.0,2,,44.0,1,56.0,2,vd1h01iv,,,,,0 +3,vbhvhozv,Person3,0,3,16,dictator,ResultsWaitPage,2023-03-27 14:16:28.285839,1,,,67.0,1,,0.0,2,,2,vd1h01iv,,,,,0 +4,2scvem7a,Person4,0,7,16,dictator,ResultsWaitPage,2023-03-27 14:16:28.673152,1,,,33.0,2,,0.0,2,,2,vd1h01iv,,,,,0 +1,xx78b3x0,Person1,0,17,16,survey,Demographics,2023-03-27 14:16:27.265131,1,,,162.0,1,,50.0,1,50.0,3,vd1h01iv,,,,,0 +2,xmxl46rm,Person2,0,17,16,survey,Demographics,2023-03-27 14:16:27.736155,1,,,138.0,2,,50.0,1,50.0,3,vd1h01iv,,,,,0 +3,vbhvhozv,Person3,0,3,16,dictator,ResultsWaitPage,2023-03-27 14:16:28.285839,1,,,67.0,1,,0.0,2,,3,vd1h01iv,,,,,0 +4,2scvem7a,Person4,0,7,16,dictator,ResultsWaitPage,2023-03-27 14:16:28.673152,1,,,33.0,2,,0.0,2,,3,vd1h01iv,,,,,0 +1,iagvtslv,Person1,0,17,16,survey,Demographics,2023-03-27 14:18:04.608853,1,,,179.0,1,,78.0,1,78.0,1,t0rog7nz,,,,,0 +2,jxh15obl,Person2,0,15,16,survey,Offer,2023-03-27 14:18:04.992824,1,,,121.0,2,,22.0,1,78.0,1,t0rog7nz,,,,,0 +3,a7dppel1,Person3,0,17,16,survey,Demographics,2023-03-27 14:18:05.456749,1,,,129.0,1,,55.0,2,55.0,1,t0rog7nz,,,,,0 +4,wk247s9w,Person4,0,17,16,survey,Demographics,2023-03-27 14:18:08.192504,1,,,171.0,2,,45.0,2,55.0,1,t0rog7nz,,,,,0 +5,xkobdvuh,Person5,0,17,16,survey,Demographics,2023-03-27 14:18:08.930555,1,,,150.0,1,,56.0,3,56.0,1,t0rog7nz,,,,,0 +6,1l5kal0r,Person6,0,17,16,survey,Demographics,2023-03-27 14:18:09.598918,1,,,150.0,2,,44.0,3,56.0,1,t0rog7nz,,,,,0 +1,iagvtslv,Person1,0,17,16,survey,Demographics,2023-03-27 14:18:04.608853,1,,,179.0,1,,45.0,1,45.0,2,t0rog7nz,,,,,0 +2,jxh15obl,Person2,0,15,16,survey,Offer,2023-03-27 14:18:04.992824,1,,,121.0,2,,55.0,1,45.0,2,t0rog7nz,,,,,0 +3,a7dppel1,Person3,0,17,16,survey,Demographics,2023-03-27 14:18:05.456749,1,,,129.0,1,,51.0,2,51.0,2,t0rog7nz,,,,,0 +4,wk247s9w,Person4,0,17,16,survey,Demographics,2023-03-27 14:18:08.192504,1,,,171.0,2,,49.0,2,51.0,2,t0rog7nz,,,,,0 +5,xkobdvuh,Person5,0,17,16,survey,Demographics,2023-03-27 14:18:08.930555,1,,,150.0,1,,60.0,3,60.0,2,t0rog7nz,,,,,0 +6,1l5kal0r,Person6,0,17,16,survey,Demographics,2023-03-27 14:18:09.598918,1,,,150.0,2,,40.0,3,60.0,2,t0rog7nz,,,,,0 +1,iagvtslv,Person1,0,17,16,survey,Demographics,2023-03-27 14:18:04.608853,1,,,179.0,1,,56.0,1,56.0,3,t0rog7nz,,,,,0 +2,jxh15obl,Person2,0,15,16,survey,Offer,2023-03-27 14:18:04.992824,1,,,121.0,2,,44.0,1,56.0,3,t0rog7nz,,,,,0 +3,a7dppel1,Person3,0,17,16,survey,Demographics,2023-03-27 14:18:05.456749,1,,,129.0,1,,23.0,2,23.0,3,t0rog7nz,,,,,0 +4,wk247s9w,Person4,0,17,16,survey,Demographics,2023-03-27 14:18:08.192504,1,,,171.0,2,,77.0,2,23.0,3,t0rog7nz,,,,,0 +5,xkobdvuh,Person5,0,17,16,survey,Demographics,2023-03-27 14:18:08.930555,1,,,150.0,1,,34.0,3,34.0,3,t0rog7nz,,,,,0 +6,1l5kal0r,Person6,0,17,16,survey,Demographics,2023-03-27 14:18:09.598918,1,,,150.0,2,,66.0,3,34.0,3,t0rog7nz,,,,,0 +1,7wa8kk3d,Person1,0,1,16,dictator,Introduction,2023-03-27 14:21:11.807202,1,,,0.0,1,,0.0,1,,1,l8ecm1uh,,,,,0 +2,znri6myc,Person2,0,1,16,dictator,Introduction,2023-03-27 14:21:12.340856,1,,,0.0,2,,0.0,1,,1,l8ecm1uh,,,,,0 +3,ao9kqvqn,Person3,0,1,16,dictator,Introduction,2023-03-27 14:21:12.797378,1,,,0.0,1,,0.0,2,,1,l8ecm1uh,,,,,0 +4,d4sq7zio,Person4,0,1,16,dictator,Introduction,2023-03-27 14:21:13.126738,1,,,0.0,2,,0.0,2,,1,l8ecm1uh,,,,,0 +5,n38k7owj,,0,0,16,,,,0,,,0.0,1,,0.0,3,,1,l8ecm1uh,,,,,0 +6,ft1whkoy,,0,0,16,,,,0,,,0.0,2,,0.0,3,,1,l8ecm1uh,,,,,0 +1,7wa8kk3d,Person1,0,1,16,dictator,Introduction,2023-03-27 14:21:11.807202,1,,,0.0,1,,0.0,1,,2,l8ecm1uh,,,,,0 +2,znri6myc,Person2,0,1,16,dictator,Introduction,2023-03-27 14:21:12.340856,1,,,0.0,2,,0.0,1,,2,l8ecm1uh,,,,,0 +3,ao9kqvqn,Person3,0,1,16,dictator,Introduction,2023-03-27 14:21:12.797378,1,,,0.0,1,,0.0,2,,2,l8ecm1uh,,,,,0 +4,d4sq7zio,Person4,0,1,16,dictator,Introduction,2023-03-27 14:21:13.126738,1,,,0.0,2,,0.0,2,,2,l8ecm1uh,,,,,0 +5,n38k7owj,,0,0,16,,,,0,,,0.0,1,,0.0,3,,2,l8ecm1uh,,,,,0 +6,ft1whkoy,,0,0,16,,,,0,,,0.0,2,,0.0,3,,2,l8ecm1uh,,,,,0 +1,7wa8kk3d,Person1,0,1,16,dictator,Introduction,2023-03-27 14:21:11.807202,1,,,0.0,1,,0.0,1,,3,l8ecm1uh,,,,,0 +2,znri6myc,Person2,0,1,16,dictator,Introduction,2023-03-27 14:21:12.340856,1,,,0.0,2,,0.0,1,,3,l8ecm1uh,,,,,0 +3,ao9kqvqn,Person3,0,1,16,dictator,Introduction,2023-03-27 14:21:12.797378,1,,,0.0,1,,0.0,2,,3,l8ecm1uh,,,,,0 +4,d4sq7zio,Person4,0,1,16,dictator,Introduction,2023-03-27 14:21:13.126738,1,,,0.0,2,,0.0,2,,3,l8ecm1uh,,,,,0 +5,n38k7owj,,0,0,16,,,,0,,,0.0,1,,0.0,3,,3,l8ecm1uh,,,,,0 +6,ft1whkoy,,0,0,16,,,,0,,,0.0,2,,0.0,3,,3,l8ecm1uh,,,,,0 +1,7l0hmpcq,Person2,0,17,16,survey,Demographics,2023-03-27 14:22:03.278253,1,,,201.0,1,,45.0,1,45.0,1,qyu3qg0q,,,,,0 +2,ia9rnfvc,Person3,0,17,16,survey,Demographics,2023-03-27 14:22:03.285265,1,,,99.0,2,,55.0,1,45.0,1,qyu3qg0q,,,,,0 +1,7l0hmpcq,Person2,0,17,16,survey,Demographics,2023-03-27 14:22:03.278253,1,,,201.0,1,,100.0,1,100.0,2,qyu3qg0q,,,,,0 +2,ia9rnfvc,Person3,0,17,16,survey,Demographics,2023-03-27 14:22:03.285265,1,,,99.0,2,,0.0,1,100.0,2,qyu3qg0q,,,,,0 +1,7l0hmpcq,Person2,0,17,16,survey,Demographics,2023-03-27 14:22:03.278253,1,,,201.0,1,,56.0,1,56.0,3,qyu3qg0q,,,,,0 +2,ia9rnfvc,Person3,0,17,16,survey,Demographics,2023-03-27 14:22:03.285265,1,,,99.0,2,,44.0,1,56.0,3,qyu3qg0q,,,,,0 +1,sik9o0t0,,0,0,16,,,,0,,,0.0,1,,0.0,1,,1,87k2lr4z,,,,,1 +2,z2mym2bh,,0,0,16,,,,0,,,0.0,2,,0.0,1,,1,87k2lr4z,,,,,1 +1,sik9o0t0,,0,0,16,,,,0,,,0.0,1,,0.0,1,,2,87k2lr4z,,,,,1 +2,z2mym2bh,,0,0,16,,,,0,,,0.0,2,,0.0,1,,2,87k2lr4z,,,,,1 +1,sik9o0t0,,0,0,16,,,,0,,,0.0,1,,0.0,1,,3,87k2lr4z,,,,,1 +2,z2mym2bh,,0,0,16,,,,0,,,0.0,2,,0.0,1,,3,87k2lr4z,,,,,1 diff --git a/inst/extdata/exp_data/survey_2023-03-27.csv b/inst/extdata/exp_data/survey_2023-03-27.csv new file mode 100644 index 0000000..d4d5209 --- /dev/null +++ b/inst/extdata/exp_data/survey_2023-03-27.csv @@ -0,0 +1,31 @@ +participant.id_in_session,participant.code,participant.label,participant._is_bot,participant._index_in_pages,participant._max_page_index,participant._current_app_name,participant._current_page_name,participant.time_started_utc,participant.visited,participant.mturk_worker_id,participant.mturk_assignment_id,participant.payoff,player.id_in_group,player.role,player.payoff,player.age,player.gender,player.crt_bat,player.crt_widget,player.crt_lake,group.id_in_subsession,subsession.round_number,session.code,session.label,session.mturk_HITId,session.mturk_HITGroupId,session.comment,session.is_demo +1,46kxib6w,Person1,0,17,16,survey,Demographics,2023-03-27 14:09:04.640153,1,,,80.0,1,,0.0,22,Male,1,1,47,1,1,7bfqtokx,,,,,0 +2,iay3dhkn,Person2,0,17,16,survey,Demographics,2023-03-27 14:09:05.096409,1,,,220.0,2,,0.0,22,Female,1,1,2,1,1,7bfqtokx,,,,,0 +3,4zhzdmzo,Person4,0,17,16,survey,Demographics,2023-03-27 14:09:06.305467,1,,,144.0,3,,0.0,23,Male,2,4,23,1,1,7bfqtokx,,,,,0 +4,3ttf7yix,Person5,0,17,16,survey,Demographics,2023-03-27 14:09:06.993953,1,,,156.0,4,,0.0,23,Female,2,5,47,1,1,7bfqtokx,,,,,0 +5,2d72mfgh,Person6,0,17,16,survey,Demographics,2023-03-27 14:09:07.592067,1,,,188.0,5,,0.0,33,Female,1,1,33,1,1,7bfqtokx,,,,,0 +6,rvce7958,Person7,0,17,16,survey,Demographics,2023-03-27 14:09:07.984583,1,,,112.0,6,,0.0,45,Male,2,5,77,1,1,7bfqtokx,,,,,0 +7,164r1hs4,Person8,0,13,16,chatapp,chat,2023-03-27 14:09:08.412382,1,,,166.0,7,,0.0,,,,,,1,1,7bfqtokx,,,,,0 +8,lsl3vbij,Person9,0,17,16,survey,Demographics,2023-03-27 14:09:08.942393,1,,,134.0,8,,0.0,44,Male,1,1,2,1,1,7bfqtokx,,,,,0 +9,ktjz5jli,Person10,0,3,16,dictator,ResultsWaitPage,2023-03-27 14:09:09.570515,1,,,0.0,9,,0.0,,,,,,1,1,7bfqtokx,,,,,0 +10,x0mrpuux,,0,0,16,,,,0,,,0.0,10,,0.0,,,,,,1,1,7bfqtokx,,,,,0 +1,xx78b3x0,Person1,0,17,16,survey,Demographics,2023-03-27 14:16:27.265131,1,,,162.0,1,,0.0,33,Female,5,2,47,1,1,vd1h01iv,,,,,0 +2,xmxl46rm,Person2,0,17,16,survey,Demographics,2023-03-27 14:16:27.736155,1,,,138.0,2,,0.0,23,Female,1,1,47,1,1,vd1h01iv,,,,,0 +3,vbhvhozv,Person3,0,3,16,dictator,ResultsWaitPage,2023-03-27 14:16:28.285839,1,,,67.0,3,,0.0,,,,,,1,1,vd1h01iv,,,,,0 +4,2scvem7a,Person4,0,7,16,dictator,ResultsWaitPage,2023-03-27 14:16:28.673152,1,,,33.0,4,,0.0,,,,,,1,1,vd1h01iv,,,,,0 +1,iagvtslv,Person1,0,17,16,survey,Demographics,2023-03-27 14:18:04.608853,1,,,179.0,1,,0.0,23,Male,1,1,47,1,1,t0rog7nz,,,,,0 +2,jxh15obl,Person2,0,15,16,survey,Offer,2023-03-27 14:18:04.992824,1,,,121.0,2,,0.0,,,1,1,47,1,1,t0rog7nz,,,,,0 +3,a7dppel1,Person3,0,17,16,survey,Demographics,2023-03-27 14:18:05.456749,1,,,129.0,3,,0.0,44,Female,4,2,7,1,1,t0rog7nz,,,,,0 +4,wk247s9w,Person4,0,17,16,survey,Demographics,2023-03-27 14:18:08.192504,1,,,171.0,4,,0.0,21,Female,1,23,56,1,1,t0rog7nz,,,,,0 +5,xkobdvuh,Person5,0,17,16,survey,Demographics,2023-03-27 14:18:08.930555,1,,,150.0,5,,0.0,23,Female,1,1,34,1,1,t0rog7nz,,,,,0 +6,1l5kal0r,Person6,0,17,16,survey,Demographics,2023-03-27 14:18:09.598918,1,,,150.0,6,,0.0,23,Male,1,23,34,1,1,t0rog7nz,,,,,0 +1,7wa8kk3d,Person1,0,1,16,dictator,Introduction,2023-03-27 14:21:11.807202,1,,,0.0,1,,0.0,,,,,,1,1,l8ecm1uh,,,,,0 +2,znri6myc,Person2,0,1,16,dictator,Introduction,2023-03-27 14:21:12.340856,1,,,0.0,2,,0.0,,,,,,1,1,l8ecm1uh,,,,,0 +3,ao9kqvqn,Person3,0,1,16,dictator,Introduction,2023-03-27 14:21:12.797378,1,,,0.0,3,,0.0,,,,,,1,1,l8ecm1uh,,,,,0 +4,d4sq7zio,Person4,0,1,16,dictator,Introduction,2023-03-27 14:21:13.126738,1,,,0.0,4,,0.0,,,,,,1,1,l8ecm1uh,,,,,0 +5,n38k7owj,,0,0,16,,,,0,,,0.0,5,,0.0,,,,,,1,1,l8ecm1uh,,,,,0 +6,ft1whkoy,,0,0,16,,,,0,,,0.0,6,,0.0,,,,,,1,1,l8ecm1uh,,,,,0 +1,7l0hmpcq,Person2,0,17,16,survey,Demographics,2023-03-27 14:22:03.278253,1,,,201.0,1,,0.0,34,Female,1,1,47,1,1,qyu3qg0q,,,,,0 +2,ia9rnfvc,Person3,0,17,16,survey,Demographics,2023-03-27 14:22:03.285265,1,,,99.0,2,,0.0,20,Female,34,1,45,1,1,qyu3qg0q,,,,,0 +1,sik9o0t0,,0,0,16,,,,0,,,0.0,1,,0.0,,,,,,1,1,87k2lr4z,,,,,1 +2,z2mym2bh,,0,0,16,,,,0,,,0.0,2,,0.0,,,,,,1,1,87k2lr4z,,,,,1 diff --git a/inst/extdata/exp_data_2.1.0/Chat messages (accessed 2023-05-16).csv b/inst/extdata/exp_data_2.1.0/Chat messages (accessed 2023-05-16).csv new file mode 100644 index 0000000..8b0717f --- /dev/null +++ b/inst/extdata/exp_data_2.1.0/Chat messages (accessed 2023-05-16).csv @@ -0,0 +1,4 @@ +participant__session__code,participant__session_id,participant__id_in_session,participant__code,channel,nickname,body,timestamp +cwpc31ys,3,3,c6yv70yw,3-1-4,Player 1,test message,1684255173.9796607 +cwpc31ys,3,4,fo2mv7pu,3-1-4,Player 2,other message,1684255179.820032 +cwpc31ys,3,3,c6yv70yw,3-1-4,Player 1,okay,1684255184.1788046 diff --git a/inst/extdata/exp_data_2.1.0/TimeSpent (accessed 2023-05-16).csv b/inst/extdata/exp_data_2.1.0/TimeSpent (accessed 2023-05-16).csv new file mode 100644 index 0000000..e94a59e --- /dev/null +++ b/inst/extdata/exp_data_2.1.0/TimeSpent (accessed 2023-05-16).csv @@ -0,0 +1,40 @@ +session_id,participant__id_in_session,participant__code,page_index,app_name,page_name,time_stamp,seconds_on_page,subsession_pk,auto_submitted +1,1,7h4f7nhb,1,start,Start,1684151662,3,1,False +1,1,7h4f7nhb,2,dictator,Introduction,1684151663,1,1,False +2,1,58mp2shv,1,start,Start,1684152058,2,2,False +2,1,58mp2shv,2,dictator,Introduction,1684152060,2,4,False +2,2,h9deh7vd,1,start,Start,1684152134,78,2,False +2,2,h9deh7vd,2,dictator,Introduction,1684152135,1,4,False +3,2,pwm92rv7,1,start,Start,1684252183,5,3,False +3,2,pwm92rv7,2,dictator,Introduction,1684252185,2,7,False +3,3,c6yv70yw,1,start,Start,1684252187,9,3,False +3,3,c6yv70yw,2,dictator,Introduction,1684252189,2,7,False +3,3,c6yv70yw,3,dictator,Offer,1684255143,2954,7,False +3,3,c6yv70yw,4,dictator,ResultsWaitPage,1684255143,0,7,False +3,3,c6yv70yw,5,dictator,Results,1684255144,1,7,False +3,3,c6yv70yw,6,dictator,Introduction,1684255146,2,8,False +3,3,c6yv70yw,7,dictator,Offer,1684255148,2,8,False +3,3,c6yv70yw,8,dictator,ResultsWaitPage,1684255156,8,8,False +3,3,c6yv70yw,9,dictator,Results,1684255165,9,8,False +3,3,c6yv70yw,10,dictator,Introduction,1684255166,1,9,False +3,3,c6yv70yw,11,dictator,Offer,1684255168,2,9,False +3,3,c6yv70yw,12,dictator,ResultsWaitPage,1684255169,1,9,False +3,3,c6yv70yw,13,dictator,Results,1684255171,2,9,False +3,3,c6yv70yw,14,chatapp,chat,1684255186,15,3,False +3,3,c6yv70yw,15,survey,CognitiveReflectionTest,1684255359,173,3,False +3,3,c6yv70yw,16,survey,Offer,1684255364,5,3,False +3,3,c6yv70yw,17,survey,Demographics,1684255409,45,3,False +3,4,fo2mv7pu,1,start,Start,1684252192,13,3,False +3,4,fo2mv7pu,2,dictator,Introduction,1684252194,2,7,False +3,4,fo2mv7pu,4,dictator,ResultsWaitPage,1684255143,2949,7,False +3,4,fo2mv7pu,5,dictator,Results,1684255155,12,7,False +3,4,fo2mv7pu,6,dictator,Introduction,1684255156,1,8,False +3,4,fo2mv7pu,8,dictator,ResultsWaitPage,1684255156,0,8,False +3,4,fo2mv7pu,9,dictator,Results,1684255158,2,8,False +3,4,fo2mv7pu,10,dictator,Introduction,1684255159,1,9,False +3,4,fo2mv7pu,12,dictator,ResultsWaitPage,1684255169,10,9,False +3,4,fo2mv7pu,13,dictator,Results,1684255176,7,9,False +3,4,fo2mv7pu,14,chatapp,chat,1684255189,13,3,False +3,4,fo2mv7pu,15,survey,CognitiveReflectionTest,1684255397,208,3,False +3,4,fo2mv7pu,16,survey,Offer,1684255398,1,3,False +3,4,fo2mv7pu,17,survey,Demographics,1684255405,7,3,False diff --git a/inst/extdata/exp_data_2.1.0/all_apps_wide_2023-05-16.csv b/inst/extdata/exp_data_2.1.0/all_apps_wide_2023-05-16.csv new file mode 100644 index 0000000..cb21c70 --- /dev/null +++ b/inst/extdata/exp_data_2.1.0/all_apps_wide_2023-05-16.csv @@ -0,0 +1,9 @@ +participant.id_in_session,participant.code,participant.label,participant._is_bot,participant._index_in_pages,participant._max_page_index,participant._current_app_name,participant._round_number,participant._current_page_name,participant.ip_address,participant.time_started,participant.visited,participant.mturk_worker_id,participant.mturk_assignment_id,participant.payoff,participant.payoff_plus_participation_fee,session.code,session.label,session.experimenter_name,session.mturk_HITId,session.mturk_HITGroupId,session.comment,session.is_demo,session.config.real_world_currency_per_point,session.config.participation_fee,start.1.player.id_in_group,start.1.player.payoff,start.1.group.id_in_subsession,start.1.subsession.round_number,dictator.1.player.id_in_group,dictator.1.player.kept,dictator.1.player.payoff,dictator.1.group.id_in_subsession,dictator.1.group.kept,dictator.1.subsession.round_number,dictator.2.player.id_in_group,dictator.2.player.kept,dictator.2.player.payoff,dictator.2.group.id_in_subsession,dictator.2.group.kept,dictator.2.subsession.round_number,dictator.3.player.id_in_group,dictator.3.player.kept,dictator.3.player.payoff,dictator.3.group.id_in_subsession,dictator.3.group.kept,dictator.3.subsession.round_number,chatapp.1.player.id_in_group,chatapp.1.player.payoff,chatapp.1.group.id_in_subsession,chatapp.1.subsession.round_number,survey.1.player.id_in_group,survey.1.player.age,survey.1.player.gender,survey.1.player.crt_bat,survey.1.player.crt_widget,survey.1.player.crt_lake,survey.1.player.payoff,survey.1.group.id_in_subsession,survey.1.subsession.round_number +1,7h4f7nhb,,0,3,17,dictator,1,Offer,127.0.0.1,2023-05-15 11:54:19.405472+00:00,1,,,0,0.00,g2athxx0,,,,,,1,1.0,0.00,1,0,1,1,1,,0,1,,1,1,,0,1,,2,1,,0,1,,3,1,0,1,1,1,,,,,,0,1,1 +2,q5m0bupv,,0,1,17,start,1,Start,127.0.0.1,2023-05-15 11:54:19.452335+00:00,1,,,0,0.00,g2athxx0,,,,,,1,1.0,0.00,2,0,1,1,2,,0,1,,1,2,,0,1,,2,2,,0,1,,3,2,0,1,1,2,,,,,,0,1,1 +1,58mp2shv,,0,3,17,dictator,1,Offer,127.0.0.1,2023-05-15 12:00:56.424786+00:00,1,,,0,0.00,lfy0dqvn,,,,,,1,1.0,0.00,1,0,1,1,1,,0,1,,1,1,,0,1,,2,1,,0,1,,3,1,0,1,1,1,,,,,,0,1,1 +2,h9deh7vd,,0,4,17,dictator,1,ResultsWaitPage,127.0.0.1,2023-05-15 12:00:56.615877+00:00,1,,,0,0.00,lfy0dqvn,,,,,,1,1.0,0.00,2,0,1,1,2,,0,1,,1,2,,0,1,,2,2,,0,1,,3,2,0,1,1,2,,,,,,0,1,1 +1,cybtvgeg,,0,1,17,start,1,Start,127.0.0.1,2023-05-16 15:49:37.887112+00:00,1,,,0,0.00,cwpc31ys,,,,,,0,1.0,0.00,1,0,1,1,1,,0,1,,1,1,,0,1,,2,1,,0,1,,3,1,0,1,1,1,,,,,,0,1,1 +2,pwm92rv7,,0,4,17,dictator,1,ResultsWaitPage,127.0.0.1,2023-05-16 15:49:38.502804+00:00,1,,,0,0.00,cwpc31ys,,,,,,0,1.0,0.00,2,0,1,1,2,,0,1,,1,2,,0,1,,2,2,,0,1,,3,2,0,1,1,2,,,,,,0,1,1 +3,c6yv70yw,,0,18,17,survey,1,Demographics,127.0.0.1,2023-05-16 15:49:38.972722+00:00,1,,,60,60.00,cwpc31ys,,,,,,0,1.0,0.00,3,0,1,1,1,,30,2,30,1,1,,20,2,20,2,1,,10,2,10,3,1,0,2,1,3,33,Male,33,1,88,0,1,1 +4,fo2mv7pu,,0,18,17,survey,1,Demographics,127.0.0.1,2023-05-16 15:49:39.486065+00:00,1,,,240,240.00,cwpc31ys,,,,,,0,1.0,0.00,4,0,1,1,2,,70,2,30,1,2,,80,2,20,2,2,,90,2,10,3,2,0,2,1,4,13,Male,223,1,56,0,1,1 diff --git a/inst/extdata/exp_data_2.1.0/all_apps_wide_2023-05-16.xlsx b/inst/extdata/exp_data_2.1.0/all_apps_wide_2023-05-16.xlsx new file mode 100644 index 0000000..dc13f90 Binary files /dev/null and b/inst/extdata/exp_data_2.1.0/all_apps_wide_2023-05-16.xlsx differ diff --git a/inst/extdata/exp_data_2.1.0/chatapp_2023-05-16.csv b/inst/extdata/exp_data_2.1.0/chatapp_2023-05-16.csv new file mode 100644 index 0000000..6369309 --- /dev/null +++ b/inst/extdata/exp_data_2.1.0/chatapp_2023-05-16.csv @@ -0,0 +1,9 @@ +participant.id_in_session,participant.code,participant.label,participant._is_bot,participant._index_in_pages,participant._max_page_index,participant._current_app_name,participant._round_number,participant._current_page_name,participant.ip_address,participant.time_started,participant.visited,participant.mturk_worker_id,participant.mturk_assignment_id,participant.payoff,player.id_in_group,player.payoff,group.id_in_subsession,subsession.round_number,session.code,session.label,session.experimenter_name,session.mturk_HITId,session.mturk_HITGroupId,session.comment,session.is_demo +1,7h4f7nhb,,0,3,17,dictator,1,Offer,127.0.0.1,2023-05-15 11:54:19.405472+00:00,1,,,0,1,0,1,1,g2athxx0,,,,,,1 +2,q5m0bupv,,0,1,17,start,1,Start,127.0.0.1,2023-05-15 11:54:19.452335+00:00,1,,,0,2,0,1,1,g2athxx0,,,,,,1 +1,58mp2shv,,0,3,17,dictator,1,Offer,127.0.0.1,2023-05-15 12:00:56.424786+00:00,1,,,0,1,0,1,1,lfy0dqvn,,,,,,1 +2,h9deh7vd,,0,4,17,dictator,1,ResultsWaitPage,127.0.0.1,2023-05-15 12:00:56.615877+00:00,1,,,0,2,0,1,1,lfy0dqvn,,,,,,1 +1,cybtvgeg,,0,1,17,start,1,Start,127.0.0.1,2023-05-16 15:49:37.887112+00:00,1,,,0,1,0,1,1,cwpc31ys,,,,,,0 +2,pwm92rv7,,0,4,17,dictator,1,ResultsWaitPage,127.0.0.1,2023-05-16 15:49:38.502804+00:00,1,,,0,2,0,1,1,cwpc31ys,,,,,,0 +3,c6yv70yw,,0,18,17,survey,1,Demographics,127.0.0.1,2023-05-16 15:49:38.972722+00:00,1,,,60,1,0,2,1,cwpc31ys,,,,,,0 +4,fo2mv7pu,,0,18,17,survey,1,Demographics,127.0.0.1,2023-05-16 15:49:39.486065+00:00,1,,,240,2,0,2,1,cwpc31ys,,,,,,0 diff --git a/inst/extdata/exp_data_2.1.0/chatapp_2023-05-16.xlsx b/inst/extdata/exp_data_2.1.0/chatapp_2023-05-16.xlsx new file mode 100644 index 0000000..3a30f9c Binary files /dev/null and b/inst/extdata/exp_data_2.1.0/chatapp_2023-05-16.xlsx differ diff --git a/inst/extdata/exp_data_2.1.0/dictator_2023-00-00.xlsx b/inst/extdata/exp_data_2.1.0/dictator_2023-00-00.xlsx new file mode 100644 index 0000000..fc97bfa Binary files /dev/null and b/inst/extdata/exp_data_2.1.0/dictator_2023-00-00.xlsx differ diff --git a/inst/extdata/exp_data_2.1.0/dictator_2023-00-01.xlsx b/inst/extdata/exp_data_2.1.0/dictator_2023-00-01.xlsx new file mode 100644 index 0000000..6a07b20 Binary files /dev/null and b/inst/extdata/exp_data_2.1.0/dictator_2023-00-01.xlsx differ diff --git a/inst/extdata/exp_data_2.1.0/dictator_2023-00-02.xlsx b/inst/extdata/exp_data_2.1.0/dictator_2023-00-02.xlsx new file mode 100644 index 0000000..8b7d480 Binary files /dev/null and b/inst/extdata/exp_data_2.1.0/dictator_2023-00-02.xlsx differ diff --git a/inst/extdata/exp_data_2.1.0/dictator_2023-05-16.csv b/inst/extdata/exp_data_2.1.0/dictator_2023-05-16.csv new file mode 100644 index 0000000..ab0df47 --- /dev/null +++ b/inst/extdata/exp_data_2.1.0/dictator_2023-05-16.csv @@ -0,0 +1,25 @@ +participant.id_in_session,participant.code,participant.label,participant._is_bot,participant._index_in_pages,participant._max_page_index,participant._current_app_name,participant._round_number,participant._current_page_name,participant.ip_address,participant.time_started,participant.visited,participant.mturk_worker_id,participant.mturk_assignment_id,participant.payoff,player.id_in_group,player.kept,player.payoff,group.id_in_subsession,group.kept,subsession.round_number,session.code,session.label,session.experimenter_name,session.mturk_HITId,session.mturk_HITGroupId,session.comment,session.is_demo +1,7h4f7nhb,,0,3,17,dictator,1,Offer,127.0.0.1,2023-05-15 11:54:19.405472+00:00,1,,,0,1,,0,1,,1,g2athxx0,,,,,,1 +2,q5m0bupv,,0,1,17,start,1,Start,127.0.0.1,2023-05-15 11:54:19.452335+00:00,1,,,0,2,,0,1,,1,g2athxx0,,,,,,1 +1,7h4f7nhb,,0,3,17,dictator,1,Offer,127.0.0.1,2023-05-15 11:54:19.405472+00:00,1,,,0,1,,0,1,,2,g2athxx0,,,,,,1 +2,q5m0bupv,,0,1,17,start,1,Start,127.0.0.1,2023-05-15 11:54:19.452335+00:00,1,,,0,2,,0,1,,2,g2athxx0,,,,,,1 +1,7h4f7nhb,,0,3,17,dictator,1,Offer,127.0.0.1,2023-05-15 11:54:19.405472+00:00,1,,,0,1,,0,1,,3,g2athxx0,,,,,,1 +2,q5m0bupv,,0,1,17,start,1,Start,127.0.0.1,2023-05-15 11:54:19.452335+00:00,1,,,0,2,,0,1,,3,g2athxx0,,,,,,1 +1,58mp2shv,,0,3,17,dictator,1,Offer,127.0.0.1,2023-05-15 12:00:56.424786+00:00,1,,,0,1,,0,1,,1,lfy0dqvn,,,,,,1 +2,h9deh7vd,,0,4,17,dictator,1,ResultsWaitPage,127.0.0.1,2023-05-15 12:00:56.615877+00:00,1,,,0,2,,0,1,,1,lfy0dqvn,,,,,,1 +1,58mp2shv,,0,3,17,dictator,1,Offer,127.0.0.1,2023-05-15 12:00:56.424786+00:00,1,,,0,1,,0,1,,2,lfy0dqvn,,,,,,1 +2,h9deh7vd,,0,4,17,dictator,1,ResultsWaitPage,127.0.0.1,2023-05-15 12:00:56.615877+00:00,1,,,0,2,,0,1,,2,lfy0dqvn,,,,,,1 +1,58mp2shv,,0,3,17,dictator,1,Offer,127.0.0.1,2023-05-15 12:00:56.424786+00:00,1,,,0,1,,0,1,,3,lfy0dqvn,,,,,,1 +2,h9deh7vd,,0,4,17,dictator,1,ResultsWaitPage,127.0.0.1,2023-05-15 12:00:56.615877+00:00,1,,,0,2,,0,1,,3,lfy0dqvn,,,,,,1 +1,cybtvgeg,,0,1,17,start,1,Start,127.0.0.1,2023-05-16 15:49:37.887112+00:00,1,,,0,1,,0,1,,1,cwpc31ys,,,,,,0 +2,pwm92rv7,,0,4,17,dictator,1,ResultsWaitPage,127.0.0.1,2023-05-16 15:49:38.502804+00:00,1,,,0,2,,0,1,,1,cwpc31ys,,,,,,0 +3,c6yv70yw,,0,18,17,survey,1,Demographics,127.0.0.1,2023-05-16 15:49:38.972722+00:00,1,,,60,1,,30,2,30,1,cwpc31ys,,,,,,0 +4,fo2mv7pu,,0,18,17,survey,1,Demographics,127.0.0.1,2023-05-16 15:49:39.486065+00:00,1,,,240,2,,70,2,30,1,cwpc31ys,,,,,,0 +1,cybtvgeg,,0,1,17,start,1,Start,127.0.0.1,2023-05-16 15:49:37.887112+00:00,1,,,0,1,,0,1,,2,cwpc31ys,,,,,,0 +2,pwm92rv7,,0,4,17,dictator,1,ResultsWaitPage,127.0.0.1,2023-05-16 15:49:38.502804+00:00,1,,,0,2,,0,1,,2,cwpc31ys,,,,,,0 +3,c6yv70yw,,0,18,17,survey,1,Demographics,127.0.0.1,2023-05-16 15:49:38.972722+00:00,1,,,60,1,,20,2,20,2,cwpc31ys,,,,,,0 +4,fo2mv7pu,,0,18,17,survey,1,Demographics,127.0.0.1,2023-05-16 15:49:39.486065+00:00,1,,,240,2,,80,2,20,2,cwpc31ys,,,,,,0 +1,cybtvgeg,,0,1,17,start,1,Start,127.0.0.1,2023-05-16 15:49:37.887112+00:00,1,,,0,1,,0,1,,3,cwpc31ys,,,,,,0 +2,pwm92rv7,,0,4,17,dictator,1,ResultsWaitPage,127.0.0.1,2023-05-16 15:49:38.502804+00:00,1,,,0,2,,0,1,,3,cwpc31ys,,,,,,0 +3,c6yv70yw,,0,18,17,survey,1,Demographics,127.0.0.1,2023-05-16 15:49:38.972722+00:00,1,,,60,1,,10,2,10,3,cwpc31ys,,,,,,0 +4,fo2mv7pu,,0,18,17,survey,1,Demographics,127.0.0.1,2023-05-16 15:49:39.486065+00:00,1,,,240,2,,90,2,10,3,cwpc31ys,,,,,,0 diff --git a/inst/extdata/exp_data_2.1.0/dictator_2023-05-16.xlsx b/inst/extdata/exp_data_2.1.0/dictator_2023-05-16.xlsx new file mode 100644 index 0000000..4debcaa Binary files /dev/null and b/inst/extdata/exp_data_2.1.0/dictator_2023-05-16.xlsx differ diff --git a/inst/extdata/exp_data_2.1.0/start_2023-05-16.csv b/inst/extdata/exp_data_2.1.0/start_2023-05-16.csv new file mode 100644 index 0000000..d370f19 --- /dev/null +++ b/inst/extdata/exp_data_2.1.0/start_2023-05-16.csv @@ -0,0 +1,9 @@ +participant.id_in_session,participant.code,participant.label,participant._is_bot,participant._index_in_pages,participant._max_page_index,participant._current_app_name,participant._round_number,participant._current_page_name,participant.ip_address,participant.time_started,participant.visited,participant.mturk_worker_id,participant.mturk_assignment_id,participant.payoff,player.id_in_group,player.payoff,group.id_in_subsession,subsession.round_number,session.code,session.label,session.experimenter_name,session.mturk_HITId,session.mturk_HITGroupId,session.comment,session.is_demo +1,7h4f7nhb,,0,3,17,dictator,1,Offer,127.0.0.1,2023-05-15 11:54:19.405472+00:00,1,,,0,1,0,1,1,g2athxx0,,,,,,1 +2,q5m0bupv,,0,1,17,start,1,Start,127.0.0.1,2023-05-15 11:54:19.452335+00:00,1,,,0,2,0,1,1,g2athxx0,,,,,,1 +1,58mp2shv,,0,3,17,dictator,1,Offer,127.0.0.1,2023-05-15 12:00:56.424786+00:00,1,,,0,1,0,1,1,lfy0dqvn,,,,,,1 +2,h9deh7vd,,0,4,17,dictator,1,ResultsWaitPage,127.0.0.1,2023-05-15 12:00:56.615877+00:00,1,,,0,2,0,1,1,lfy0dqvn,,,,,,1 +1,cybtvgeg,,0,1,17,start,1,Start,127.0.0.1,2023-05-16 15:49:37.887112+00:00,1,,,0,1,0,1,1,cwpc31ys,,,,,,0 +2,pwm92rv7,,0,4,17,dictator,1,ResultsWaitPage,127.0.0.1,2023-05-16 15:49:38.502804+00:00,1,,,0,2,0,1,1,cwpc31ys,,,,,,0 +3,c6yv70yw,,0,18,17,survey,1,Demographics,127.0.0.1,2023-05-16 15:49:38.972722+00:00,1,,,60,3,0,1,1,cwpc31ys,,,,,,0 +4,fo2mv7pu,,0,18,17,survey,1,Demographics,127.0.0.1,2023-05-16 15:49:39.486065+00:00,1,,,240,4,0,1,1,cwpc31ys,,,,,,0 diff --git a/inst/extdata/exp_data_2.1.0/start_2023-05-16.xlsx b/inst/extdata/exp_data_2.1.0/start_2023-05-16.xlsx new file mode 100644 index 0000000..a4772d1 Binary files /dev/null and b/inst/extdata/exp_data_2.1.0/start_2023-05-16.xlsx differ diff --git a/inst/extdata/exp_data_2.1.0/survey_2023-05-16.csv b/inst/extdata/exp_data_2.1.0/survey_2023-05-16.csv new file mode 100644 index 0000000..42385d2 --- /dev/null +++ b/inst/extdata/exp_data_2.1.0/survey_2023-05-16.csv @@ -0,0 +1,9 @@ +participant.id_in_session,participant.code,participant.label,participant._is_bot,participant._index_in_pages,participant._max_page_index,participant._current_app_name,participant._round_number,participant._current_page_name,participant.ip_address,participant.time_started,participant.visited,participant.mturk_worker_id,participant.mturk_assignment_id,participant.payoff,player.id_in_group,player.age,player.gender,player.crt_bat,player.crt_widget,player.crt_lake,player.payoff,group.id_in_subsession,subsession.round_number,session.code,session.label,session.experimenter_name,session.mturk_HITId,session.mturk_HITGroupId,session.comment,session.is_demo +1,7h4f7nhb,,0,3,17,dictator,1,Offer,127.0.0.1,2023-05-15 11:54:19.405472+00:00,1,,,0,1,,,,,,0,1,1,g2athxx0,,,,,,1 +2,q5m0bupv,,0,1,17,start,1,Start,127.0.0.1,2023-05-15 11:54:19.452335+00:00,1,,,0,2,,,,,,0,1,1,g2athxx0,,,,,,1 +1,58mp2shv,,0,3,17,dictator,1,Offer,127.0.0.1,2023-05-15 12:00:56.424786+00:00,1,,,0,1,,,,,,0,1,1,lfy0dqvn,,,,,,1 +2,h9deh7vd,,0,4,17,dictator,1,ResultsWaitPage,127.0.0.1,2023-05-15 12:00:56.615877+00:00,1,,,0,2,,,,,,0,1,1,lfy0dqvn,,,,,,1 +1,cybtvgeg,,0,1,17,start,1,Start,127.0.0.1,2023-05-16 15:49:37.887112+00:00,1,,,0,1,,,,,,0,1,1,cwpc31ys,,,,,,0 +2,pwm92rv7,,0,4,17,dictator,1,ResultsWaitPage,127.0.0.1,2023-05-16 15:49:38.502804+00:00,1,,,0,2,,,,,,0,1,1,cwpc31ys,,,,,,0 +3,c6yv70yw,,0,18,17,survey,1,Demographics,127.0.0.1,2023-05-16 15:49:38.972722+00:00,1,,,60,3,33,Male,33,1,88,0,1,1,cwpc31ys,,,,,,0 +4,fo2mv7pu,,0,18,17,survey,1,Demographics,127.0.0.1,2023-05-16 15:49:39.486065+00:00,1,,,240,4,13,Male,223,1,56,0,1,1,cwpc31ys,,,,,,0 diff --git a/inst/extdata/exp_data_2.1.0/survey_2023-05-16.xlsx b/inst/extdata/exp_data_2.1.0/survey_2023-05-16.xlsx new file mode 100644 index 0000000..e3cfe82 Binary files /dev/null and b/inst/extdata/exp_data_2.1.0/survey_2023-05-16.xlsx differ diff --git a/inst/extdata/exp_data_2.2.4/Chat messages (accessed 2023-05-13).csv b/inst/extdata/exp_data_2.2.4/Chat messages (accessed 2023-05-13).csv new file mode 100644 index 0000000..59dd863 --- /dev/null +++ b/inst/extdata/exp_data_2.2.4/Chat messages (accessed 2023-05-13).csv @@ -0,0 +1,11 @@ +participant__session__code,participant__session_id,participant__id_in_session,participant__code,channel,nickname,body,timestamp +mugt25jb,1,1,giqwyeh7,1-1-1,Participant 1,This is a test,1683965357.1635158 +mugt25jb,1,2,ibauvcv6,1-1-1,Participant 2,This is another message,1683965362.075973 +mugt25jb,1,1,giqwyeh7,1-1-1,Participant 1,Awesome!,1683965366.07096 +mugt25jb,1,2,ibauvcv6,1-1-1,Participant 2,Super!,1683965370.1358202 +mugt25jb,1,5,xb5oapsv,1-1-3,Participant 1,44,1683965390.9560452 +mugt25jb,1,6,oh3pjgtd,1-1-3,Participant 2,90,1683965395.6682875 +mugt25jb,1,6,oh3pjgtd,1-1-3,Participant 2,100,1683965406.7112763 +1d33zgt8,2,2,trua2ysc,2-1-6,Participant 2,This is a test message,1683965545.157237 +1d33zgt8,2,1,pwg27fum,2-1-6,Participant 1,My answer to that,1683965549.8166058 +1d33zgt8,2,2,trua2ysc,2-1-6,Participant 2,cool,1683965552.8326757 diff --git a/inst/extdata/exp_data_2.2.4/TimeSpent (accessed 2023-05-13).csv b/inst/extdata/exp_data_2.2.4/TimeSpent (accessed 2023-05-13).csv new file mode 100644 index 0000000..9972ef9 --- /dev/null +++ b/inst/extdata/exp_data_2.2.4/TimeSpent (accessed 2023-05-13).csv @@ -0,0 +1,104 @@ +session_id,participant__id_in_session,participant__code,page_index,app_name,page_name,time_stamp,seconds_on_page,subsession_pk,auto_submitted +1,1,giqwyeh7,1,start,Start,1683965273,9,1,False +1,1,giqwyeh7,2,dictator,Introduction,1683965284,11,1,False +1,1,giqwyeh7,3,dictator,Offer,1683965286,2,1,False +1,1,giqwyeh7,4,dictator,ResultsWaitPage,1683965289,3,1,False +1,1,giqwyeh7,5,dictator,Results,1683965293,4,1,False +1,1,giqwyeh7,6,dictator,Introduction,1683965295,2,2,False +1,1,giqwyeh7,7,dictator,Offer,1683965297,2,2,False +1,1,giqwyeh7,8,dictator,ResultsWaitPage,1683965315,18,2,False +1,1,giqwyeh7,9,dictator,Results,1683965333,18,2,False +1,1,giqwyeh7,10,dictator,Introduction,1683965335,2,3,False +1,1,giqwyeh7,11,dictator,Offer,1683965338,3,3,False +1,1,giqwyeh7,12,dictator,ResultsWaitPage,1683965341,3,3,False +1,1,giqwyeh7,13,dictator,Results,1683965350,9,3,False +1,1,giqwyeh7,14,chatapp,chat,1683965373,23,1,False +1,2,ibauvcv6,1,start,Start,1683965274,10,1,False +1,2,ibauvcv6,2,dictator,Introduction,1683965288,14,1,False +1,2,ibauvcv6,4,dictator,ResultsWaitPage,1683965289,1,1,False +1,2,ibauvcv6,5,dictator,Results,1683965290,1,1,False +1,2,ibauvcv6,6,dictator,Introduction,1683965315,25,2,False +1,2,ibauvcv6,8,dictator,ResultsWaitPage,1683965315,0,2,False +1,2,ibauvcv6,9,dictator,Results,1683965331,16,2,False +1,2,ibauvcv6,10,dictator,Introduction,1683965340,9,3,False +1,2,ibauvcv6,12,dictator,ResultsWaitPage,1683965341,1,3,False +1,2,ibauvcv6,13,dictator,Results,1683965352,11,3,False +1,2,ibauvcv6,14,chatapp,chat,1683965371,19,1,False +1,2,ibauvcv6,15,survey,CognitiveReflectionTest,1683965382,11,1,False +1,2,ibauvcv6,16,survey,Offer,1683965397,15,1,False +1,2,ibauvcv6,17,survey,Demographics,1683965402,5,1,False +1,3,mqaatrt4,1,start,Start,1683965275,10,1,False +1,3,mqaatrt4,2,dictator,Introduction,1683965292,17,1,False +1,3,mqaatrt4,3,dictator,Offer,1683965319,27,1,False +1,5,xb5oapsv,1,start,Start,1683965277,10,1,False +1,5,xb5oapsv,2,dictator,Introduction,1683965278,1,1,False +1,5,xb5oapsv,3,dictator,Offer,1683965301,23,1,False +1,5,xb5oapsv,4,dictator,ResultsWaitPage,1683965303,2,1,False +1,5,xb5oapsv,5,dictator,Results,1683965320,17,1,False +1,5,xb5oapsv,6,dictator,Introduction,1683965322,2,2,False +1,5,xb5oapsv,7,dictator,Offer,1683965324,2,2,False +1,5,xb5oapsv,8,dictator,ResultsWaitPage,1683965325,1,2,False +1,5,xb5oapsv,9,dictator,Results,1683965346,21,2,False +1,5,xb5oapsv,10,dictator,Introduction,1683965347,1,3,False +1,5,xb5oapsv,11,dictator,Offer,1683965386,39,3,False +1,5,xb5oapsv,12,dictator,ResultsWaitPage,1683965386,0,3,False +1,5,xb5oapsv,13,dictator,Results,1683965388,2,3,False +1,5,xb5oapsv,14,chatapp,chat,1683965458,70,1,False +1,5,xb5oapsv,15,survey,CognitiveReflectionTest,1683965464,6,1,False +1,5,xb5oapsv,16,survey,Offer,1683965465,1,1,False +1,5,xb5oapsv,17,survey,Demographics,1683965472,7,1,False +1,6,oh3pjgtd,1,start,Start,1683965280,13,1,False +1,6,oh3pjgtd,2,dictator,Introduction,1683965303,23,1,False +1,6,oh3pjgtd,4,dictator,ResultsWaitPage,1683965303,0,1,False +1,6,oh3pjgtd,5,dictator,Results,1683965304,1,1,False +1,6,oh3pjgtd,6,dictator,Introduction,1683965306,2,2,False +1,6,oh3pjgtd,8,dictator,ResultsWaitPage,1683965325,19,2,False +1,6,oh3pjgtd,9,dictator,Results,1683965326,1,2,False +1,6,oh3pjgtd,10,dictator,Introduction,1683965329,3,3,False +1,6,oh3pjgtd,12,dictator,ResultsWaitPage,1683965386,57,3,False +1,6,oh3pjgtd,13,dictator,Results,1683965393,7,3,False +1,6,oh3pjgtd,14,chatapp,chat,1683965408,15,1,False +1,6,oh3pjgtd,15,survey,CognitiveReflectionTest,1683965414,6,1,False +1,6,oh3pjgtd,16,survey,Offer,1683965416,2,1,False +1,8,u3jdbpav,1,start,Start,1683965310,40,1,False +2,1,pwg27fum,1,start,Start,1683965496,4,2,False +2,1,pwg27fum,2,dictator,Introduction,1683965503,7,4,True +2,1,pwg27fum,3,dictator,Offer,1683965506,3,4,False +2,1,pwg27fum,4,dictator,ResultsWaitPage,1683965506,0,4,False +2,1,pwg27fum,5,dictator,Results,1683965511,5,4,False +2,1,pwg27fum,6,dictator,Introduction,1683965513,2,5,False +2,1,pwg27fum,7,dictator,Offer,1683965515,2,5,False +2,1,pwg27fum,8,dictator,ResultsWaitPage,1683965527,12,5,False +2,1,pwg27fum,9,dictator,Results,1683965532,5,5,False +2,1,pwg27fum,10,dictator,Introduction,1683965534,2,6,False +2,1,pwg27fum,11,dictator,Offer,1683965537,3,6,False +2,1,pwg27fum,12,dictator,ResultsWaitPage,1683965537,0,6,False +2,1,pwg27fum,13,dictator,Results,1683965539,2,6,False +2,1,pwg27fum,14,chatapp,chat,1683965556,17,2,False +2,1,pwg27fum,15,survey,CognitiveReflectionTest,1683965572,16,2,False +2,1,pwg27fum,16,survey,Offer,1683965573,1,2,False +2,1,pwg27fum,17,survey,Demographics,1683965579,6,2,False +2,2,trua2ysc,1,start,Start,1683965500,7,2,True +2,2,trua2ysc,2,dictator,Introduction,1683965503,3,4,True +2,2,trua2ysc,4,dictator,ResultsWaitPage,1683965506,3,4,False +2,2,trua2ysc,5,dictator,Results,1683965517,11,4,False +2,2,trua2ysc,6,dictator,Introduction,1683965526,9,5,False +2,2,trua2ysc,8,dictator,ResultsWaitPage,1683965527,1,5,False +2,2,trua2ysc,9,dictator,Results,1683965528,1,5,False +2,2,trua2ysc,10,dictator,Introduction,1683965530,2,6,False +2,2,trua2ysc,12,dictator,ResultsWaitPage,1683965537,7,6,False +2,2,trua2ysc,13,dictator,Results,1683965541,4,6,False +2,2,trua2ysc,14,chatapp,chat,1683965554,13,2,False +2,2,trua2ysc,15,survey,CognitiveReflectionTest,1683965561,7,2,False +2,2,trua2ysc,16,survey,Offer,1683965563,2,2,False +2,2,trua2ysc,17,survey,Demographics,1683965567,4,2,False +2,3,gab9azw4,1,start,Start,1683965500,7,2,True +2,3,gab9azw4,2,dictator,Introduction,1683965503,3,4,True +2,3,gab9azw4,3,dictator,Offer,1683965509,6,4,False +2,3,gab9azw4,4,dictator,ResultsWaitPage,1683965509,0,4,False +2,3,gab9azw4,5,dictator,Results,1683965518,9,4,False +2,3,gab9azw4,6,dictator,Introduction,1683965523,5,5,False +2,4,6ox6u8dx,1,start,Start,1683965501,7,2,True +2,4,6ox6u8dx,2,dictator,Introduction,1683965504,3,4,True +2,4,6ox6u8dx,4,dictator,ResultsWaitPage,1683965509,5,4,False +2,4,6ox6u8dx,5,dictator,Results,1683965521,12,4,False diff --git a/inst/extdata/exp_data_2.2.4/all_apps_wide_2023-05-13.csv b/inst/extdata/exp_data_2.2.4/all_apps_wide_2023-05-13.csv new file mode 100644 index 0000000..2a8fd66 --- /dev/null +++ b/inst/extdata/exp_data_2.2.4/all_apps_wide_2023-05-13.csv @@ -0,0 +1,15 @@ +participant.id_in_session,participant.code,participant.label,participant._is_bot,participant._index_in_pages,participant._max_page_index,participant._current_app_name,participant._current_page_name,participant.ip_address,participant.time_started,participant.visited,participant.mturk_worker_id,participant.mturk_assignment_id,participant.payoff,participant.payoff_plus_participation_fee,session.code,session.label,session.experimenter_name,session.mturk_HITId,session.mturk_HITGroupId,session.comment,session.is_demo,session.config.real_world_currency_per_point,session.config.participation_fee,start.1.player.id_in_group,start.1.player.payoff,start.1.group.id_in_subsession,start.1.subsession.round_number,dictator.1.player.id_in_group,dictator.1.player.payoff,dictator.1.group.id_in_subsession,dictator.1.group.kept,dictator.1.subsession.round_number,dictator.2.player.id_in_group,dictator.2.player.payoff,dictator.2.group.id_in_subsession,dictator.2.group.kept,dictator.2.subsession.round_number,dictator.3.player.id_in_group,dictator.3.player.payoff,dictator.3.group.id_in_subsession,dictator.3.group.kept,dictator.3.subsession.round_number,chatapp.1.player.id_in_group,chatapp.1.player.payoff,chatapp.1.group.id_in_subsession,chatapp.1.subsession.round_number,survey.1.player.id_in_group,survey.1.player.age,survey.1.player.gender,survey.1.player.crt_bat,survey.1.player.crt_widget,survey.1.player.crt_lake,survey.1.player.payoff,survey.1.group.id_in_subsession,survey.1.subsession.round_number +1,giqwyeh7,Person1,0,15,17,survey,CognitiveReflectionTest,127.0.0.1,2023-05-13 08:07:44.394673+00:00,1,,,134,134.00,mugt25jb,,,,,,0,1.0,0.00,1,0,1,1,1,22,1,22,1,1,22,1,22,2,1,90,1,90,3,1,0,1,1,1,,,,,,0,1,1 +2,ibauvcv6,Person2,0,18,17,survey,Demographics,127.0.0.1,2023-05-13 08:07:44.890091+00:00,1,,,166,166.00,mugt25jb,,,,,,0,1.0,0.00,2,0,1,1,2,78,1,22,1,2,78,1,22,2,2,10,1,90,3,2,0,1,1,2,90,Male,1,5,2,0,1,1 +3,mqaatrt4,Person3,0,4,17,dictator,ResultsWaitPage,127.0.0.1,2023-05-13 08:07:45.825341+00:00,1,,,0,0.00,mugt25jb,,,,,,0,1.0,0.00,3,0,1,1,1,0,2,12,1,1,0,2,,2,1,0,2,,3,1,0,2,1,3,,,,,,0,1,1 +4,k8tihf8g,Person4,0,1,17,start,Start,127.0.0.1,2023-05-13 08:07:46.509581+00:00,1,,,0,0.00,mugt25jb,,,,,,0,1.0,0.00,4,0,1,1,2,0,2,12,1,2,0,2,,2,2,0,2,,3,2,0,2,1,4,,,,,,0,1,1 +5,xb5oapsv,Person5,0,18,17,survey,Demographics,127.0.0.1,2023-05-13 08:07:47.117394+00:00,1,,,189,189.00,mugt25jb,,,,,,0,1.0,0.00,5,0,1,1,1,87,3,87,1,1,22,3,22,2,1,80,3,80,3,1,0,3,1,5,39,Female,42,1,1,0,1,1 +6,oh3pjgtd,Person6,0,17,17,survey,Demographics,127.0.0.1,2023-05-13 08:07:47.829122+00:00,1,,,111,111.00,mugt25jb,,,,,,0,1.0,0.00,6,0,1,1,2,13,3,87,1,2,78,3,22,2,2,20,3,80,3,2,0,3,1,6,,,70,2,10,0,1,1 +7,744avqxx,Person7,0,1,17,start,Start,127.0.0.1,2023-05-13 08:07:48.984720+00:00,1,,,0,0.00,mugt25jb,,,,,,0,1.0,0.00,7,0,1,1,1,0,4,,1,1,0,4,,2,1,0,4,,3,1,0,4,1,7,,,,,,0,1,1 +8,u3jdbpav,Person8,0,2,17,dictator,Introduction,127.0.0.1,2023-05-13 08:07:50.258132+00:00,1,,,0,0.00,mugt25jb,,,,,,0,1.0,0.00,8,0,1,1,2,0,4,,1,2,0,4,,2,2,0,4,,3,2,0,4,1,8,,,,,,0,1,1 +9,k9v23vx9,,0,0,17,,,,,0,,,0,0.00,mugt25jb,,,,,,0,1.0,0.00,9,0,1,1,1,0,5,,1,1,0,5,,2,1,0,5,,3,1,0,5,1,9,,,,,,0,1,1 +10,1a5k98k4,,0,0,17,,,,,0,,,0,0.00,mugt25jb,,,,,,0,1.0,0.00,10,0,1,1,2,0,5,,1,2,0,5,,2,2,0,5,,3,2,0,5,1,10,,,,,,0,1,1 +1,pwg27fum,,0,18,17,survey,Demographics,127.0.0.1,2023-05-13 08:11:32.834582+00:00,1,,,155,155.00,1d33zgt8,,,,,,0,1.0,0.00,1,0,1,1,1,55,1,55,1,1,50,1,50,2,1,50,1,50,3,1,0,1,1,1,90,Male,1,3,76,0,1,1 +2,trua2ysc,,0,18,17,survey,Demographics,127.0.0.1,2023-05-13 08:11:33.343669+00:00,1,,,145,145.00,1d33zgt8,,,,,,0,1.0,0.00,2,0,1,1,2,45,1,55,1,2,50,1,50,2,2,50,1,50,3,2,0,1,1,2,33,Male,3,7,1,0,1,1 +3,gab9azw4,,0,7,17,dictator,Offer,127.0.0.1,2023-05-13 08:11:33.860623+00:00,1,,,12,12.00,1d33zgt8,,,,,,0,1.0,0.00,3,0,1,1,1,12,2,12,1,1,0,2,,2,1,0,2,,3,1,0,2,1,3,,,,,,0,1,1 +4,6ox6u8dx,,0,6,17,dictator,Introduction,127.0.0.1,2023-05-13 08:11:34.419168+00:00,1,,,88,88.00,1d33zgt8,,,,,,0,1.0,0.00,4,0,1,1,2,88,2,12,1,2,0,2,,2,2,0,2,,3,2,0,2,1,4,,,,,,0,1,1 diff --git a/inst/extdata/exp_data_2.2.4/all_apps_wide_2023-05-13.xlsx b/inst/extdata/exp_data_2.2.4/all_apps_wide_2023-05-13.xlsx new file mode 100644 index 0000000..23067ad Binary files /dev/null and b/inst/extdata/exp_data_2.2.4/all_apps_wide_2023-05-13.xlsx differ diff --git a/inst/extdata/exp_data_2.2.4/chatapp_2023-05-13.csv b/inst/extdata/exp_data_2.2.4/chatapp_2023-05-13.csv new file mode 100644 index 0000000..ad5da04 --- /dev/null +++ b/inst/extdata/exp_data_2.2.4/chatapp_2023-05-13.csv @@ -0,0 +1,15 @@ +participant.id_in_session,participant.code,participant.label,participant._is_bot,participant._index_in_pages,participant._max_page_index,participant._current_app_name,participant._current_page_name,participant.ip_address,participant.time_started,participant.visited,participant.mturk_worker_id,participant.mturk_assignment_id,participant.payoff,player.id_in_group,player.payoff,group.id_in_subsession,subsession.round_number,session.code,session.label,session.experimenter_name,session.mturk_HITId,session.mturk_HITGroupId,session.comment,session.is_demo +1,giqwyeh7,Person1,0,15,17,survey,CognitiveReflectionTest,127.0.0.1,2023-05-13 08:07:44.394673+00:00,1,,,134,1,0,1,1,mugt25jb,,,,,,0 +2,ibauvcv6,Person2,0,18,17,survey,Demographics,127.0.0.1,2023-05-13 08:07:44.890091+00:00,1,,,166,2,0,1,1,mugt25jb,,,,,,0 +3,mqaatrt4,Person3,0,4,17,dictator,ResultsWaitPage,127.0.0.1,2023-05-13 08:07:45.825341+00:00,1,,,0,1,0,2,1,mugt25jb,,,,,,0 +4,k8tihf8g,Person4,0,1,17,start,Start,127.0.0.1,2023-05-13 08:07:46.509581+00:00,1,,,0,2,0,2,1,mugt25jb,,,,,,0 +5,xb5oapsv,Person5,0,18,17,survey,Demographics,127.0.0.1,2023-05-13 08:07:47.117394+00:00,1,,,189,1,0,3,1,mugt25jb,,,,,,0 +6,oh3pjgtd,Person6,0,17,17,survey,Demographics,127.0.0.1,2023-05-13 08:07:47.829122+00:00,1,,,111,2,0,3,1,mugt25jb,,,,,,0 +7,744avqxx,Person7,0,1,17,start,Start,127.0.0.1,2023-05-13 08:07:48.984720+00:00,1,,,0,1,0,4,1,mugt25jb,,,,,,0 +8,u3jdbpav,Person8,0,2,17,dictator,Introduction,127.0.0.1,2023-05-13 08:07:50.258132+00:00,1,,,0,2,0,4,1,mugt25jb,,,,,,0 +9,k9v23vx9,,0,0,17,,,,,0,,,0,1,0,5,1,mugt25jb,,,,,,0 +10,1a5k98k4,,0,0,17,,,,,0,,,0,2,0,5,1,mugt25jb,,,,,,0 +1,pwg27fum,,0,18,17,survey,Demographics,127.0.0.1,2023-05-13 08:11:32.834582+00:00,1,,,155,1,0,1,1,1d33zgt8,,,,,,0 +2,trua2ysc,,0,18,17,survey,Demographics,127.0.0.1,2023-05-13 08:11:33.343669+00:00,1,,,145,2,0,1,1,1d33zgt8,,,,,,0 +3,gab9azw4,,0,7,17,dictator,Offer,127.0.0.1,2023-05-13 08:11:33.860623+00:00,1,,,12,1,0,2,1,1d33zgt8,,,,,,0 +4,6ox6u8dx,,0,6,17,dictator,Introduction,127.0.0.1,2023-05-13 08:11:34.419168+00:00,1,,,88,2,0,2,1,1d33zgt8,,,,,,0 diff --git a/inst/extdata/exp_data_2.2.4/chatapp_2023-05-13.xlsx b/inst/extdata/exp_data_2.2.4/chatapp_2023-05-13.xlsx new file mode 100644 index 0000000..093be55 Binary files /dev/null and b/inst/extdata/exp_data_2.2.4/chatapp_2023-05-13.xlsx differ diff --git a/inst/extdata/exp_data_2.2.4/dictator_2023-05-13.csv b/inst/extdata/exp_data_2.2.4/dictator_2023-05-13.csv new file mode 100644 index 0000000..b6462a5 --- /dev/null +++ b/inst/extdata/exp_data_2.2.4/dictator_2023-05-13.csv @@ -0,0 +1,43 @@ +participant.id_in_session,participant.code,participant.label,participant._is_bot,participant._index_in_pages,participant._max_page_index,participant._current_app_name,participant._current_page_name,participant.ip_address,participant.time_started,participant.visited,participant.mturk_worker_id,participant.mturk_assignment_id,participant.payoff,player.id_in_group,player.payoff,group.id_in_subsession,group.kept,subsession.round_number,session.code,session.label,session.experimenter_name,session.mturk_HITId,session.mturk_HITGroupId,session.comment,session.is_demo +1,giqwyeh7,Person1,0,15,17,survey,CognitiveReflectionTest,127.0.0.1,2023-05-13 08:07:44.394673+00:00,1,,,134,1,22,1,22,1,mugt25jb,,,,,,0 +2,ibauvcv6,Person2,0,18,17,survey,Demographics,127.0.0.1,2023-05-13 08:07:44.890091+00:00,1,,,166,2,78,1,22,1,mugt25jb,,,,,,0 +3,mqaatrt4,Person3,0,4,17,dictator,ResultsWaitPage,127.0.0.1,2023-05-13 08:07:45.825341+00:00,1,,,0,1,0,2,12,1,mugt25jb,,,,,,0 +4,k8tihf8g,Person4,0,1,17,start,Start,127.0.0.1,2023-05-13 08:07:46.509581+00:00,1,,,0,2,0,2,12,1,mugt25jb,,,,,,0 +5,xb5oapsv,Person5,0,18,17,survey,Demographics,127.0.0.1,2023-05-13 08:07:47.117394+00:00,1,,,189,1,87,3,87,1,mugt25jb,,,,,,0 +6,oh3pjgtd,Person6,0,17,17,survey,Demographics,127.0.0.1,2023-05-13 08:07:47.829122+00:00,1,,,111,2,13,3,87,1,mugt25jb,,,,,,0 +7,744avqxx,Person7,0,1,17,start,Start,127.0.0.1,2023-05-13 08:07:48.984720+00:00,1,,,0,1,0,4,,1,mugt25jb,,,,,,0 +8,u3jdbpav,Person8,0,2,17,dictator,Introduction,127.0.0.1,2023-05-13 08:07:50.258132+00:00,1,,,0,2,0,4,,1,mugt25jb,,,,,,0 +9,k9v23vx9,,0,0,17,,,,,0,,,0,1,0,5,,1,mugt25jb,,,,,,0 +10,1a5k98k4,,0,0,17,,,,,0,,,0,2,0,5,,1,mugt25jb,,,,,,0 +1,giqwyeh7,Person1,0,15,17,survey,CognitiveReflectionTest,127.0.0.1,2023-05-13 08:07:44.394673+00:00,1,,,134,1,22,1,22,2,mugt25jb,,,,,,0 +2,ibauvcv6,Person2,0,18,17,survey,Demographics,127.0.0.1,2023-05-13 08:07:44.890091+00:00,1,,,166,2,78,1,22,2,mugt25jb,,,,,,0 +3,mqaatrt4,Person3,0,4,17,dictator,ResultsWaitPage,127.0.0.1,2023-05-13 08:07:45.825341+00:00,1,,,0,1,0,2,,2,mugt25jb,,,,,,0 +4,k8tihf8g,Person4,0,1,17,start,Start,127.0.0.1,2023-05-13 08:07:46.509581+00:00,1,,,0,2,0,2,,2,mugt25jb,,,,,,0 +5,xb5oapsv,Person5,0,18,17,survey,Demographics,127.0.0.1,2023-05-13 08:07:47.117394+00:00,1,,,189,1,22,3,22,2,mugt25jb,,,,,,0 +6,oh3pjgtd,Person6,0,17,17,survey,Demographics,127.0.0.1,2023-05-13 08:07:47.829122+00:00,1,,,111,2,78,3,22,2,mugt25jb,,,,,,0 +7,744avqxx,Person7,0,1,17,start,Start,127.0.0.1,2023-05-13 08:07:48.984720+00:00,1,,,0,1,0,4,,2,mugt25jb,,,,,,0 +8,u3jdbpav,Person8,0,2,17,dictator,Introduction,127.0.0.1,2023-05-13 08:07:50.258132+00:00,1,,,0,2,0,4,,2,mugt25jb,,,,,,0 +9,k9v23vx9,,0,0,17,,,,,0,,,0,1,0,5,,2,mugt25jb,,,,,,0 +10,1a5k98k4,,0,0,17,,,,,0,,,0,2,0,5,,2,mugt25jb,,,,,,0 +1,giqwyeh7,Person1,0,15,17,survey,CognitiveReflectionTest,127.0.0.1,2023-05-13 08:07:44.394673+00:00,1,,,134,1,90,1,90,3,mugt25jb,,,,,,0 +2,ibauvcv6,Person2,0,18,17,survey,Demographics,127.0.0.1,2023-05-13 08:07:44.890091+00:00,1,,,166,2,10,1,90,3,mugt25jb,,,,,,0 +3,mqaatrt4,Person3,0,4,17,dictator,ResultsWaitPage,127.0.0.1,2023-05-13 08:07:45.825341+00:00,1,,,0,1,0,2,,3,mugt25jb,,,,,,0 +4,k8tihf8g,Person4,0,1,17,start,Start,127.0.0.1,2023-05-13 08:07:46.509581+00:00,1,,,0,2,0,2,,3,mugt25jb,,,,,,0 +5,xb5oapsv,Person5,0,18,17,survey,Demographics,127.0.0.1,2023-05-13 08:07:47.117394+00:00,1,,,189,1,80,3,80,3,mugt25jb,,,,,,0 +6,oh3pjgtd,Person6,0,17,17,survey,Demographics,127.0.0.1,2023-05-13 08:07:47.829122+00:00,1,,,111,2,20,3,80,3,mugt25jb,,,,,,0 +7,744avqxx,Person7,0,1,17,start,Start,127.0.0.1,2023-05-13 08:07:48.984720+00:00,1,,,0,1,0,4,,3,mugt25jb,,,,,,0 +8,u3jdbpav,Person8,0,2,17,dictator,Introduction,127.0.0.1,2023-05-13 08:07:50.258132+00:00,1,,,0,2,0,4,,3,mugt25jb,,,,,,0 +9,k9v23vx9,,0,0,17,,,,,0,,,0,1,0,5,,3,mugt25jb,,,,,,0 +10,1a5k98k4,,0,0,17,,,,,0,,,0,2,0,5,,3,mugt25jb,,,,,,0 +1,pwg27fum,,0,18,17,survey,Demographics,127.0.0.1,2023-05-13 08:11:32.834582+00:00,1,,,155,1,55,1,55,1,1d33zgt8,,,,,,0 +2,trua2ysc,,0,18,17,survey,Demographics,127.0.0.1,2023-05-13 08:11:33.343669+00:00,1,,,145,2,45,1,55,1,1d33zgt8,,,,,,0 +3,gab9azw4,,0,7,17,dictator,Offer,127.0.0.1,2023-05-13 08:11:33.860623+00:00,1,,,12,1,12,2,12,1,1d33zgt8,,,,,,0 +4,6ox6u8dx,,0,6,17,dictator,Introduction,127.0.0.1,2023-05-13 08:11:34.419168+00:00,1,,,88,2,88,2,12,1,1d33zgt8,,,,,,0 +1,pwg27fum,,0,18,17,survey,Demographics,127.0.0.1,2023-05-13 08:11:32.834582+00:00,1,,,155,1,50,1,50,2,1d33zgt8,,,,,,0 +2,trua2ysc,,0,18,17,survey,Demographics,127.0.0.1,2023-05-13 08:11:33.343669+00:00,1,,,145,2,50,1,50,2,1d33zgt8,,,,,,0 +3,gab9azw4,,0,7,17,dictator,Offer,127.0.0.1,2023-05-13 08:11:33.860623+00:00,1,,,12,1,0,2,,2,1d33zgt8,,,,,,0 +4,6ox6u8dx,,0,6,17,dictator,Introduction,127.0.0.1,2023-05-13 08:11:34.419168+00:00,1,,,88,2,0,2,,2,1d33zgt8,,,,,,0 +1,pwg27fum,,0,18,17,survey,Demographics,127.0.0.1,2023-05-13 08:11:32.834582+00:00,1,,,155,1,50,1,50,3,1d33zgt8,,,,,,0 +2,trua2ysc,,0,18,17,survey,Demographics,127.0.0.1,2023-05-13 08:11:33.343669+00:00,1,,,145,2,50,1,50,3,1d33zgt8,,,,,,0 +3,gab9azw4,,0,7,17,dictator,Offer,127.0.0.1,2023-05-13 08:11:33.860623+00:00,1,,,12,1,0,2,,3,1d33zgt8,,,,,,0 +4,6ox6u8dx,,0,6,17,dictator,Introduction,127.0.0.1,2023-05-13 08:11:34.419168+00:00,1,,,88,2,0,2,,3,1d33zgt8,,,,,,0 diff --git a/inst/extdata/exp_data_2.2.4/dictator_2023-05-13.xlsx b/inst/extdata/exp_data_2.2.4/dictator_2023-05-13.xlsx new file mode 100644 index 0000000..fd495ce Binary files /dev/null and b/inst/extdata/exp_data_2.2.4/dictator_2023-05-13.xlsx differ diff --git a/inst/extdata/exp_data_2.2.4/note.txt b/inst/extdata/exp_data_2.2.4/note.txt new file mode 100644 index 0000000..d115a31 --- /dev/null +++ b/inst/extdata/exp_data_2.2.4/note.txt @@ -0,0 +1 @@ +It was not possible to download only the session data. \ No newline at end of file diff --git a/inst/extdata/exp_data_2.2.4/start_2023-05-13.csv b/inst/extdata/exp_data_2.2.4/start_2023-05-13.csv new file mode 100644 index 0000000..badcae9 --- /dev/null +++ b/inst/extdata/exp_data_2.2.4/start_2023-05-13.csv @@ -0,0 +1,15 @@ +participant.id_in_session,participant.code,participant.label,participant._is_bot,participant._index_in_pages,participant._max_page_index,participant._current_app_name,participant._current_page_name,participant.ip_address,participant.time_started,participant.visited,participant.mturk_worker_id,participant.mturk_assignment_id,participant.payoff,player.id_in_group,player.payoff,group.id_in_subsession,subsession.round_number,session.code,session.label,session.experimenter_name,session.mturk_HITId,session.mturk_HITGroupId,session.comment,session.is_demo +1,giqwyeh7,Person1,0,15,17,survey,CognitiveReflectionTest,127.0.0.1,2023-05-13 08:07:44.394673+00:00,1,,,134,1,0,1,1,mugt25jb,,,,,,0 +2,ibauvcv6,Person2,0,18,17,survey,Demographics,127.0.0.1,2023-05-13 08:07:44.890091+00:00,1,,,166,2,0,1,1,mugt25jb,,,,,,0 +3,mqaatrt4,Person3,0,4,17,dictator,ResultsWaitPage,127.0.0.1,2023-05-13 08:07:45.825341+00:00,1,,,0,3,0,1,1,mugt25jb,,,,,,0 +4,k8tihf8g,Person4,0,1,17,start,Start,127.0.0.1,2023-05-13 08:07:46.509581+00:00,1,,,0,4,0,1,1,mugt25jb,,,,,,0 +5,xb5oapsv,Person5,0,18,17,survey,Demographics,127.0.0.1,2023-05-13 08:07:47.117394+00:00,1,,,189,5,0,1,1,mugt25jb,,,,,,0 +6,oh3pjgtd,Person6,0,17,17,survey,Demographics,127.0.0.1,2023-05-13 08:07:47.829122+00:00,1,,,111,6,0,1,1,mugt25jb,,,,,,0 +7,744avqxx,Person7,0,1,17,start,Start,127.0.0.1,2023-05-13 08:07:48.984720+00:00,1,,,0,7,0,1,1,mugt25jb,,,,,,0 +8,u3jdbpav,Person8,0,2,17,dictator,Introduction,127.0.0.1,2023-05-13 08:07:50.258132+00:00,1,,,0,8,0,1,1,mugt25jb,,,,,,0 +9,k9v23vx9,,0,0,17,,,,,0,,,0,9,0,1,1,mugt25jb,,,,,,0 +10,1a5k98k4,,0,0,17,,,,,0,,,0,10,0,1,1,mugt25jb,,,,,,0 +1,pwg27fum,,0,18,17,survey,Demographics,127.0.0.1,2023-05-13 08:11:32.834582+00:00,1,,,155,1,0,1,1,1d33zgt8,,,,,,0 +2,trua2ysc,,0,18,17,survey,Demographics,127.0.0.1,2023-05-13 08:11:33.343669+00:00,1,,,145,2,0,1,1,1d33zgt8,,,,,,0 +3,gab9azw4,,0,7,17,dictator,Offer,127.0.0.1,2023-05-13 08:11:33.860623+00:00,1,,,12,3,0,1,1,1d33zgt8,,,,,,0 +4,6ox6u8dx,,0,6,17,dictator,Introduction,127.0.0.1,2023-05-13 08:11:34.419168+00:00,1,,,88,4,0,1,1,1d33zgt8,,,,,,0 diff --git a/inst/extdata/exp_data_2.2.4/start_2023-05-13.xlsx b/inst/extdata/exp_data_2.2.4/start_2023-05-13.xlsx new file mode 100644 index 0000000..ff267ea Binary files /dev/null and b/inst/extdata/exp_data_2.2.4/start_2023-05-13.xlsx differ diff --git a/inst/extdata/exp_data_2.2.4/survey_2023-05-13.csv b/inst/extdata/exp_data_2.2.4/survey_2023-05-13.csv new file mode 100644 index 0000000..97ae901 --- /dev/null +++ b/inst/extdata/exp_data_2.2.4/survey_2023-05-13.csv @@ -0,0 +1,15 @@ +participant.id_in_session,participant.code,participant.label,participant._is_bot,participant._index_in_pages,participant._max_page_index,participant._current_app_name,participant._current_page_name,participant.ip_address,participant.time_started,participant.visited,participant.mturk_worker_id,participant.mturk_assignment_id,participant.payoff,player.id_in_group,player.age,player.gender,player.crt_bat,player.crt_widget,player.crt_lake,player.payoff,group.id_in_subsession,subsession.round_number,session.code,session.label,session.experimenter_name,session.mturk_HITId,session.mturk_HITGroupId,session.comment,session.is_demo +1,giqwyeh7,Person1,0,15,17,survey,CognitiveReflectionTest,127.0.0.1,2023-05-13 08:07:44.394673+00:00,1,,,134,1,,,,,,0,1,1,mugt25jb,,,,,,0 +2,ibauvcv6,Person2,0,18,17,survey,Demographics,127.0.0.1,2023-05-13 08:07:44.890091+00:00,1,,,166,2,90,Male,1,5,2,0,1,1,mugt25jb,,,,,,0 +3,mqaatrt4,Person3,0,4,17,dictator,ResultsWaitPage,127.0.0.1,2023-05-13 08:07:45.825341+00:00,1,,,0,3,,,,,,0,1,1,mugt25jb,,,,,,0 +4,k8tihf8g,Person4,0,1,17,start,Start,127.0.0.1,2023-05-13 08:07:46.509581+00:00,1,,,0,4,,,,,,0,1,1,mugt25jb,,,,,,0 +5,xb5oapsv,Person5,0,18,17,survey,Demographics,127.0.0.1,2023-05-13 08:07:47.117394+00:00,1,,,189,5,39,Female,42,1,1,0,1,1,mugt25jb,,,,,,0 +6,oh3pjgtd,Person6,0,17,17,survey,Demographics,127.0.0.1,2023-05-13 08:07:47.829122+00:00,1,,,111,6,,,70,2,10,0,1,1,mugt25jb,,,,,,0 +7,744avqxx,Person7,0,1,17,start,Start,127.0.0.1,2023-05-13 08:07:48.984720+00:00,1,,,0,7,,,,,,0,1,1,mugt25jb,,,,,,0 +8,u3jdbpav,Person8,0,2,17,dictator,Introduction,127.0.0.1,2023-05-13 08:07:50.258132+00:00,1,,,0,8,,,,,,0,1,1,mugt25jb,,,,,,0 +9,k9v23vx9,,0,0,17,,,,,0,,,0,9,,,,,,0,1,1,mugt25jb,,,,,,0 +10,1a5k98k4,,0,0,17,,,,,0,,,0,10,,,,,,0,1,1,mugt25jb,,,,,,0 +1,pwg27fum,,0,18,17,survey,Demographics,127.0.0.1,2023-05-13 08:11:32.834582+00:00,1,,,155,1,90,Male,1,3,76,0,1,1,1d33zgt8,,,,,,0 +2,trua2ysc,,0,18,17,survey,Demographics,127.0.0.1,2023-05-13 08:11:33.343669+00:00,1,,,145,2,33,Male,3,7,1,0,1,1,1d33zgt8,,,,,,0 +3,gab9azw4,,0,7,17,dictator,Offer,127.0.0.1,2023-05-13 08:11:33.860623+00:00,1,,,12,3,,,,,,0,1,1,1d33zgt8,,,,,,0 +4,6ox6u8dx,,0,6,17,dictator,Introduction,127.0.0.1,2023-05-13 08:11:34.419168+00:00,1,,,88,4,,,,,,0,1,1,1d33zgt8,,,,,,0 diff --git a/inst/extdata/exp_data_2.2.4/survey_2023-05-13.xlsx b/inst/extdata/exp_data_2.2.4/survey_2023-05-13.xlsx new file mode 100644 index 0000000..707ca33 Binary files /dev/null and b/inst/extdata/exp_data_2.2.4/survey_2023-05-13.xlsx differ diff --git a/inst/extdata/exp_data_5.4.0/ChatMessages-2023-05-16.csv b/inst/extdata/exp_data_5.4.0/ChatMessages-2023-05-16.csv new file mode 100644 index 0000000..b197919 --- /dev/null +++ b/inst/extdata/exp_data_5.4.0/ChatMessages-2023-05-16.csv @@ -0,0 +1,7 @@ +session_code,id_in_session,participant_code,channel,nickname,body,timestamp +jk9ekpl0,2,vbuvng7x,2-chatapp-2,Participant 2,this is a test,1684257978.108514 +jk9ekpl0,1,sdh9ar2m,2-chatapp-2,Participant 1,asdfasdfääääpüüüß,1684257984.2444334 +jk9ekpl0,2,vbuvng7x,2-chatapp-2,Participant 2,<= "3.4") withAutoprint else force)(\{ # examplesIf} +# Set data folder first +withr::with_dir(system.file("extdata", package = "gmoTree"), { + +# Import all oTree files in this folder and its subfolders +oTree <- import_otree() +}) + +# First, show some row numbers +print(paste(nrow(oTree$all_apps_wide), nrow(oTree$survey), +nrow(oTree$Time), nrow(oTree$Chats))) + +# Delete duplicate rows +oTree <- delete_duplicate(oTree) + +# Show row numbers again +print(paste(nrow(oTree$all_apps_wide), nrow(oTree$survey), +nrow(oTree$Time), nrow(oTree$Chats))) +\dontshow{\}) # examplesIf} +} +\keyword{oTree} diff --git a/man/delete_plabels.Rd b/man/delete_plabels.Rd new file mode 100644 index 0000000..74e7f1c --- /dev/null +++ b/man/delete_plabels.Rd @@ -0,0 +1,44 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/delete_plabels.R +\name{delete_plabels} +\alias{delete_plabels} +\title{Delete participant labels in all apps} +\usage{ +delete_plabels(oTree, del_plabel = TRUE, del_mturk = TRUE) +} +\arguments{ +\item{oTree}{A list of data frames that were created by import_otree().} + +\item{del_plabel}{Logical. +TRUE if all participant labels should be deleted.} + +\item{del_mturk}{Logical. +TRUE if all MTurk variables should be deleted.} +} +\value{ +This function returns a duplicate of the original oTree list of +data frames that do not include the participant labels and/or the MTurk +variables. +} +\description{ +If you work with MTurk, the MTurk IDs will be stored in the +participant labels variable. +This function deletes this variable in all_apps_wide and every app data frame +in the list of data frames that was created by import_otree() and/or all +variables referring to MTurk, such as participant.mturk_worker_id. +} +\examples{ +# Use package-internal list of oTree data frames +oTree <- gmoTree::oTree + +# Show participant labels +oTree$all_apps_wide$participant.label +oTree$survey$participant.label + +# Delete all participant labels +oTree2 <- delete_plabels(oTree) + +# Show participant labels again +oTree2$all_apps_wide$participant.label +oTree2$survey$participant.label +} diff --git a/man/delete_sessions.Rd b/man/delete_sessions.Rd new file mode 100644 index 0000000..d2e686a --- /dev/null +++ b/man/delete_sessions.Rd @@ -0,0 +1,82 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/delete_sessions.R +\name{delete_sessions} +\alias{delete_sessions} +\title{Delete all cases of one session} +\usage{ +delete_sessions(oTree, scodes, saved_vars = NULL, reason, info = FALSE) +} +\arguments{ +\item{oTree}{A list of data frames that were created by import_otree().} + +\item{scodes}{Character. The session.code(s) of the +session(s) whose data should be removed.} + +\item{saved_vars}{Character. The name(s) of variable(s) that need(s) to be +stored in the list of information on deleted cases in $info$deleted_cases.} + +\item{reason}{Character. The reason for deletion that should be stored in +the list of information on deleted cases in $info$deleted_cases.} + +\item{info}{Logical. TRUE if a brief information on the session +deletion process should be printed.} +} +\value{ +This function returns a duplicate of the original oTree list of +data frames that do not include the deleted sessions. + +It adds information on the deleted cases to $info$deleted_cases. (This +list is also filled by other functions.) + +In this list, you can find the following information: + +$full and $unique = The data frames $full and $unique contain +information on all participants +whose data were deleted. The entries to the $full and the $unique data +frames in this list are the same. Columns "end_app" and "end_page" are left +empty intentionally because they are only filled by the delete_dropouts() +function. Columns "participant.code" and "reason" are filled. + +$codes = A vector containing the participant codes of +all deleted participants. + +$count = The number of all deleted participants. +} +\description{ +Delete cases from specific sessions in all data frames in the +oTree list of data frames. + +Caution 1: This function does not delete cases from the +original CSV and Excel files! + +Caution 2: This function does not delete cases from custom exports if the +custom exports do not have a variable named participant.code and a variable +named session.code! +} +\examples{ +# Use package-internal list of oTree data frames +oTree <- gmoTree::oTree + +# First, show some row numbers +print(paste(nrow(oTree$all_apps_wide), nrow(oTree$survey), +nrow(oTree$Time), nrow(oTree$Chats))) + +# Delete one session +oTree2 <- delete_sessions(oTree, + scodes = "7bfqtokx", + reason = "Only tests") + +# Show row numbers +print(paste(nrow(oTree2$all_apps_wide), nrow(oTree2$survey), +nrow(oTree2$Time), nrow(oTree2$Chats))) + +# Delete two sessions +oTree2 <- delete_sessions(oTree, + scodes = c("7bfqtokx", "vd1h01iv"), + reason = "Only tests") + +# Show row numbers again +print(paste(nrow(oTree2$all_apps_wide), nrow(oTree2$survey), +nrow(oTree2$Time), nrow(oTree2$Chats))) +} +\keyword{oTree} diff --git a/man/extime.Rd b/man/extime.Rd new file mode 100644 index 0000000..eabc991 --- /dev/null +++ b/man/extime.Rd @@ -0,0 +1,98 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/extime.R +\name{extime} +\alias{extime} +\title{Calculate the time that was spent on the whole experiment} +\usage{ +extime( + oTree, + pcode = NULL, + plabel = NULL, + group_id = NULL, + seconds = FALSE, + rounded = TRUE, + digits = 2, + startat = 1, + tz = "UTC", + sinfo = "session_code", + combine = TRUE +) +} +\arguments{ +\item{oTree}{A list of data frames that were created by import_otree().} + +\item{pcode}{Character. The value of the participant.code variable if the +time should only be calculated for one specified participant.} + +\item{plabel}{Character. The value of the participant.label variable if the +time should only be calculated for one specified participant.} + +\item{group_id}{Integer. The value of the group_id variable if the +time should only be calculated for one specified group. The group_id +variable can be created with make_ids().} + +\item{seconds}{Logical. +TRUE if the output should be in seconds instead of minutes.} + +\item{rounded}{Logical. TRUE if the output should be rounded.} + +\item{digits}{Integer. The number of digits to which the output +should be rounded. +This parameter has no effect unless rounded = TRUE.} + +\item{startat}{Integer or character string "real". +Whether the start of the experiment should be taken from the time at +a certain index of each person's vector of page_indexes in the +Time data frame or from the "time_started" +variable in all_apps_wide ("real"). Important: If integer, +it represents the position within the page index sequence, +not the numeric value of the index.} + +\item{tz}{Character. Time zone.} + +\item{sinfo}{Character. +"session_id" to use session ID for additional information in the data frame +of single durations, "session_code" to use session codes, or NULL if no +session column should be shown.} + +\item{combine}{Logical. TRUE if all variables referring to epoch time should +be merged, and all variables referring to participant code should +be merged in case data of several versions of oTree are used. If FALSE, +the function returns an error if several oTree versions' data are present.} +} +\value{ +This function returns either a single value if only the data of one person +is calculated or a list of information on the time several participants +spent on the experiment. + +In this list, you can find the following information: + +$mean_duration = The experiment's average duration. + +$min_duration = The experiment's minimum duration. + +$max_duration = The experiment's maximum duration. + +$single_durations = A data frame of all durations that +are used for calculating the min, max, and mean duration. + +$messages = All important notes to the calculations. + +$only_one_page = A vector of all individuals who only have one time stamp. +} +\description{ +Calculate the time spent on the experiment. +If not stated otherwise, the calculation only starts at the end of +the first page! +} +\examples{ +# Use package-internal list of oTree data frames +oTree <- gmoTree::oTree + +# Make a data frame of durations +extime(oTree) + +# Show time for one participant +extime(oTree, pcode = "wk247s9w") +} +\keyword{oTree} diff --git a/man/import_otree.Rd b/man/import_otree.Rd new file mode 100644 index 0000000..4df88b5 --- /dev/null +++ b/man/import_otree.Rd @@ -0,0 +1,166 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/import_otree.R +\name{import_otree} +\alias{import_otree} +\title{Import oTree data} +\usage{ +import_otree( + path = ".", + file_names = NULL, + final_apps = NULL, + final_pages = NULL, + recursive = TRUE, + csv = TRUE, + onlybots = FALSE, + del_empty = TRUE, + info = FALSE, + encoding = "UTF-8" +) +} +\arguments{ +\item{path}{Character. The path to the files (default is the +working directory).} + +\item{file_names}{Character. The name(s) of the file(s) to be imported. +If not specified, all files in the path and subfolders are imported.} + +\item{final_apps}{Character. +The name(s) of the app(s) at which the participants have to finish the +experiment. If the argument final_apps is left empty, you can still call +for deleting the participants who did not finish the experiment with +delete_dropouts().} + +\item{final_pages}{Character. +The name(s) of the page(s) at which the participants have to finish the +experiment. If the argument final_pages is left empty, you can still +call for deleting the participants who did not finish the experiment +with delete_dropouts().} + +\item{recursive}{Logical. TRUE if the files in the path's +subfolders should also be imported.} + +\item{csv}{Logical. +TRUE if only CSV files should be imported. +FALSE if only Excel files should be imported.} + +\item{onlybots}{Logical. TRUE if only bot-created files should be imported.} + +\item{del_empty}{Logical. TRUE if all empty cases should be deleted from the +all_apps_wide or normal app data frames (not Time or Chats).} + +\item{info}{Logical. TRUE if a brief information on the data import should be +printed.} + +\item{encoding}{Character. Encoding of the CSV files that are imported. +Default is "UTF-8".} +} +\value{ +Returns a list of data frames (one data frame for each app and +all_apps_wide) and a list of information on this list of data frames +in $info. + +See detailed information on the imported files in $info$imported_files. + +If all_apps_wide is imported, see the number of imported cases +in $info$initial_n. In this number, empty rows are +already considered. So, if empty rows are deleted with del_empty=TRUE, +initial_n counts all rows that are not empty. +Cases that are deleted because the participants did not make it to the +last page and/or app are not subtracted from this number. + +Information: Empty rows are rows without the "participant._current_app_name" +variable set. Empty rows are deleted from all app data frames and +all_apps_wide when using del_empty=TRUE. Empty rows in the Chats and Time +data frames are not deleted. + +If old and new oTree versions are combined, the Time data frame contains +variables called "participant_code" and "participant__code" +(the difference is in the underscores). +Caution! If there is an unusual amount of NAs, +check if everything got imported correctly. +Sometimes, the CSV or Excel file may be corrupted, and all information is +only found in one column. +} +\description{ +Import data files that were created by oTree. +All files containing the pattern YYYY-MM-DD at the end +of their file names are considered oTree files. +Bot outputs are saved by oTree without the date included. Hence, to +import bot data, you must either rename the original bot files +using the YYYY-MM-DD format or use the argument "onlybots = TRUE." +By using the second option, only data of bot files are imported. + +Caution! Data can be downloaded from within the +session and globally at the same time. If both files are downloaded, +this can lead to the all_apps_wide data being there twice! You can remove +duplicate data by using delete_duplicate(). + +Caution! When importing Excel files, this function does not check +for erroneous data structures +and will combine all data frames with the same file name patterns. +Before using the "CSV = FALSE" argument, clean up your data appropriately. +} +\examples{ +\dontshow{if (rlang::is_installed("withr")) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} +# Set data folder first +withr::with_dir(system.file("extdata", package = "gmoTree"), { + +# Import all oTree files in this folder and its subfolders +oTree <- import_otree() + +# Show the structure of the import +str(oTree, max.level = 1) + +# Show the names of all imported files +oTree$info$imported_files + +# Delete empty cases and delete every case of a person +# who didn't end the experiment in the app "survey" +oTree <- import_otree( + del_empty = TRUE, + final_apps = "survey", + info = TRUE) + +# Show the structure of the import +str(oTree, max.level = 1) + +# Import bot files +import_otree( + path = "./bot_data", + onlybots = TRUE, + csv = TRUE, + info = TRUE) + +# Show the structure of the import +str(oTree, max.level = 1) + +# Import with file names (path separately) +oTree2 <- import_otree( + del_empty = TRUE, + path = "./exp_data", + file_names = c("all_apps_wide-2023-03-27.csv", + "ChatMessages-2023-03-27.csv", + "PageTimes-2023-03-27.csv"), + onlybots = FALSE, + csv = TRUE, + info = TRUE) + +# Show the structure of the import +str(oTree, max.level = 1) + +# Import with file names (without path separately) +oTree2 <- import_otree( + del_empty = TRUE, + file_names = c("exp_data/all_apps_wide-2023-03-27.csv", + "exp_data/ChatMessages-2023-03-27.csv", + "exp_data/PageTimes-2023-03-27.csv"), + onlybots = FALSE, + csv = TRUE, + info = TRUE) + +# Show the structure of the import +str(oTree, max.level = 1) +}) +\dontshow{\}) # examplesIf} +} +\keyword{oTree} diff --git a/man/make_ids.Rd b/man/make_ids.Rd new file mode 100644 index 0000000..29a3618 --- /dev/null +++ b/man/make_ids.Rd @@ -0,0 +1,105 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/make_ids.R +\name{make_ids} +\alias{make_ids} +\title{Make IDs} +\usage{ +make_ids( + oTree, + gmake = FALSE, + pmake = TRUE, + from_app = "all_apps_wide", + from_var = NULL, + sstart = 1, + gstart = 1, + pstart = 1, + emptyrows = NULL, + icw = FALSE +) +} +\arguments{ +\item{oTree}{A list of data frames that were created by import_otree().} + +\item{gmake}{Logical. TRUE if a variable called group_id should be made. +If from_var is not NULL, gmake is automatically set to TRUE.} + +\item{pmake}{Logical. TRUE if a variable called participant_id +should be made.} + +\item{from_app}{Character. Name of the data frame from which the session, +group, and participant information should be taken. +All normal app data frames and all_apps_wide are allowed.} + +\item{from_var}{Character. Name of the variable from which the group +information should be taken. This argument is only relevant when +all_apps_wide is used as from_app and has group information that contradicts +each other.} + +\item{sstart}{Integer. +The number that serves as a starting point for session IDs.} + +\item{gstart}{Integer. +The number that serves as a starting point for group IDs.} + +\item{pstart}{Integer. +The number that serves as a starting point for participant IDs.} + +\item{emptyrows}{Character. "no" if the function should stop if there are +empty rows in from_app. "yes" if the function should continue to make IDs.} + +\item{icw}{Logical. TRUE if the warning message should be +ignored that states that IDs cannot be made because of an oTree bug.} +} +\value{ +ID variables are made in all_apps_wide, all app data frames, +the Time data frame, and the Chats data frame. +See list of the additional ID variables in $info$additional_variables. +} +\description{ +Make session IDs and, optionally, group IDs and participant IDs +that span across all data frames created by +import_otree(). Information for these IDs is taken from all_apps_wide +but can be defined otherwise. + +Note: Older versions of oTree may already contain a +variable called session_id in their Time data frames. +This variable is overwritten by this function! + +Important: Combine duplicate data before running this function! +} +\examples{ +# Use package-internal list of oTree data frames +oTree <- gmoTree::oTree + +# Make session IDs only +oTree2 <- make_ids(oTree) + +# Show new variables +oTree2$all_apps_wide$session_id + +# Make session IDs and group IDs # +# Not working with this data set because group ID is not the same in all apps +# oTree2 <- make_ids(oTree, gmake = TRUE) + +# Show new variables +# oTree2$all_apps_wide$session_id +# oTree2$all_apps_wide$group_id + +# Get IDs from variable "dictator.1.group.id_in_subsession" +# in the data frame "all_apps_wide" +oTree2 <- make_ids(oTree, + gmake = TRUE, + from_var = "dictator.1.group.id_in_subsession") + +# Show new variables +oTree2$all_apps_wide$session_id +oTree2$all_apps_wide$group_id + +# Get IDs from another app than all_apps_wide +oTree2 <- make_ids(oTree, gmake = TRUE, from_app = "dictator") + +# Show new variables +oTree2$all_apps_wide$session_id +oTree2$all_apps_wide$group_id +} +\keyword{oTree} diff --git a/man/messy_chat.Rd b/man/messy_chat.Rd new file mode 100644 index 0000000..eeb7423 --- /dev/null +++ b/man/messy_chat.Rd @@ -0,0 +1,75 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/messy_chat.R +\name{messy_chat} +\alias{messy_chat} +\title{Check if the Chats data frame is messy} +\usage{ +messy_chat( + oTree, + combine = FALSE, + session = TRUE, + participant = TRUE, + info = FALSE +) +} +\arguments{ +\item{oTree}{A list of data frames that were created by import_otree().} + +\item{combine}{Logical. TRUE if all variables referring to +the session code should be merged and/or all variables referring +to participant code should be merged in case data of several versions +of oTree are used.} + +\item{session}{Logical. TRUE if all variables referring to the session code +should be checked and merged. Merging only works if combine = TRUE.} + +\item{participant}{Logical. TRUE if all variables referring to the +participant code should be checked and merged. Merging only works if +combine = TRUE.} + +\item{info}{Logical. TRUE if a brief information on the process should +be printed.} +} +\value{ +This function returns an oTree list of data frames that is +an exact copy of the original oTree list of data frames but - if the user +wishes to do so - combines the participant code and session code +variables in the Chats data frame if several variables are referring to +those because of the +combination of different oTree versions. The final variables are called +participant_code and session_code. + +If combine = FALSE, the function only checks for the existence of several +variables referring to the participant code and session code and throws an +error if yes. +} +\description{ +Check if the Chats data frame includes both +session-related variables and participant-related variables that +appear multiple times. This may occur when data from different +oTree versions, which use different variable names, are combined. + +If desired, the function can merge these variables, +storing the data using the newer oTree version's variable names +and removing the outdated variables. +} +\examples{ +\dontshow{if (rlang::is_installed("withr")) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} +# Set data folder first +withr::with_dir(system.file("extdata", package = "gmoTree"), { + +# Import all oTree files in this folder and its subfolders +oTree <- import_otree() +}) + +# Show all Chats column names +print(colnames(oTree$Chats)) + +# Run function +oTree <- messy_chat(oTree, combine = TRUE) + +# Show all Chats column names again +print(colnames(oTree$Chats)) +\dontshow{\}) # examplesIf} +} +\keyword{oTree} diff --git a/man/messy_time.Rd b/man/messy_time.Rd new file mode 100644 index 0000000..e3889cd --- /dev/null +++ b/man/messy_time.Rd @@ -0,0 +1,73 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/messy_time.R +\name{messy_time} +\alias{messy_time} +\title{Check if the Time data frame is messy} +\usage{ +messy_time( + oTree, + combine = FALSE, + epoch_time = TRUE, + participant = TRUE, + info = FALSE +) +} +\arguments{ +\item{oTree}{A list of data frames that were created by import_otree().} + +\item{combine}{Logical. TRUE if all variables referring to epoch time should +be merged and/or all variables referring to participant code should be merged +in case data of several versions of oTree are used.} + +\item{epoch_time}{Logical. TRUE if all variables referring to the time stamp +should be checked and merged. Only works if combine = TRUE.} + +\item{participant}{Logical. TRUE if all variables referring to the +participant code should be checked and merged. Only works if combine = TRUE.} + +\item{info}{Logical. TRUE if a brief information on the process should +be printed.} +} +\value{ +This function returns an oTree list of data frames that is +an exact copy of the original oTree list of data frames but - if the user +wishes to do so - combines the +time tamps and participant codes in the Time data frame if several variables +are referring to those because of the +combination of different oTree versions. The final variables are called +epoch_time_completed and participant_code. + +If combine = FALSE, the function only checks for the existence of several +variables referring to the time stamp or the participant code and throws an +error if yes. +} +\description{ +Check if the Time data frame includes both participant-related variables +and time stamp variables that appear multiple times. This may occur when +data from different oTree versions, which use different variable names, +are combined. + +If desired, the function can merge these variables, +storing the data using the newer oTree version's variable names +and removing the outdated variables. +} +\examples{ +\dontshow{if (rlang::is_installed("withr")) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} +# Set data folder first +withr::with_dir(system.file("extdata", package = "gmoTree"), { + +# Import all oTree files in this folder and its subfolders +oTree <- import_otree() +}) + +# Show all Time column names +print(colnames(oTree$Time)) + +# Run function +oTree <- messy_time(oTree, combine = TRUE) + +# Show all Time column names again +print(colnames(oTree$Time)) +\dontshow{\}) # examplesIf} +} +\keyword{oTree} diff --git a/man/oTree.Rd b/man/oTree.Rd new file mode 100644 index 0000000..00e1df5 --- /dev/null +++ b/man/oTree.Rd @@ -0,0 +1,21 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/oTree.R +\docType{data} +\name{oTree} +\alias{oTree} +\title{Sample experiment data} +\format{ +A list of data frames created by import_otree(). +} +\source{ +The data set was created by using modified versions of the official +oTree sample experiments that can be downloaded when installing oTree. +In detail, the following apps were used: "dictator," "chatapp," "survey." +} +\usage{ +oTree +} +\description{ +Sample experiment data +} +\keyword{datasets} diff --git a/man/pagesec.Rd b/man/pagesec.Rd new file mode 100644 index 0000000..9335fd7 --- /dev/null +++ b/man/pagesec.Rd @@ -0,0 +1,44 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/pagesec.R +\name{pagesec} +\alias{pagesec} +\title{Calculate the seconds spent on each page} +\usage{ +pagesec(oTree, rounded = TRUE, digits = 2, minutes = FALSE, combine = FALSE) +} +\arguments{ +\item{oTree}{A list of data frames that were created by import_otree().} + +\item{rounded}{Logical. TRUE if the output should be rounded.} + +\item{digits}{Integer. The number of digits to which the +output should be rounded. +This parameter has no effect unless rounded = TRUE.} + +\item{minutes}{Logical. TRUE if the output should be +minutes instead of seconds.} + +\item{combine}{Logical. TRUE if all variables referring to epoch time should +be merged, and all variables referring to participant code should be +merged in case data of several versions of oTree are used.} +} +\value{ +This function returns a duplicate of the original oTree list of +data frames that also contains a column in the Time data frame named +seconds_on_page2 or minutes_on_page. +} +\description{ +Create a new variable in the Time data frame that contains the time +spent on each page. +} +\examples{ +# Use package-internal list of oTree data frames +oTree <- gmoTree::oTree + +# Create two new columns: seconds_on_page2 and minutes_on_page +oTree <- pagesec(oTree, rounded = TRUE, minutes = TRUE) + +# Show the Time data frame +head(oTree$Time, n = 30) +} +\keyword{oTree} diff --git a/man/show_constant.Rd b/man/show_constant.Rd new file mode 100644 index 0000000..a79f215 --- /dev/null +++ b/man/show_constant.Rd @@ -0,0 +1,41 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/show_constant.R +\name{show_constant} +\alias{show_constant} +\title{Show constant columns} +\usage{ +show_constant(oTree, value = "any") +} +\arguments{ +\item{oTree}{A list of data frames that were created by import_otree().} + +\item{value}{The value that is controlled to be the same within a column. +The default is NA. If the value is set to "any," the function checks for +columns where any possible values are identical.} +} +\value{ +This function returns a list of vectors, one for each app, +all_apps_wide, the Time and/or the Chats data frame. +Each vector contains the names of all variables with constant values. +If there are no variables with constant values, the vector is empty. +} +\description{ +Show all columns with no variation in their values for each data frame +in the oTree list of data frames (except the ones in the info list). +This function is helpful before running an experiment to check if there +are unnecessary variables. +You can check for columns that have any unchanging possible value +or for columns containing only a specific value. +} +\examples{ +# Use package-internal list of oTree data frames +oTree <- gmoTree::oTree + +# Show all columns that contain only NAs +show_constant(oTree = oTree) +show_constant(oTree = oTree, value = NA) + +# Show all columns that contain only -99 +show_constant(oTree = oTree, value = -99) +} +\keyword{oTree} diff --git a/man/show_dropouts.Rd b/man/show_dropouts.Rd new file mode 100644 index 0000000..484c079 --- /dev/null +++ b/man/show_dropouts.Rd @@ -0,0 +1,84 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/show_dropouts.R +\name{show_dropouts} +\alias{show_dropouts} +\title{Show participants who did not finish the experiment} +\usage{ +show_dropouts(oTree, final_apps = NULL, final_pages = NULL, saved_vars = NULL) +} +\arguments{ +\item{oTree}{A list of data frames that were created by import_otree().} + +\item{final_apps}{Character. +The name(s) of the app(s) at which the participants have to finish the +experiment.} + +\item{final_pages}{Character. +The name(s) of the page(s) at which the participants have to finish the +experiment.} + +\item{saved_vars}{The name(s) of variable(s) that need(s) to be +shown in the list of information on dropout cases.} +} +\value{ +This function returns a list of information on participants who did not +finish the experiment. + +In this list, you can find the following information: + +$full = A data frame that contains information +on all participants who did not finish the study; +it shows their participant codes, the names of the apps in which they +left the experiment, +the names of the pages in which they left the experiment, +the names of the app data frames in which this information was found, and +the dropout reason ("ENC," experiment not completed, combined +with the name of the data frame in which the dropout was observed). +Because participants usually appear in multiple app data frames, +the $full data frame may contain several entries for +each person. + +$unique = A data frame that contains similar information as the $full data +frame but with only one row per participant and no information on the data +frame in which the dropout was observed. + +$all_end = A table that provides information on the app and page combinations +where participants ended the experiment. This table also includes +information on participants who did not drop out of the experiment. +The $all_end table is only shown if an all_apps_wide data frame exists. + +$codes = A vector containing the participant codes of +all participants who did not finish the experiment. + +$count = The number of all participants who did not finish the experiment. + +It is important to note that if only the argument final_pages is set, +this function does not distinguish between page names that reoccur in +different apps. + +If the columns end_app and end_page in the output are empty, +these variables were not saved by oTree for the specific participants. +This could be because empty rows were not deleted. This can be done +by using the argument "del_empty = TRUE" when using import_otree(). +} +\description{ +Show information on the people who did not finish the experiment at (a) +certain page(s) and/or app(s). +} +\examples{ +# Use package-internal list of oTree data frames +oTree <- gmoTree::oTree + +# Show everyone who did not finish with the app "survey" +show_dropouts(oTree, final_apps = "survey") + +# Show everyone who did not finish with the page "Demographics" +show_dropouts(oTree, final_pages = "Demographics") + +# Show everyone who finished with the following apps: "survey," "dictator" +final_apps <- unique(oTree$all_apps_wide$participant._current_app_name) +final_apps <- final_apps[final_apps != "survey"] +final_apps <- final_apps[final_apps != "dictator"] +show_dropouts(oTree, final_apps = final_apps) +} +\keyword{oTree} diff --git a/tests/testthat.R b/tests/testthat.R new file mode 100644 index 0000000..4d333d7 --- /dev/null +++ b/tests/testthat.R @@ -0,0 +1,12 @@ +# This file is part of the standard setup for testthat. +# It is recommended that you do not modify it. +# +# Where should you do additional test configuration? +# Learn more about the roles of various files in: +# * https://r-pkgs.org/tests.html +# * https://testthat.r-lib.org/reference/test_package.html#special-files + +library(testthat) +library(gmoTree) + +test_check("gmoTree") diff --git a/tests/testthat/tests.R b/tests/testthat/tests.R new file mode 100644 index 0000000..c7d583b --- /dev/null +++ b/tests/testthat/tests.R @@ -0,0 +1,7803 @@ +if (rlang::is_installed(c("withr", "testthat"))) { + +library(testthat) # load testthat package +library(gmoTree) # load our package + +# Set data folder first +withr::with_dir(system.file( + file.path("extdata"), # Make sure the file path is read on windows and ubuntu + package = "gmoTree"), { + +# Imports that will be used later #### +# Must be outside of testthat, so that they can be referred to later + + otree_2_2_4 <- import_otree( + del_empty = TRUE, + path = file.path(".", "exp_data_2.2.4"), + onlybots = FALSE, + csv = TRUE, + info = TRUE) + + otree_5_4_0 <- import_otree( + del_empty = TRUE, + path = "./exp_data_5.4.0", + onlybots = FALSE, + csv = TRUE, + info = TRUE) + # Alternative: # file.path(".", "exp_data_5.4.0"), + + otree_5_4_0_non_unique <- otree_5_4_0 + otree_5_4_0 <- delete_duplicate(otree_5_4_0) + + otree_old_one <- import_otree( + del_empty = TRUE, + path = ".\\old_one", + onlybots = FALSE, + csv = TRUE, + info = TRUE) + # Alternative: # file.path(".", "old_one"), + + otree_all <- import_otree( + del_empty = TRUE, + onlybots = FALSE, + csv = TRUE, + info = TRUE) + + otree_new_empty <- import_otree( + del_empty = FALSE, + path = ".\\exp_data", + onlybots = FALSE, + csv = TRUE, + info = TRUE) + # Alternative: # file.path(".", "exp_data"), + +# Import data tests #### + +testthat::test_that("Import - all", { + + testthat::expect_warning( + otree1 <- import_otree( + del_empty = TRUE, + onlybots = FALSE, + csv = TRUE, + info = TRUE + ), "globally but also room-specific") + + testthat::expect_warning( + otree2 <- import_otree( + del_empty = FALSE, + onlybots = FALSE, + csv = TRUE, + info = TRUE + ), "globally but also room-specific") + + # Test + testthat::expect_output(str(otree2), + "List of 10") + # "start", "dictator", "chatapp", "survey", + # "all_apps_wide", "Time", "Chats" + + diff <- nrow(otree2$all_apps_wide[ + otree2$all_apps_wide$participant._current_app_name == "", ]) + test1 <- (otree2$info$initial_n - otree1$info$initial_n) == diff + + testthat::expect_true(test1) +}) + +testthat::test_that("Import - bot files", { + # Run function + otree_bot <- import_otree( + del_empty = TRUE, + path = file.path(".", "bot_data"), + onlybots = TRUE, + csv = TRUE, + info = FALSE) + + # Test + testthat::expect_equal( + unique(otree_bot$all_apps_wide$participant._is_bot), 1) +}) + +testthat::test_that("Import - all info FALSE", { + # Run function + testthat::expect_warning( + otree2 <- import_otree( + del_empty = TRUE, + onlybots = FALSE, + csv = TRUE, + info = FALSE), + "globally but also room-specific") + + # Test + testthat::expect_output(str(otree2), "List of 10") + # [1] "all_apps_wide" "info" "chatapp" "dictator" + # [5] "start" "survey" "Time" "Chats" +}) + +testthat::test_that("Import - dropouts", { + # Run function + testthat::expect_warning( + otree2 <- import_otree( + del_empty = TRUE, + onlybots = FALSE, + csv = TRUE, + info = TRUE), "globally but also room-specific") + + # Test + testthat::expect_output(str(otree2), "List of 10") +}) + +testthat::test_that("Import - Excel", { + + file_names <- list.files( + path = file.path("exp_data_2.1.0"), + pattern = "[0-9]{4}-[0-9]{2}-[0-9]{2}.xlsx") + + # Run function + otree2 <- import_otree( + del_empty = TRUE, + path = file.path("exp_data_2.1.0"), + onlybots = FALSE, + csv = FALSE, + info = TRUE) + + # Test + testthat::expect_output(str(otree2), "List of 8") + testthat::expect_vector(otree2$info$imported_files) + # (Plus two because of Chat and Time!) + test1 <- length(otree2$info$imported_files) == 7 + # Don't do that because there are also faulty files: length(file_names) + 2 + testthat::expect_true(test1) +}) + +testthat::test_that("Import - subapp name test1", { + # Run function + testthat::expect_warning( + otree2 <- import_otree( + del_empty = TRUE, + path = ".\\exp_data_5.4.0subapp", + onlybots = FALSE, + csv = TRUE, + info = TRUE), + "globally but also room-specific") + + # Test + test1 <- "2chatapp" %in% names(otree2) + test2 <- "chatapp" %in% names(otree2) + test3 <- "dictator" %in% names(otree2) + test4 <- "dictator2" %in% names(otree2) + testthat::expect_true(all(c(test1, test2, test3, test4))) +}) + +testthat::test_that("Import - delete dropouts", { + # Run functions + testthat::expect_warning( + otree1 <- import_otree( + del_empty = TRUE, + path = ".\\exp_data_5.4.0", + onlybots = FALSE, + csv = TRUE, + info = FALSE), + "globally but also room-specific") + + otree2 <- delete_dropouts(otree1, final_apps = "survey", info = TRUE) + + testthat::expect_message( + otree3 <- import_otree( + del_empty = TRUE, + path = ".\\exp_data_5.4.0", + onlybots = FALSE, + csv = TRUE, + final_apps = "survey", + info = TRUE), + "Dropouts are deleted from all data frames.") + + testthat::expect_message( + otree3 <- import_otree( + del_empty = TRUE, + path = ".\\exp_data_5.4.0", + onlybots = FALSE, + csv = TRUE, + final_apps = "survey", + info = FALSE), NA) + + # Test if dropouts were deleted + test1 <- nrow(otree1$all_apps_wide) > nrow(otree2$all_apps_wide) + test2 <- nrow(otree1$dictator) > nrow(otree2$dictator) + test3 <- nrow(otree1$survey) > nrow(otree2$survey) + test4 <- nrow(otree1$Chats) == nrow(otree2$Chats) # Must be equal! + test5 <- nrow(otree1$Time) > nrow(otree2$Time) + testthat::expect_true(all(c(test1, test2, test3, test4, test5))) + + # Test if after-dropout numbers are the same + test1 <- nrow(otree3$all_apps_wide) == nrow(otree2$all_apps_wide) + test2 <- nrow(otree3$dictator) == nrow(otree2$dictator) + test3 <- nrow(otree3$survey) == nrow(otree2$survey) + test4 <- nrow(otree3$Chats) == nrow(otree2$Chats) + test5 <- nrow(otree3$Time) == nrow(otree2$Time) + testthat::expect_true(all(c(test1, test2, test3, test4, test5))) +}) + +testthat::test_that("Import - subapp name test2 ", { + # Run function + otree2 <- import_otree( + del_empty = TRUE, + path = ".\\exp_data_5.4.0subapp", + file_names = c("2chatapp_2023-05-16.csv", + "chatapp_2023-05-16.csv", + "dictator2_2023-05-16.csv", + "dictator_2023-05-16.csv"), + onlybots = FALSE, + csv = TRUE, + info = TRUE) + + # Test + test1 <- "2chatapp" %in% names(otree2) + test2 <- "chatapp" %in% names(otree2) + test3 <- "dictator" %in% names(otree2) + test4 <- "dictator2" %in% names(otree2) + testthat::expect_true(all(c( + test1, test2, test3, test4))) +}) + +testthat::test_that("Import - empty rows check", { + # Run function + testthat::expect_warning( + otree2 <- import_otree( + del_empty = FALSE, + onlybots = FALSE, + csv = TRUE, + info = TRUE), "globally but also room-specific") + + testthat::expect_warning( + otree3 <- import_otree( + del_empty = TRUE, + onlybots = FALSE, + csv = TRUE, + info = TRUE), "globally but also room-specific") + + # Test + testthat::expect_gt(nrow(otree2$all_apps_wide), + nrow(otree3$all_apps_wide)) + testthat::expect_gt(nrow(otree2$dictator), + nrow(otree3$dictator)) + testthat::expect_gt(nrow(otree2$survey), + nrow(otree3$survey)) + testthat::expect_equal(nrow(otree2$Time), + nrow(otree3$Time)) + testthat::expect_equal(nrow(otree2$Chats), + nrow(otree3$Chats)) +}) + +testthat::test_that("Import - with 2 paths", { + # Run function + otree1 <- import_otree( + del_empty = TRUE, + path = c(file.path(".", "exp_data_2.2.4")), + onlybots = FALSE, + csv = TRUE, + info = TRUE) # No warning here + + testthat::expect_warning( + otree2 <- import_otree( + del_empty = TRUE, + path = file.path(".", "exp_data_5.4.0"), + onlybots = FALSE, + csv = TRUE, + info = TRUE), " stored all_apps_wide globally but also room-specific") + + testthat::expect_warning( + otree3 <- import_otree( + del_empty = TRUE, + path = c(file.path(".", "exp_data_2.2.4"), + file.path(".", "exp_data_5.4.0")), + onlybots = FALSE, + csv = TRUE, + info = TRUE + ), " stored all_apps_wide globally but also room-specific") + + # Test + test1 <- nrow(otree1$all_apps_wide) + + nrow(otree2$all_apps_wide) == + nrow(otree3$all_apps_wide) + testthat::expect_true(test1) +}) + +testthat::test_that("Import - with file_names(path included)", { + # Run function + otree2 <- import_otree( + del_empty = TRUE, + file_names = c("exp_data_5.4.0\\all_apps_wide-2023-05-16.csv", + "exp_data_5.4.0\\ChatMessages-2023-05-16.csv", + "exp_data_5.4.0\\PageTimes-2023-05-16.csv"), + onlybots = FALSE, + csv = TRUE, + info = TRUE) + + # Test + testthat::expect_output(str(otree2), "List of 4") + test1 <- ("initial_n" %in% names(otree2$info)) + testthat::expect_true(test1) + test2 <- length(otree2$info$imported_files) == 3 + testthat::expect_true(test2) +}) + +testthat::test_that("Import - with file_names- one warning", { + # Test if there is no warning if "all apps wide" is saved with - + # and not with _ before the date. (as it should be) + + # Run function + expect_warning( + otree2 <- import_otree( + del_empty = TRUE, + path = system.file( + file.path("extdata"), + package = "gmoTree"), + file_names = c("exp_data\\all_apps_wide-2023-03-27.csv", + "exp_data\\ChatMessages-2023-03-27.csv", + "exp_data\\PageTimes-2023-03-27.csv"), + onlybots = FALSE, + csv = TRUE, + info = TRUE), NA) + + # Test + testthat::expect_output(str(otree2), "List of 4") + test1 <- ("initial_n" %in% names(otree2$info)) + testthat::expect_true(test1) + test2 <- length(otree2$info$imported_files) == 3 + testthat::expect_true(test2) +}) + +testthat::test_that("Import - only Chats", { + # Run function + otree2 <- import_otree( + del_empty = TRUE, + path = system.file( + file.path("extdata"), + package = "gmoTree"), + file_names = "exp_data_5.4.0/ChatMessages-2023-05-16.csv", + onlybots = FALSE, + csv = TRUE, + info = TRUE) + + # Test + test <- "Chats" %in% names(otree2) + testthat::expect_true(test) +}) + +testthat::test_that("Import - only time", { + # Run function + otree2 <- import_otree( + del_empty = TRUE, + path = system.file( + file.path("extdata"), + package = "gmoTree"), + file_names = "exp_data_5.4.0/PageTimes-2023-05-16.csv", + onlybots = FALSE, + csv = TRUE, + info = TRUE) + + # Test + test <- "Time" %in% names(otree2) + testthat::expect_true(test) +}) + +testthat::test_that("Import - only Chats not faulty", { + # Run function + testthat::expect_message( + otree2 <- import_otree( + del_empty = TRUE, + path = system.file( + file.path("extdata"), + package = "gmoTree"), + file_names = c("exp_data_5.4.0/all_apps_wide-2900-05-16.csv", + "exp_data_5.4.0/ChatMessages-2023-05-16.csv", + "exp_data_5.4.0/PageTimes-2900-05-16.csv"), + onlybots = FALSE, + csv = TRUE, + info = TRUE), + "Imported: 0 app.*No Time fil.*Imported: Chat file.*Errors when importing") + + # Test + test0 <- !is.null(otree2$info) + test1 <- !("initial_n" %in% names(otree2$info)) # Not available without AAW + test2 <- length(otree2$info$imported_files) == 1 + test3 <- ("Chats" %in% names(otree2)) + testthat::expect_true(all(c(test0, test1, test2, test3))) +}) + +testthat::test_that("Import - only TIME not faulty", { + # Run function + testthat::expect_message( + otree2 <- import_otree( + del_empty = TRUE, + path = system.file( + file.path("extdata"), + package = "gmoTree"), + file_names = c("exp_data_5.4.0/all_apps_wide-2900-05-16.csv", + "exp_data_5.4.0/ChatMessages-2090-05-16.csv", + "exp_data_5.4.0/PageTimes-2023-05-16.csv", + "exp_data_5.4.0/PageTimes-2900-05-16.csv"), + onlybots = FALSE, + csv = TRUE, + info = TRUE), + "Imported: 0 app.*Imported: Time fil.*No chat files available.*Errors when") + + # Test + test1 <- !("initial_n" %in% names(otree2$info)) # Not available without AAW + test2 <- length(otree2$info$imported_files) == 1 + test3 <- ("Time" %in% names(otree2)) + testthat::expect_true(all(c(test1, test2, test3))) +}) + +testthat::test_that("Import - with some faulty file_names", { + # Run function + otree2 <- import_otree( + del_empty = TRUE, + path = system.file( + file.path("extdata"), + package = "gmoTree"), + file_names = c( + "exp_data_5.4.0/all_apps_wide-2023-05-16.csv", + "exp_data_5.4.0/all_apps_wide-2023-05-96.csv", # - + "exp_data_5.4.0/dictator_2023-05-16.csv", + "exp_data_5.4.0/ChatMessages-2900-05-16.csv", # - + "exp_data_5.4.0/ChatMessages-2900-05-26.csv", # - + "exp_data_5.4.0/PageTimes-2900-05-16.csv", # - + "exp_data_5.4.0/PageTimes-2901-05-16.csv", # - + "exp_data_5.4.0/PageTimes-2023-05-16.csv", + "exp_data_5.4.0/ChatMessages-2023-05-16.csv" + ), + onlybots = FALSE, + csv = TRUE, + info = TRUE) + + # Test + test1 <- ("initial_n" %in% names(otree2$info)) + test2 <- length(otree2$info$imported_files) == 4 + test3 <- "dictator" %in% names(otree2) + test4 <- "Chats" %in% names(otree2) + test5 <- "Time" %in% names(otree2) + test6 <- "all_apps_wide" %in% names(otree2) + testthat::expect_true(all(c(test1, test2, test3, test4, + test5, test6))) +}) + +testthat::test_that("Import - with file_names(path included)", { + # Run function + otree2 <- import_otree( + del_empty = TRUE, + file_names = c("exp_data_5.4.0/all_apps_wide-2023-05-16.csv", + "exp_data_5.4.0/ChatMessages-2023-05-16.csv", + "exp_data_5.4.0/PageTimes-2023-05-16.csv"), + onlybots = FALSE, + csv = TRUE, + info = TRUE) + + # Test + testthat::expect_output(str(otree2), "List of 4") + test1 <- ("initial_n" %in% names(otree2$info)) + test2 <- length(otree2$info$imported_files) == 3 + testthat::expect_true(test1) + testthat::expect_true(test2) +}) + +testthat::test_that("Import - specific csv without all apps wide", { + file_names <- c( + "dictator_2023-03-27.csv", + "ChatMessages-2023-03-27.csv", + "PageTimes-2023-03-27.csv") + + # Run function + otree2 <- import_otree( + del_empty = TRUE, + path = file.path(".", "exp_data"), + file_names = file_names, + onlybots = FALSE, + csv = TRUE, + recursive = TRUE, + info = TRUE) + + # Test + testthat::expect_output(str(otree2), "List of 4") + # Test if there is no initial_n (should be omitted if there is no aaw!) + test1 <- !("initial_n" %in% names(otree2$info)) + testthat::expect_true(test1) + test2 <- length(otree2$info$imported_files) == length(file_names) + testthat::expect_true(test2) +}) + +testthat::test_that("Import - without all apps wide xlsx", { + file_names <- c( + "dictator_2023-05-16.xlsx", + "Chat messages (accessed 2023-05-16).csv", + "TimeSpent (accessed 2023-05-16).csv") + + # Run function + otree2 <- import_otree( + del_empty = TRUE, + path = file.path(".", "exp_data_2.1.0"), + file_names = file_names, + onlybots = FALSE, + csv = FALSE, + recursive = TRUE, + info = TRUE) + + # Test + testthat::expect_output(str(otree2), "List of 4") + # Test if there is no initial_n (should be omitted if there is no aaw!) + test1 <- !("initial_n" %in% names(otree2$info)) + test2 <- length(otree2$info$imported_files) == length(file_names) + test3 <- "dictator" %in% names(otree2) + test4 <- "Chats" %in% names(otree2) + test5 <- "Time" %in% names(otree2) + testthat::expect_true(all(c(test1, test2, test3, test4, test5))) +}) + +testthat::test_that("Import - with file names", { + file_names <- c("all_apps_wide-2023-03-27.csv", + "ChatMessages-2023-03-27.csv", + "PageTimes-2023-03-27.csv") + + # Run function + otree2 <- import_otree( + del_empty = TRUE, + path = "./exp_data", + file_names = file_names, + onlybots = FALSE, + csv = TRUE, + info = TRUE) + + # Test + testthat::expect_output(str(otree2), "List of 4") + test1 <- "initial_n" %in% names(otree2$info) + test2 <- length(otree2$info$imported_files) == length(file_names) + test3 <- "all_apps_wide" %in% names(otree2) + test4 <- "Chats" %in% names(otree2) + test5 <- "Time" %in% names(otree2) + testthat::expect_true(all(c(test1, test3, test4, test5))) +}) + +testthat::test_that("Import (e) - no files", { + # Run function and test + testthat::expect_error(import_otree( + del_empty = TRUE, + path = ".\\empty", + ), "No files to import") +}) + +testthat::test_that("Import (e) - file_names(empty path)", { + # Run function + testthat::expect_error( + otree2 <- import_otree( + del_empty = TRUE, + path = NULL, + file_names = c("exp_data_5.4.0\\all_apps_wide-2023-05-16.csv", + "exp_data_5.4.0\\ChatMessages-2023-05-16.csv", + "exp_data_5.4.0\\PageTimes-2023-05-16.csv"), + onlybots = FALSE, + csv = TRUE, + info = TRUE), "Path must not be NULL!") +}) + +testthat::test_that("Import (e) - csv - all faulty file_names", { + # Run function and test + # This error message is only shown because all of them are faulty + + testthat::expect_error( + otree2 <- import_otree( + del_empty = TRUE, + path = system.file( + file.path("extdata"), + package = "gmoTree"), + file_names = c("exp_data_5.4.0/all_apps_wide-2900-05-16.csv", + "exp_data_5.4.0/ChatMessages-2900-05-16.csv", + "exp_data_5.4.0/PageTimes-2900-05-16.csv"), + onlybots = FALSE, + csv = TRUE, + info = TRUE), "Errors when importing these files") +}) + +testthat::test_that("Import (e) - xlsx - all faulty file_names", { + # Run function and test + # This error message is only shown because all of them are faulty + + testthat::expect_error( + otree2 <- import_otree( + del_empty = TRUE, + path = system.file( + file.path("extdata"), + package = "gmoTree"), + file_names = c("exp_data_5.4.0/all_apps_wide-2900-05-16.xlsx", + "exp_data_5.4.0/dictator-2900-05-16.xlsx", + "exp_data_5.4.0/ChatMessages-2900-05-16.csv", + "exp_data_5.4.0/PageTimes-2900-05-16.csv"), + onlybots = FALSE, + csv = FALSE, + info = TRUE), "Errors when importing these files") +}) + +testthat::test_that("Import (e) - xlsx - some faulty file_names", { + # Run function + testthat::expect_message( + otree2 <- import_otree( + del_empty = TRUE, + path = system.file( + file.path("extdata"), + package = "gmoTree"), + file_names = c("exp_data_2.1.0/all_apps_wide-2900-05-16.xlsx", + "exp_data_2.1.0/all_apps_wide_2023-05-16.xlsx", + "exp_data_2.1.0/dictator_2023-05-16.xlsx", + "exp_data_2.1.0/dictator-2900-05-16.xlsx", + "exp_data_2.1.0/start-2900-05-16.xlsx", + "exp_data_2.1.0/ChatMessages-2900-05-16.csv", + "exp_data_2.1.0/Chat messages (accessed 2023-05-16).csv", + "exp_data_2.1.0/TimeSpent (accessed 2023-05-16).csv", + "exp_data_2.1.0/PageTimes-2900-05-16.csv"), + onlybots = FALSE, + csv = FALSE, + info = TRUE), "Errors when importing these files") + + # Test + test1 <- !("start" %in% names(otree2)) + test2 <- "dictator" %in% names(otree2) + test3 <- "Time" %in% names(otree2) + test4 <- "Chats" %in% names(otree2) + testthat::expect_true(all(c(test1, test2, test3, test4))) +}) + +testthat::test_that("Import (w) - erroneous files", { + # Dictator file is faulty + + # Run function + testthat::expect_warning( + testthat::expect_message( + otree2 <- import_otree( + info = TRUE, + path = file.path(".", "exp_wrong_data")), + "Errors when importing these files"), + "stored all_apps_wide globally but also room-specific") + + # Test + test2 <- "survey" %in% names(otree2) + test3 <- !("dictator" %in% names(otree2)) + test4 <- "Chats" %in% names(otree2) + test5 <- "Time" %in% names(otree2) + test6 <- "all_apps_wide" %in% names(otree2) + test7 <- !(any(grepl("dictator", otree2$info$imported_files))) + testthat::expect_true(all(c(test2, test3, test4, test5, test6, test7))) +}) + +testthat::test_that("Import (e) - path", { + # Run function and test + testthat::expect_error(import_otree( + del_empty = TRUE, + path = "xyz", + onlybots = FALSE, + csv = TRUE, + info = TRUE), "This path does not exist") +}) + +print("---- delete_duplicate -----") +# Delete duplicate #### +testthat::test_that("Delete duplicate", { + # Prepare data + testthat::expect_warning( + otree2 <- import_otree( + del_empty = TRUE, + path = "./exp_data_5.4.0", + onlybots = FALSE, + csv = TRUE, + info = FALSE)) + # Alternative: # file.path(".", "exp_data_5.4.0"), + + before_aaw <- nrow(otree2$all_apps_wide) + before_dictator <- nrow(otree2$dictator) + before_n <- otree2$info$initial_n + + # Run function + otree2 <- delete_duplicate(otree2) + + # Test + after_aaw <- nrow(otree2$all_apps_wide) + after_dictator <- nrow(otree2$dictator) + after_n <- otree2$info$initial_n + testthat::expect_gt(before_aaw, after_aaw) + testthat::expect_gt(before_dictator, after_dictator) + testthat::expect_gt(before_n, after_n) +}) + +testthat::test_that("Delete duplicate - time and chat", { + # Prepare data + otree2 <- otree_all + + otree2$all_apps_wide <- rbind(otree2$all_apps_wide, + otree2$all_apps_wide) + otree2$dictator <- rbind(otree2$dictator, + otree2$dictator) + otree2$survey <- rbind(otree2$survey, + otree2$survey) + otree2$Time <- rbind(otree2$Time, + otree2$Time) + otree2$Chats <- rbind(otree2$Chats, + otree2$Chats) + + # Before + before_aaw <- nrow(otree2$all_apps_wide) + before_dictator <- nrow(otree2$dictator) + before_survey <- nrow(otree2$survey) + before_time <- nrow(otree2$Time) + before_chat <- nrow(otree2$Chat) + before_n <- otree2$info$initial_n + + # Run function + otree2 <- delete_duplicate(otree2) + + # Test + after_aaw <- nrow(otree2$all_apps_wide) + after_dictator <- nrow(otree2$dictator) + after_n <- otree2$info$initial_n + testthat::expect_gt(before_aaw, after_aaw) + testthat::expect_gt(before_dictator, after_dictator) + testthat::expect_gt(before_n, after_n) +}) + +print("---- messy_time -----") +# Messy time #### +testthat::test_that("Messy time", { + # Prepare data + otree2 <- otree_all + + # Run function and test (combine only time stamps) + testthat::expect_warning( + otree2 <- messy_time(otree2, + combine = TRUE, + epoch_time = TRUE, + info = TRUE), + "referred to the time stamp.*referred to the participant code") + + test1 <- !("epoch_time" %in% names(otree2$Time)) + test2 <- !("time_stamp" %in% names(otree2$Time)) + test3 <- !("participant__code" %in% names(otree2$Time)) + testthat::expect_true(all(c(test1, test2, test3))) +}) + +# The other messy tests are below inside the other functions tests +testthat::test_that("Messy time", { + # Prepare data + otree2 <- otree_all + + # Run function and test + testthat::expect_error( + messy_time(otree2), + "referred to the time stamp.*referred to the participant code") +}) + +testthat::test_that("Messy time", { + # Prepare data + otree2 <- otree_all + + # Run function and test + testthat::expect_error(messy_time(otree2), + "referred to the time stamp") +}) + +testthat::test_that("Messy time - combine false, epoch time false", { + # Prepare data + otree2 <- otree_all + + # Run function and test (combine only time stamps + testthat::expect_error(messy_time(otree2, + combine = FALSE, + epoch_time = FALSE), + "referred to the participant code") +}) + +print("---- messy_chat -----") +# Messy chat #### +testthat::test_that("Messy chat", { + # Prepare data + otree2 <- otree_all + + # Run function and test + testthat::expect_error(messy_chat(otree2), + " referred to the session code") +}) + +testthat::test_that("Messy chat - combine", { + # Prepare data + otree2 <- otree_all + + # Run function and test + testthat::expect_warning( + otree2 <- messy_chat(otree2, + combine = TRUE, + info = TRUE), + "referred to") +}) + +testthat::test_that("Messy chat (e) - more participant code variables", { + # Prepare data + otree2 <- otree_all + + # Run function and test + testthat::expect_error(messy_chat(otree2, + session = FALSE), + "referred to the participant code") +}) + +print("---- delete_cases -----") +# Delete cases #### +testthat::test_that("Delete cases - new oTree", { + # Prepare data + otree2 <- otree_5_4_0 + person <- otree2$all_apps_wide$participant.code[1] + + # Before + before_aaw <- nrow(otree2$all_apps_wide) + before_dictator <- nrow(otree2$dictator) + before_survey <- nrow(otree2$survey) + before_time <- nrow(otree2$Time) + before_chat <- nrow(otree2$Chat) + + # Run function and test + testthat::expect_message( + delete_cases(otree2, + person, + reason = "Upon request", + info = TRUE), + "Cases are deleted") + otree2 <- delete_cases(otree2, person, reason = "Upon request") + + # After + after_aaw <- nrow(otree2$all_apps_wide) + after_dictator <- nrow(otree2$dictator) + after_survey <- nrow(otree2$survey) + after_time <- nrow(otree2$Time) + after_chat <- nrow(otree2$Chat) + + # Diff + diff_aaw <- before_aaw - after_aaw + diff_dictator <- before_dictator - after_dictator + diff_survey <- before_survey - after_survey + diff_time <- before_time - after_time + diff_chat <- before_chat - after_chat + + # Test difference + testthat::expect_gt(diff_aaw, 0) + testthat::expect_gt(diff_dictator, 0) + testthat::expect_gt(diff_survey, 0) + testthat::expect_gt(diff_time, 0) + testthat::expect_equal(diff_chat, 0) + + # Test if not all cases were deleted! + testthat::expect_gt(after_aaw, 0) + testthat::expect_gt(after_dictator, 0) + testthat::expect_gt(after_survey, 0) + testthat::expect_gt(after_time, 0) + testthat::expect_gt(after_chat, 0) + + # Test if deleted people are really deleted + test0 <- length(otree2$info[["deleted_cases"]][["codes"]]) == 1 + test1 <- person %in% otree2$info[["deleted_cases"]][["codes"]] + test2 <- !any(otree2$info[["deleted_cases"]][["codes"]] %in% + unique(otree2$Time$participant_code)) + test3 <- !any(otree2$info[["deleted_cases"]][["codes"]] %in% + unique(otree2$all_apps_wide$participant.code)) + testthat::expect_true(test0) + testthat::expect_true(test1) + testthat::expect_true(test2) + testthat::expect_true(test3) + + # Test if participant is really deleted - version 2 + test1 <- !(person %in% otree2$all_apps_wide$participant.code) + test2 <- !(person %in% otree2$dictator$participant.code) + test3 <- !(person %in% otree2$start$participant.code) + test4 <- !(person %in% otree2$survey$participant.code) + test5 <- !(person %in% otree2$Time$participant__code) + test6 <- !(person %in% otree2$Chats$participant__code) + testthat::expect_true(all(c(test1, test2, test3, test4, test5, test6))) + + # Test for consistency + test1 <- setequal(otree2$info$deleted_cases$unique$participant.code, + otree2$info$deleted_cases$full$participant.code) + + test2 <- setequal(otree2$info$deleted_cases$unique$participant.code, + otree2$info$deleted_cases$codes) + test3 <- length(otree2$info$deleted_cases$codes) == + otree2$info$deleted_cases$count + test4 <- length(otree2$info$deleted_cases$codes) == + nrow(otree2$info$deleted_cases$unique) + testthat::expect_true(all(c(test1, test2, test3, test4))) +}) + +testthat::test_that("Delete cases - new oTree, one random data frame", { + # Prepare data + otree2 <- otree_5_4_0 + person <- otree2$all_apps_wide$participant.code[1] + otree2$random_dataframe <- data.frame( + a = c(1, 2, 3), + b = c(4, 5, 6), + c = c(7, 8, 9)) + + # Before + before_aaw <- nrow(otree2$all_apps_wide) + before_dictator <- nrow(otree2$dictator) + before_survey <- nrow(otree2$survey) + before_time <- nrow(otree2$Time) + before_chat <- nrow(otree2$Chat) + before_random <- nrow(otree2$random_dataframe) + + # Run function and test + testthat::expect_message( + delete_cases(otree2, + person, + reason = "Upon request", + info = TRUE), + "Cases are deleted") + otree2 <- delete_cases(otree2, person, reason = "Upon request") + + # After + after_aaw <- nrow(otree2$all_apps_wide) + after_dictator <- nrow(otree2$dictator) + after_survey <- nrow(otree2$survey) + after_time <- nrow(otree2$Time) + after_chat <- nrow(otree2$Chat) + after_random <- nrow(otree2$random_dataframe) + + # Diff + diff_aaw <- before_aaw - after_aaw + diff_dictator <- before_dictator - after_dictator + diff_survey <- before_survey - after_survey + diff_time <- before_time - after_time + diff_chat <- before_chat - after_chat + diff_random <- before_random - after_random + + # Test difference + testthat::expect_gt(diff_aaw, 0) + testthat::expect_gt(diff_dictator, 0) + testthat::expect_gt(diff_survey, 0) + testthat::expect_gt(diff_time, 0) + testthat::expect_equal(diff_chat, 0) + testthat::expect_equal(diff_random, 0) + + # Test if not all cases were deleted! + testthat::expect_gt(after_aaw, 0) + testthat::expect_gt(after_dictator, 0) + testthat::expect_gt(after_survey, 0) + testthat::expect_gt(after_time, 0) + testthat::expect_gt(after_chat, 0) + testthat::expect_gt(after_random, 0) + + # Test if deleted people are really deleted + test0 <- length(otree2$info[["deleted_cases"]][["codes"]]) == 1 + test1 <- person %in% otree2$info[["deleted_cases"]][["codes"]] + test2 <- !any(otree2$info[["deleted_cases"]][["codes"]] %in% + unique(otree2$Time$participant_code)) + test3 <- !any(otree2$info[["deleted_cases"]][["codes"]] %in% + unique(otree2$all_apps_wide$participant.code)) + testthat::expect_true(test0) + testthat::expect_true(test1) + testthat::expect_true(test2) + testthat::expect_true(test3) + + # Test if participant is really deleted - version 2 + test1 <- !(person %in% otree2$all_apps_wide$participant.code) + test2 <- !(person %in% otree2$dictator$participant.code) + test3 <- !(person %in% otree2$start$participant.code) + test4 <- !(person %in% otree2$survey$participant.code) + test5 <- !(person %in% otree2$Time$participant__code) + test6 <- !(person %in% otree2$Chats$participant__code) + testthat::expect_true(all(c(test1, test2, test3, test4, test5, test6))) + + # Test for consistency + test1 <- setequal(otree2$info$deleted_cases$unique$participant.code, + otree2$info$deleted_cases$full$participant.code) + + test2 <- setequal(otree2$info$deleted_cases$unique$participant.code, + otree2$info$deleted_cases$codes) + test3 <- length(otree2$info$deleted_cases$codes) == + otree2$info$deleted_cases$count + test4 <- length(otree2$info$deleted_cases$codes) == + nrow(otree2$info$deleted_cases$unique) + testthat::expect_true(all(c(test1, test2, test3, test4))) +}) + +testthat::test_that("Delete cases - old and new otree", { + # Prepare data (delete person from old and new data frame) + otree2 <- otree_all + person1 <- otree2$Time$participant_code[ + !is.na(otree2$Time$participant_code)][1] + person2 <- otree2$Time$participant__code[ + !is.na(otree2$Time$participant__code)][1] + person <- c(person1, person2) + + # Before + before_aaw <- nrow(otree2$all_apps_wide) + before_dictator <- nrow(otree2$dictator) + before_survey <- nrow(otree2$survey) + before_time <- nrow(otree2$Time) + before_chat <- nrow(otree2$Chat) + + # Run function and test + otree2 <- messy_time(otree2, combine = TRUE) + otree2 <- messy_chat(otree2, combine = TRUE) + testthat::expect_message( + otree2 <- delete_cases(otree2, + person, + reason = "Upon request", + info = TRUE), + "2 case") + + # After + after_aaw <- nrow(otree2$all_apps_wide) + after_dictator <- nrow(otree2$dictator) + after_survey <- nrow(otree2$survey) + after_time <- nrow(otree2$Time) + after_chat <- nrow(otree2$Chat) + + # Diff + diff_aaw <- before_aaw - after_aaw + diff_dictator <- before_dictator - after_dictator + diff_survey <- before_survey - after_survey + diff_time <- before_time - after_time + diff_chat <- before_chat - after_chat + + # Test difference + testthat::expect_gt(diff_aaw, 0) + testthat::expect_gt(diff_dictator, 0) + testthat::expect_gt(diff_survey, 0) + testthat::expect_gt(diff_time, 0) + testthat::expect_equal(diff_chat, 0) + + # Test if not all cases were deleted! + testthat::expect_gt(after_aaw, 0) + testthat::expect_gt(after_dictator, 0) + testthat::expect_gt(after_survey, 0) + testthat::expect_gt(after_time, 0) + testthat::expect_gt(after_chat, 0) + + # Test if deleted people are really deleted (sample) + test1 <- all(person %in% otree2$info[["deleted_cases"]][["codes"]]) + test2 <- !any(otree2$info[["deleted_cases"]][["codes"]] %in% + unique(otree2$Time$participant_code[ + !is.na(otree2$Time$participant_code)])) + + test3 <- !any(otree2$info[["deleted_cases"]][["codes"]] %in% + unique(otree2$all_apps_wide$participant.code)) + testthat::expect_true(test1) + testthat::expect_true(test2) + testthat::expect_true(test3) + + test1 <- length(otree2$info[["deleted_cases"]][["codes"]]) == 2 + testthat::expect_true(test1) + + # Test if participant is really deleted - version 2 + test1 <- !(person %in% otree2$all_apps_wide$participant.code) + test2 <- !(person %in% otree2$dictator$participant.code) + test3 <- !(person %in% otree2$start$participant.code) + test4 <- !(person %in% otree2$survey$participant.code) + test5 <- !(person %in% otree2$Time$participant__code) + test6 <- !(person %in% otree2$Chats$participant__code) + testthat::expect_true(all(c(test1, test2, test3, test4, test5, test6))) + + # Test for consistency + test1 <- setequal(otree2$info$deleted_cases$unique$participant.code, + otree2$info$deleted_cases$full$participant.code) + + test2 <- setequal(otree2$info$deleted_cases$unique$participant.code, + otree2$info$deleted_cases$codes) + test3 <- length(otree2$info$deleted_cases$codes) == + otree2$info$deleted_cases$count + test4 <- length(otree2$info$deleted_cases$codes) == + nrow(otree2$info$deleted_cases$unique) + testthat::expect_true(all(c(test1, test2, test3, test4))) +}) + +testthat::test_that("Delete cases - more people ", { + # Prepare data + otree2 <- otree_5_4_0 + person <- otree2$all_apps_wide$participant.code[c(1, 2, 3, 4)] + + # Before + before_aaw <- nrow(otree2$all_apps_wide) + before_dictator <- nrow(otree2$dictator) + before_survey <- nrow(otree2$survey) + before_time <- nrow(otree2$Time) + before_chat <- nrow(otree2$Chat) + + # Run function + otree2 <- delete_cases(otree2, + person, + reason = "Upon request") + + # After + after_aaw <- nrow(otree2$all_apps_wide) + after_dictator <- nrow(otree2$dictator) + after_survey <- nrow(otree2$survey) + after_time <- nrow(otree2$Time) + after_chat <- nrow(otree2$Chat) + + # Diff + diff_aaw <- before_aaw - after_aaw + diff_dictator <- before_dictator - after_dictator + diff_survey <- before_survey - after_survey + diff_time <- before_time - after_time + diff_chat <- before_chat - after_chat + + # Test: Nothing should be deleted + testthat::expect_gt(diff_aaw, 0) + testthat::expect_gt(diff_dictator, 0) + testthat::expect_gt(diff_survey, 0) + testthat::expect_gt(diff_time, 0) + testthat::expect_equal(diff_chat, 0) + + # Test if deleted people are really deleted (sample) + test1 <- all( + person %in% otree2$info[["deleted_cases"]][["codes"]]) + test2 <- !any(otree2$info[["deleted_cases"]][["codes"]] %in% + unique(otree2$Time$participant_code)) + + test3 <- !any(otree2$info[["deleted_cases"]][["codes"]] %in% + unique(otree2$all_apps_wide$participant.code)) + testthat::expect_true(test1) + testthat::expect_true(test2) + testthat::expect_true(test3) + + # Test if participant is really deleted - version 2 + test1 <- !(person %in% otree2$all_apps_wide$participant.code) + test2 <- !(person %in% otree2$dictator$participant.code) + test3 <- !(person %in% otree2$start$participant.code) + test4 <- !(person %in% otree2$survey$participant.code) + test5 <- !(person %in% otree2$Time$participant__code) + test6 <- !(person %in% otree2$Chats$participant__code) + testthat::expect_true(all(c(test1, test2, test3, test4, test5, test6))) + + # Test for consistency + test1 <- setequal(otree2$info$deleted_cases$unique$participant.code, + otree2$info$deleted_cases$full$participant.code) + + test2 <- setequal(otree2$info$deleted_cases$unique$participant.code, + otree2$info$deleted_cases$codes) + test3 <- length(otree2$info$deleted_cases$codes) == + otree2$info$deleted_cases$count + test4 <- length(otree2$info$deleted_cases$codes) == + nrow(otree2$info$deleted_cases$unique) + testthat::expect_true(all(c(test1, test2, test3, test4))) +}) + +testthat::test_that("Delete cases - more people - one not there", { + # Prepare data + otree2 <- otree_5_4_0 + person <- c(otree2$all_apps_wide$participant.code[c(1, 2, 3, 4)], + "notthere") + + # Before + before_aaw <- nrow(otree2$all_apps_wide) + before_dictator <- nrow(otree2$dictator) + before_survey <- nrow(otree2$survey) + before_time <- nrow(otree2$Time) + before_chat <- nrow(otree2$Chat) + + # Run function + otree2 <- delete_cases(otree2, + person, + reason = "Upon request") + + # After + after_aaw <- nrow(otree2$all_apps_wide) + after_dictator <- nrow(otree2$dictator) + after_survey <- nrow(otree2$survey) + after_time <- nrow(otree2$Time) + after_chat <- nrow(otree2$Chat) + + # Diff + diff_aaw <- before_aaw - after_aaw + diff_dictator <- before_dictator - after_dictator + diff_survey <- before_survey - after_survey + diff_time <- before_time - after_time + diff_chat <- before_chat - after_chat + + # Test difference + testthat::expect_gt(diff_aaw, 0) + testthat::expect_gt(diff_dictator, 0) + testthat::expect_gt(diff_survey, 0) + testthat::expect_gt(diff_time, 0) + testthat::expect_equal(diff_chat, 0) + + # Test if not all cases were deleted! + testthat::expect_gt(after_aaw, 0) + testthat::expect_gt(after_dictator, 0) + testthat::expect_gt(after_survey, 0) + testthat::expect_gt(after_time, 0) + testthat::expect_gt(after_chat, 0) + + # Test if deleted people are really deleted (sample) + test1 <- all( + person[person != "notthere"] %in% + otree2$info[["deleted_cases"]][["codes"]]) + + test2 <- !any(otree2$info[["deleted_cases"]][["codes"]] %in% + unique(otree2$Time$participant_code)) + + test3 <- !any(otree2$info[["deleted_cases"]][["codes"]] %in% + unique(otree2$all_apps_wide$participant.code)) + testthat::expect_true(test1) + testthat::expect_true(test2) + testthat::expect_true(test3) + + # Test if participant is really deleted - version 2 + test1 <- !(person %in% otree2$all_apps_wide$participant.code) + test2 <- !(person %in% otree2$dictator$participant.code) + test3 <- !(person %in% otree2$start$participant.code) + test4 <- !(person %in% otree2$survey$participant.code) + test5 <- !(person %in% otree2$Time$participant__code) + test6 <- !(person %in% otree2$Chats$participant__code) + testthat::expect_true(all(c(test1, test2, test3, test4, test5, test6))) + + # Test for consistency + test1 <- setequal(otree2$info$deleted_cases$unique$participant.code, + otree2$info$deleted_cases$full$participant.code) + + test2 <- setequal(otree2$info$deleted_cases$unique$participant.code, + otree2$info$deleted_cases$codes) + test3 <- length(otree2$info$deleted_cases$codes) == + otree2$info$deleted_cases$count + test4 <- length(otree2$info$deleted_cases$codes) == + nrow(otree2$info$deleted_cases$unique) + testthat::expect_true(all(c(test1, test2, test3, test4))) +}) + +testthat::test_that("Delete cases - person not in aaw", { + # Prepare data + otree1 <- otree_5_4_0 + person <- otree1$all_apps_wide$participant.code[1] + otree1$all_apps_wide <- tail(otree1$all_apps_wide, -1) + + # Before + before_aaw <- nrow(otree1$all_apps_wide) + before_dictator <- nrow(otree1$dictator) + before_survey <- nrow(otree1$survey) + before_time <- nrow(otree1$Time) + before_chat <- nrow(otree1$Chat) + + # Run function + otree2 <- delete_cases(otree1, person, + reason = "Upon request") + + # After + after_aaw <- nrow(otree2$all_apps_wide) + after_dictator <- nrow(otree2$dictator) + after_survey <- nrow(otree2$survey) + after_time <- nrow(otree2$Time) + after_chat <- nrow(otree2$Chat) + + # Diff + diff_aaw <- before_aaw - after_aaw + diff_dictator <- before_dictator - after_dictator + diff_survey <- before_survey - after_survey + diff_time <- before_time - after_time + diff_chat <- before_chat - after_chat + + # Test difference + testthat::expect_equal(diff_aaw, 0) + testthat::expect_gt(diff_dictator, 0) + testthat::expect_gt(diff_survey, 0) + testthat::expect_gt(diff_time, 0) + testthat::expect_equal(diff_chat, 0) + + # Test if not all cases were deleted! + testthat::expect_gt(after_aaw, 0) + testthat::expect_gt(after_dictator, 0) + testthat::expect_gt(after_survey, 0) + testthat::expect_gt(after_time, 0) + testthat::expect_gt(after_chat, 0) + + # Test if deleted people are really deleted + test1 <- + !(otree2$info$deleted_cases$codes %in% + otree2$all_apps_wide$participant.code) + test2 <- + !(otree2$info$deleted_cases$codes %in% + otree2$dictator$participant.code) + test3 <- + !(otree2$info$deleted_cases$codes %in% + otree2$survey$participant.code) + test4 <- + !(otree2$info$deleted_cases$codes %in% + otree2$Time$participant_code) + test5a <- otree1$Chats$participant_code %in% + otree2$info$deleted_cases$codes # Chat differently: Before + test5b <- otree2$Chats$participant_code %in% + otree2$info$deleted_cases$codes # Chat differently: After + + testthat::expect_true(all(c(test1, test2))) + testthat::expect_true(all(c(test3, test4))) + testthat::expect_equal(test5a, test5b) + + # Test if participant is really deleted - version 2 + test1 <- !(person %in% otree2$all_apps_wide$participant.code) + test2 <- !(person %in% otree2$dictator$participant.code) + test3 <- !(person %in% otree2$start$participant.code) + test4 <- !(person %in% otree2$survey$participant.code) + test5 <- !(person %in% otree2$Time$participant__code) + test6 <- !(person %in% otree2$Chats$participant__code) + testthat::expect_true(all(c(test1, test2, test3, test4, test5, test6))) + + # Test for consistency + test1 <- setequal(otree2$info$deleted_cases$unique$participant.code, + otree2$info$deleted_cases$full$participant.code) + + test2 <- setequal(otree2$info$deleted_cases$unique$participant.code, + otree2$info$deleted_cases$codes) + test3 <- length(otree2$info$deleted_cases$codes) == + otree2$info$deleted_cases$count + test4 <- length(otree2$info$deleted_cases$codes) == + nrow(otree2$info$deleted_cases$unique) + testthat::expect_true(all(c(test1, test2, test3, test4))) +}) + +testthat::test_that("Delete cases - without aaw", { + # Prepare data + otree2 <- otree_5_4_0 + person <- otree2$all_apps_wide$participant.code[1] + otree2$all_apps_wide <- NULL + + # Before + before_dictator <- nrow(otree2$dictator) + before_survey <- nrow(otree2$survey) + before_time <- nrow(otree2$Time) + before_chat <- nrow(otree2$Chat) + + # Run function + otree2 <- delete_cases(otree2, + pcodes = person, + reason = "Upon request") + + # After + after_dictator <- nrow(otree2$dictator) + after_survey <- nrow(otree2$survey) + after_time <- nrow(otree2$Time) + after_chat <- nrow(otree2$Chat) + + # Diff + diff_dictator <- before_dictator - after_dictator + diff_survey <- before_survey - after_survey + diff_time <- before_time - after_time + diff_chat <- before_chat - after_chat + + # Test difference + testthat::expect_gt(diff_dictator, 0) + testthat::expect_gt(diff_survey, 0) + testthat::expect_gt(diff_time, 0) + testthat::expect_equal(diff_chat, 0) + + # Test if not all cases were deleted! + testthat::expect_gt(after_dictator, 0) + testthat::expect_gt(after_survey, 0) + testthat::expect_gt(after_time, 0) + testthat::expect_gt(after_chat, 0) + + # Test if deleted people are really deleted (sample) + test1 <- person %in% otree2$info[["deleted_cases"]][["codes"]] + test2 <- !any(otree2$info[["deleted_cases"]][["codes"]] %in% + unique(otree2$Time$participant_code)) + + test3 <- !any(otree2$info[["deleted_cases"]][["codes"]] %in% + unique(otree2$dictator$participant.code)) + testthat::expect_true(test1) + testthat::expect_true(test2) + testthat::expect_true(test3) + + # Test if participant is really deleted - version 2 + test2 <- !(person %in% otree2$dictator$participant.code) + test3 <- !(person %in% otree2$start$participant.code) + test4 <- !(person %in% otree2$survey$participant.code) + test5 <- !(person %in% otree2$Time$participant__code) + test6 <- !(person %in% otree2$Chats$participant__code) + testthat::expect_true(all(c(test2, test3, test4, test5, test6))) + + # Test for consistency + test1 <- setequal(otree2$info$deleted_cases$unique$participant.code, + otree2$info$deleted_cases$full$participant.code) + + test2 <- setequal(otree2$info$deleted_cases$unique$participant.code, + otree2$info$deleted_cases$codes) + test3 <- length(otree2$info$deleted_cases$codes) == + otree2$info$deleted_cases$count + test4 <- length(otree2$info$deleted_cases$codes) == + nrow(otree2$info$deleted_cases$unique) + testthat::expect_true(all(c(test1, test2, test3, test4))) +}) + +testthat::test_that("Delete cases - plabels", { + # Prepare data + otree1 <- otree_5_4_0 + person <- c("Person4", "Person1") + person_codes <- otree1$all_apps_wide$participant.code[ + otree1$all_apps_wide$participant.label %in% person] + + # Before + before_aaw <- nrow(otree1$all_apps_wide) + before_dictator <- nrow(otree1$dictator) + before_survey <- nrow(otree1$survey) + before_time <- nrow(otree1$Time) + before_chat <- nrow(otree1$Chat) + + # Run function + otree2 <- delete_cases(otree1, + plabels = person, + reason = "Only tests") + + # After + after_aaw <- nrow(otree2$all_apps_wide) + after_dictator <- nrow(otree2$dictator) + after_survey <- nrow(otree2$survey) + after_time <- nrow(otree2$Time) + after_chat <- nrow(otree2$Chat) + + # Diff + diff_aaw <- before_aaw - after_aaw + diff_dictator <- before_dictator - after_dictator + diff_survey <- before_survey - after_survey + diff_time <- before_time - after_time + diff_chat <- before_chat - after_chat + + # Test difference + testthat::expect_gt(diff_aaw, 0) + testthat::expect_gt(diff_dictator, 0) + testthat::expect_gt(diff_survey, 0) + testthat::expect_gt(diff_time, 0) + testthat::expect_equal(diff_chat, 0) + + # Test if not all cases were deleted! + testthat::expect_gt(after_aaw, 0) + testthat::expect_gt(after_dictator, 0) + testthat::expect_gt(after_survey, 0) + testthat::expect_gt(after_time, 0) + testthat::expect_gt(after_chat, 0) + + # Test if deleted people are really deleted + test0 <- all(person_codes %in% otree2$info[["deleted_cases"]][["codes"]]) + test1 <- + !(otree2$info$deleted_cases$codes %in% + otree2$all_apps_wide$participant.code) + test2 <- + !(otree2$info$deleted_cases$codes %in% + otree2$dictator$participant.code) + test3 <- + !(otree2$info$deleted_cases$codes %in% + otree2$survey$participant.code) + test4 <- + !(otree2$info$deleted_cases$codes %in% + otree2$Time$participant_code) + test5a <- otree1$Chats$participant_code %in% + otree2$info$deleted_cases$codes # Chat differently: Before + test5b <- otree2$Chats$participant_code %in% + otree2$info$deleted_cases$codes # Chat differently: After + + testthat::expect_true(all(c(test0, test1, test2))) + testthat::expect_true(all(c(test3, test4))) + testthat::expect_equal(test5a, test5b) + + test1 <- length(otree2$info[["deleted_cases"]][["codes"]]) == + length(person_codes) + testthat::expect_true(test1) + + # Test for consistency + test1 <- setequal(otree2$info$deleted_cases$unique$participant.code, + otree2$info$deleted_cases$full$participant.code) + + test2 <- setequal(otree2$info$deleted_cases$unique$participant.code, + otree2$info$deleted_cases$codes) + test3 <- length(otree2$info$deleted_cases$codes) == + otree2$info$deleted_cases$count + test4 <- length(otree2$info$deleted_cases$codes) == + nrow(otree2$info$deleted_cases$unique) + testthat::expect_true(all(c(test1, test2, test3, test4))) +}) + +testthat::test_that("Delete cases - old", { + # Prepare data + otree1 <- otree_2_2_4 + labels <- c("Person4", "Person1") + person <- otree1$all_apps_wide$participant.code[ + otree1$all_apps_wide$participant.label %in% labels] + + # Before + before_aaw <- nrow(otree1$all_apps_wide) + before_dictator <- nrow(otree1$dictator) + before_survey <- nrow(otree1$survey) + before_time <- nrow(otree1$Time) + before_chat <- nrow(otree1$Chat) + + # Run function + otree2 <- delete_cases(otree1, + plabels = labels, + reason = "Only tests") + + # After + after_aaw <- nrow(otree2$all_apps_wide) + after_dictator <- nrow(otree2$dictator) + after_survey <- nrow(otree2$survey) + after_time <- nrow(otree2$Time) + after_chat <- nrow(otree2$Chat) + + # Diff + diff_aaw <- before_aaw - after_aaw + diff_dictator <- before_dictator - after_dictator + diff_survey <- before_survey - after_survey + diff_time <- before_time - after_time + diff_chat <- before_chat - after_chat + + # Test difference + testthat::expect_gt(diff_aaw, 0) + testthat::expect_gt(diff_dictator, 0) + testthat::expect_gt(diff_survey, 0) + testthat::expect_gt(diff_time, 0) + testthat::expect_equal(diff_chat, 0) # Equal zero!!! + + # Test if not all cases were deleted! + testthat::expect_gt(after_aaw, 0) + testthat::expect_gt(after_dictator, 0) + testthat::expect_gt(after_survey, 0) + testthat::expect_gt(after_time, 0) + testthat::expect_gt(after_chat, 0) + + # Test if deleted people are really deleted + test0a <- all( + person %in% otree2$info[["deleted_cases"]][["codes"]]) + + test0b <- length(otree2$info[["deleted_cases"]][["codes"]]) == + length(person) + + test1 <- + !(otree2$info$deleted_cases$codes %in% + otree2$all_apps_wide$participant.code) + test2 <- + !(otree2$info$deleted_cases$codes %in% + otree2$dictator$participant.code) + test3 <- + !(otree2$info$deleted_cases$codes %in% + otree2$survey$participant.code) + test4 <- + !(otree2$info$deleted_cases$codes %in% + otree2$Time$participant_code) + test5a <- otree1$Chats$participant_code %in% + otree2$info$deleted_cases$codes # Chat differently: Before + test5b <- otree2$Chats$participant_code %in% + otree2$info$deleted_cases$codes # Chat differently: After + + testthat::expect_true(all(c(test0a, test0b, test1, test2))) + testthat::expect_true(all(c(test3, test4))) + testthat::expect_equal(test5a, test5b) + + # Test if participant is really deleted - version 2 + test1 <- !(person %in% otree2$all_apps_wide$participant.code) + test2 <- !(person %in% otree2$dictator$participant.code) + test3 <- !(person %in% otree2$start$participant.code) + test4 <- !(person %in% otree2$survey$participant.code) + test5 <- !(person %in% otree2$Time$participant__code) + testthat::expect_true(all(c(test1, test2, test3, test4, test5))) + + # Test for consistency + test1 <- setequal(otree2$info$deleted_cases$unique$participant.code, + otree2$info$deleted_cases$full$participant.code) + + test2 <- setequal(otree2$info$deleted_cases$unique$participant.code, + otree2$info$deleted_cases$codes) + test3 <- length(otree2$info$deleted_cases$codes) == + otree2$info$deleted_cases$count + test4 <- length(otree2$info$deleted_cases$codes) == + nrow(otree2$info$deleted_cases$unique) + testthat::expect_true(all(c(test1, test2, test3, test4))) +}) + +testthat::test_that("Delete cases - saved vars", { + # Prepare data + otree1 <- otree_5_4_0 + person <- otree1$all_apps_wide$participant.code[1] + + # Before + before_aaw <- nrow(otree1$all_apps_wide) + before_dictator <- nrow(otree1$dictator) + before_survey <- nrow(otree1$survey) + before_time <- nrow(otree1$Time) + before_chat <- nrow(otree1$Chat) + + # Run function + otree2 <- delete_cases(otree1, + pcodes = person, + reason = "Upon request", + saved_vars = "dictator.1.group.id_in_subsession") + + # After + after_aaw <- nrow(otree2$all_apps_wide) + after_dictator <- nrow(otree2$dictator) + after_survey <- nrow(otree2$survey) + after_time <- nrow(otree2$Time) + after_chat <- nrow(otree2$Chat) + + # Diff + diff_aaw <- before_aaw - after_aaw + diff_dictator <- before_dictator - after_dictator + diff_survey <- before_survey - after_survey + diff_time <- before_time - after_time + diff_chat <- before_chat - after_chat + + # Test difference + testthat::expect_gt(diff_aaw, 0) + testthat::expect_gt(diff_dictator, 0) + testthat::expect_gt(diff_survey, 0) + testthat::expect_gt(diff_time, 0) + testthat::expect_equal(diff_chat, 0) + + # Test if not all cases were deleted! + testthat::expect_gt(after_aaw, 0) + testthat::expect_gt(after_dictator, 0) + testthat::expect_gt(after_survey, 0) + testthat::expect_gt(after_time, 0) + testthat::expect_gt(after_chat, 0) + + # Test if deleted people are really deleted (sample) + test0 <- person %in% otree2$info[["deleted_cases"]][["codes"]] + # Test if deleted people are really deleted + test1 <- + !(otree2$info$deleted_cases$codes %in% + otree2$all_apps_wide$participant.code) + test2 <- + !(otree2$info$deleted_cases$codes %in% + otree2$dictator$participant.code) + test3 <- + !(otree2$info$deleted_cases$codes %in% + otree2$survey$participant.code) + test4 <- + !(otree2$info$deleted_cases$codes %in% + otree2$Time$participant_code) + test5a <- otree1$Chats$participant_code %in% + otree2$info$deleted_cases$codes # Chat differently: Before + test5b <- otree2$Chats$participant_code %in% + otree2$info$deleted_cases$codes # Chat differently: After + + testthat::expect_true(all(c(test0, test1, test2))) + testthat::expect_true(all(c(test3, test4))) + testthat::expect_equal(test5a, test5b) + + test1 <- length(otree2$info[["deleted_cases"]][["codes"]]) == 1 + testthat::expect_true(test1) + + # Test if participant is really deleted - version 2 + test1 <- !(person %in% otree2$all_apps_wide$participant.code) + test2 <- !(person %in% otree2$dictator$participant.code) + test3 <- !(person %in% otree2$start$participant.code) + test4 <- !(person %in% otree2$survey$participant.code) + test5 <- !(person %in% otree2$Time$participant__code) + test6 <- !(person %in% otree2$Chats$participant__code) + testthat::expect_true(all(c(test1, test2, test3, test4, test5, test6))) + + # Test for consistency + test1 <- setequal(otree2$info$deleted_cases$unique$participant.code, + otree2$info$deleted_cases$full$participant.code) + + test2 <- setequal(otree2$info$deleted_cases$unique$participant.code, + otree2$info$deleted_cases$codes) + test3 <- length(otree2$info$deleted_cases$codes) == + otree2$info$deleted_cases$count + test4 <- length(otree2$info$deleted_cases$codes) == + nrow(otree2$info$deleted_cases$unique) + testthat::expect_true(all(c(test1, test2, test3, test4))) +}) + +testthat::test_that("Delete cases - old", { + # Prepare data + otree1 <- otree_2_2_4 + person <- otree1$all_apps_wide$participant.code[1] + + # Before + before_aaw <- nrow(otree1$all_apps_wide) + before_dictator <- nrow(otree1$dictator) + before_survey <- nrow(otree1$survey) + before_time <- nrow(otree1$Time) + check_time <- person %in% otree1$Time$participant__code + before_chat <- nrow(otree1$Chat) + + # Run function + otree2 <- delete_cases(otree1, person, reason = "Upon request") + + # After + after_aaw <- nrow(otree2$all_apps_wide) + after_dictator <- nrow(otree2$dictator) + after_survey <- nrow(otree2$survey) + after_time <- nrow(otree2$Time) + after_chat <- nrow(otree2$Chat) + + # Diff + diff_aaw <- before_aaw - after_aaw + diff_dictator <- before_dictator - after_dictator + diff_survey <- before_survey - after_survey + diff_time <- before_time - after_time + diff_chat <- before_chat - after_chat + + # Test difference + testthat::expect_gt(diff_aaw, 0) + testthat::expect_gt(diff_dictator, 0) + testthat::expect_gt(diff_survey, 0) + if (check_time == TRUE) { + testthat::expect_gt(diff_time, 0) + } else { + testthat::expect_equal(diff_time, 0) + } + testthat::expect_equal(diff_chat, 0) + + # Test if not all cases were deleted! + testthat::expect_gt(after_aaw, 0) + testthat::expect_gt(after_dictator, 0) + testthat::expect_gt(after_survey, 0) + testthat::expect_gt(after_time, 0) + testthat::expect_gt(after_chat, 0) + + # Test if deleted people are really deleted + test1 <- + !(otree2$info$deleted_cases$codes %in% + otree2$all_apps_wide$participant.code) + test2 <- + !(otree2$info$deleted_cases$codes %in% + otree2$dictator$participant.code) + test3 <- + !(otree2$info$deleted_cases$codes %in% + otree2$survey$participant.code) + test4 <- + !(otree2$info$deleted_cases$codes %in% + otree2$Time$participant__code) + test5a <- otree1$Chats$participant__code %in% + otree2$info$deleted_cases$codes # Chat differently: Before + test5b <- otree2$Chats$participant__code %in% + otree2$info$deleted_cases$codes # Chat differently: After + + testthat::expect_true(all(c(test1, test2))) + testthat::expect_true(all(c(test3, test4))) + testthat::expect_equal(test5a, test5b) + + test1 <- length(otree2$info[["deleted_cases"]][["codes"]]) == 1 + testthat::expect_true(test1) + + # Test if participant is really deleted - version 2 + test1 <- !(person %in% otree2$all_apps_wide$participant.code) + test2 <- !(person %in% otree2$dictator$participant.code) + test3 <- !(person %in% otree2$start$participant.code) + test4 <- !(person %in% otree2$survey$participant.code) + test5 <- !(person %in% otree2$Time$participant__code) + test6 <- (person %in% otree2$Chats$participant__code) + testthat::expect_true(all(c(test1, test2, test3, test4, test5, test6))) + + # Test for consistency + test1 <- setequal(otree2$info$deleted_cases$unique$participant.code, + otree2$info$deleted_cases$full$participant.code) + + test2 <- setequal(otree2$info$deleted_cases$unique$participant.code, + otree2$info$deleted_cases$codes) + test3 <- length(otree2$info$deleted_cases$codes) == + otree2$info$deleted_cases$count + test4 <- length(otree2$info$deleted_cases$codes) == + nrow(otree2$info$deleted_cases$unique) + testthat::expect_true(all(c(test1, test2, test3, test4))) +}) + +testthat::test_that("Delete cases (e) - old label not there", { + # Prepare data + otree2 <- otree_2_2_4 + + # Run function and test + testthat::expect_error(delete_cases(otree2, + plabels = "xyz", + reason = "Only tests")) +}) + +testthat::test_that("Delete cases (e)- person not there", { + # Prepare data + otree2 <- otree_5_4_0 + + # Run function and test + testthat::expect_error(delete_cases(otree2, + "notthere", + reason = "Upon request"), + "not in data frames") +}) + +testthat::test_that("Delete cases (e) - saved vars", { + # Prepare data + otree2 <- otree_5_4_0 + + # Run function and test + testthat::expect_error(delete_cases(otree2, "46kxib6w", + reason = "Upon request", + saved_vars = "wrongvars"), "not in") +}) + +testthat::test_that("Delete cases (e) - only participant code or label", { + # Prepare data + otree2 <- otree_5_4_0 + + # Run function and test + testthat::expect_error(delete_cases(otree2, + pcodes = "46kxib6w", + plabels = "Person1", + reason = "Upon request", + saved_vars = "wrongvars"), + "Please only specify either") +}) + +testthat::test_that("Delete cases (e) - participant not there", { + # Prepare data + otree2 <- otree_5_4_0 + + # Run function and test + testthat::expect_error(delete_cases(otree2, + pcodes = "falsecode", + reason = "Upon request"), + "not in data frames") +}) + +testthat::test_that("Delete cases (e) - no variable", { + # Prepare data + otree2 <- otree_5_4_0 + otree2$all_apps_wide$participant.code <- NULL + + # Run function and test + testthat::expect_error(delete_cases(otree2, + plabels = "Person1", + reason = "Upon request"), + "this function needs the variable") +}) + +testthat::test_that("Delete cases (e) - saved vars", { + # Prepare data + otree2 <- otree_5_4_0 + otree2$all_apps_wide <- NULL + + # Run function and test + testthat::expect_error(delete_cases(otree2, "46kxib6w", + reason = "Upon request", + saved_vars = "wrongvars"), + "only works") +}) + +testthat::test_that("Delete cases (e) - no participants", { + # Prepare data + otree2 <- otree_5_4_0 + otree2$all_apps_wide <- NULL + + # Run function and test + testthat::expect_error(delete_cases(otree2, + reason = "Upon request", + saved_vars = "wrongvars"), + "Please specify pcodes or plabels") +}) + +testthat::test_that("Delete cases (e) - participant code NA", { + # Prepare data + otree2 <- otree_5_4_0 + person <- c("46kxib6w", NA) + + # Run function and test + testthat::expect_error(delete_cases(otree2, + pcodes = person, + reason = "Only tests"), + "At least one element in pcodes is NA") +}) + +testthat::test_that("Delete cases (e) - empty participant code", { + # Prepare data + otree2 <- otree_5_4_0 + person <- c() + + # Run function and test + testthat::expect_error(delete_cases(otree2, + pcodes = person, + reason = "Only tests"), + "Please specify pcodes or plabels") +}) + +testthat::test_that("Delete cases (e) - participant label NA", { + # Prepare data + otree2 <- otree_5_4_0 + person <- c("Person4", NA) + + # Run function and test + testthat::expect_error(delete_cases(otree2, + plabels = person, + reason = "Only tests"), + "plabel is NA") +}) + +testthat::test_that("Delete cases (e) - not oTree", { + x <- c(1, 2, 3) + testthat::expect_error(delete_cases(x, + reason = "Only tests"), + "not a list of oTree") +}) + +testthat::test_that("Delete cases (e) - not otree2", { + x <- list(a = 1, b = 2, c = 3) + testthat::expect_error(delete_cases(x, + reason = "Only tests"), + "not a list of oTree") +}) + +testthat::test_that("Delete cases (e) - old and new otree", { + # Prepare data (delete person from old and new data frame) + otree2 <- otree_all + person1 <- otree2$Time$participant_code[ + !is.na(otree2$Time$participant_code)][1] + person2 <- otree2$Time$participant__code[ + !is.na(otree2$Time$participant__code)][1] + + person <- c(person1, person2) + + # Run function + error <- tryCatch( + delete_cases(otree2, + person, + reason = "Upon request", + info = TRUE), + error = function(e) e) + + # Test + testthat::expect_true(grepl( + "You combined data from old and new oTree versions", error)) + testthat::expect_true(grepl( + "messy_chat", error)) + testthat::expect_true(grepl( + "messy_time", error)) +}) + +testthat::test_that("Delete cases (e) - all but messed time done", { + # Prepare data (delete person from old and new data frame) + otree2 <- otree_all + person1 <- otree2$Time$participant_code[ + !is.na(otree2$Time$participant_code)][1] + person2 <- otree2$Time$participant__code[ + !is.na(otree2$Time$participant__code)][1] + + person <- c(person1, person2) + + otree2 <- messy_time(otree2, combine = TRUE) + # Run function + error <- tryCatch( + delete_cases(otree2, + person, + reason = "Upon request", + info = TRUE), + error = function(e) e) + + # Test + testthat::expect_true(grepl( + "You combined data from old and new oTree versions", error)) + testthat::expect_true(grepl( + "messy_chat", error)) + testthat::expect_false(grepl( + "messy_time", error)) +}) + +testthat::test_that("Delete cases (e) - all but messed chat done", { + # Prepare data (delete person from old and new data frame) + otree2 <- otree_all + person1 <- otree2$Time$participant_code[ + !is.na(otree2$Time$participant_code)][1] + person2 <- otree2$Time$participant__code[ + !is.na(otree2$Time$participant__code)][1] + person <- c(person1, person2) + otree2 <- messy_chat(otree2, combine = TRUE) + + # Run function + error <- tryCatch( + delete_cases(otree2, + person, + reason = "Upon request", + info = TRUE), + error = function(e) e) + + # Test + testthat::expect_true(grepl( + "You combined data from old and new oTree versions", error)) + testthat::expect_false(grepl( + "messy_chat", error)) + testthat::expect_true(grepl( + "messy_time", error)) +}) + +print("---- show_dropouts -----") + +# Delete sessions #### + +testthat::test_that("Delete sessions - old ", { + # Prepare data (get a session with at least 4 cases) + otree2 <- otree_2_2_4 + session <- as.data.frame(table(otree2$all_apps_wide$session.code)) + session <- session[session$Freq >= 4, 1] + part <- otree2$all_apps_wide$participant.code[ + otree2$all_apps_wide$session.code == session] + + # Before + before_aaw <- nrow(otree2$all_apps_wide) + before_dictator <- nrow(otree2$dictator) + before_survey <- nrow(otree2$survey) + before_time <- nrow(otree2$Time) + before_chat <- nrow(otree2$Chat) + + # Run function + testthat::expect_warning( + otree2 <- delete_sessions(otree2, + scodes = session, + reason = "Only tests"), + "Session information is taken from the data frames") + + # After + after_aaw <- nrow(otree2$all_apps_wide) + after_dictator <- nrow(otree2$dictator) + after_survey <- nrow(otree2$survey) + after_time <- nrow(otree2$Time) + after_chat <- nrow(otree2$Chat) + + # Diff + diff_aaw <- before_aaw - after_aaw + diff_dictator <- before_dictator - after_dictator + diff_survey <- before_survey - after_survey + diff_time <- before_time - after_time + diff_chat <- before_chat - after_chat + + # Test + testthat::expect_gt(diff_aaw, 0) + testthat::expect_gt(diff_dictator, 0) + testthat::expect_gt(diff_survey, 0) + testthat::expect_gt(diff_time, 0) + testthat::expect_gt(diff_chat, 0) + + # Test if sessions are really deleted + test1 <- !(session %in% otree2$all_apps_wide$session.code) + test2 <- !(session %in% otree2$dictator$session.code) + test3 <- !(session %in% otree2$start$session.code) + test4 <- !(session %in% otree2$survey$session.code) + test5 <- !(session %in% otree2$Chats$participant__session__code) + testthat::expect_true(all(c(test1, test2, test3, test4, test5))) + + # Test if participant is really deleted # todo die sind noch alle falsch + test1 <- !(part %in% otree2$all_apps_wide$participant.code) + test2 <- !(part %in% otree2$dictator$participant.code) + test3 <- !(part %in% otree2$start$participant.code) + test4 <- !(part %in% otree2$survey$participant.code) + test5 <- !(part %in% otree2$Time$participant__code) + test6 <- !(part %in% otree2$Chats$participant__code) + testthat::expect_true(all(c(test1, test2, test3, test4, test5, test6))) + + # Test for consistency of the info output + test1 <- setequal(otree2$info$deleted_cases$unique$participant.code, + otree2$info$deleted_cases$full$participant.code) + + test2 <- setequal(otree2$info$deleted_cases$unique$participant.code, + otree2$info$deleted_cases$codes) + test3 <- length(otree2$info$deleted_cases$codes) == + otree2$info$deleted_cases$count + test4 <- length(otree2$info$deleted_cases$codes) == + nrow(otree2$info$deleted_cases$unique) + testthat::expect_true(all(c(test1, test2, test3, test4))) +}) + +testthat::test_that("Delete sessions - new", { + # Prepare data (get a session with at least 4 cases) + otree2 <- otree_5_4_0 + session <- as.data.frame(table(otree2$all_apps_wide$session.code)) + session <- session[session$Freq >= 4, 1] + part <- otree2$all_apps_wide$participant.code[ + otree2$all_apps_wide$session.code == session] + + # Before + before_aaw <- nrow(otree2$all_apps_wide) + before_dictator <- nrow(otree2$dictator) + before_survey <- nrow(otree2$survey) + before_time <- nrow(otree2$Time) + before_chat <- nrow(otree2$Chat) + + # Run function + otree2 <- delete_sessions(otree2, + scodes = session, + reason = "Only tests") + # After + after_aaw <- nrow(otree2$all_apps_wide) + after_dictator <- nrow(otree2$dictator) + after_survey <- nrow(otree2$survey) + after_time <- nrow(otree2$Time) + after_chat <- nrow(otree2$Chat) + + # Diff + diff_aaw <- before_aaw - after_aaw + diff_dictator <- before_dictator - after_dictator + diff_survey <- before_survey - after_survey + diff_time <- before_time - after_time + diff_chat <- before_chat - after_chat + + # Test + testthat::expect_gt(diff_aaw, 0) + testthat::expect_gt(diff_dictator, 0) + testthat::expect_gt(diff_survey, 0) + testthat::expect_gt(diff_time, 0) + testthat::expect_gt(diff_chat, 0) + + # Test if participant is really deleted - version 1 + test1 <- !(part %in% otree2$all_apps_wide$participant.code) + test2 <- !(part %in% otree2$dictator$participant.code) + test3 <- !(part %in% otree2$start$participant.code) + test4 <- !(part %in% otree2$survey$participant.code) + test5 <- !(part %in% otree2$Time$participant__code) + test6 <- !(part %in% otree2$Chats$participant__code) + testthat::expect_true(all(c(test1, test2, test3, test4, test5, test6))) + + # Test if deleted people are really deleted - version 2 + test1 <- + !(otree2$info$deleted_cases$codes %in% + otree2$all_apps_wide$participant.code) + test2 <- + !(otree2$info$deleted_cases$codes %in% + otree2$dictator$participant.code) + test3 <- + !(otree2$info$deleted_cases$codes %in% + otree2$survey$participant.code) + test4 <- + !(otree2$info$deleted_cases$codes %in% + otree2$Time$participant_code) + test5 <- !(otree2$Chats$participant_code %in% + otree2$info$deleted_cases$codes) + + testthat::expect_true(all(c(test1, test2))) + testthat::expect_true(all(c(test3, test4))) + testthat::expect_true(all(test5)) + + # Test if deleted people are really deleted - version 3 + test1 <- !(session %in% otree2$all_apps_wide$session.code) + test2 <- !(session %in% otree2$dictator$session.code) + test3 <- !(session %in% otree2$start$session.code) + test4 <- !(session %in% otree2$survey$session.code) + test5 <- !(session %in% otree2$Time$session_code) + test6 <- !(session %in% otree2$Chats$session_code) + testthat::expect_true(all(c(test1, test2, test3, test4, test5, + test6))) + + # Test for consistency of the info output + test1 <- setequal(otree2$info$deleted_cases$unique$participant.code, + otree2$info$deleted_cases$full$participant.code) + + test2 <- setequal(otree2$info$deleted_cases$unique$participant.code, + otree2$info$deleted_cases$codes) + test3 <- length(otree2$info$deleted_cases$codes) == + otree2$info$deleted_cases$count + test4 <- length(otree2$info$deleted_cases$codes) == + nrow(otree2$info$deleted_cases$unique) + testthat::expect_true(all(c(test1, test2, test3, test4))) +}) + +testthat::test_that("Delete sessions - new, one random data frame", { + # Prepare data (get a session with at least 4 cases) + otree2 <- otree_5_4_0 + otree2$random_dataframe <- data.frame( + a = c(1, 2, 3), + b = c(4, 5, 6), + c = c(7, 8, 9)) + + session <- as.data.frame(table(otree2$all_apps_wide$session.code)) + session <- session[session$Freq >= 4, 1] + part <- otree2$all_apps_wide$participant.code[ + otree2$all_apps_wide$session.code == session] + + # Before + before_aaw <- nrow(otree2$all_apps_wide) + before_dictator <- nrow(otree2$dictator) + before_survey <- nrow(otree2$survey) + before_time <- nrow(otree2$Time) + before_chat <- nrow(otree2$Chat) + before_random <- nrow(otree2$random_dataframe) + + # Run function + otree2 <- delete_sessions(otree2, + scodes = session, + reason = "Only tests") + # After + after_aaw <- nrow(otree2$all_apps_wide) + after_dictator <- nrow(otree2$dictator) + after_survey <- nrow(otree2$survey) + after_time <- nrow(otree2$Time) + after_chat <- nrow(otree2$Chat) + after_random <- nrow(otree2$random_dataframe) + + # Diff + diff_aaw <- before_aaw - after_aaw + diff_dictator <- before_dictator - after_dictator + diff_survey <- before_survey - after_survey + diff_time <- before_time - after_time + diff_chat <- before_chat - after_chat + diff_random <- before_random - after_random + + # Test + testthat::expect_gt(diff_aaw, 0) + testthat::expect_gt(diff_dictator, 0) + testthat::expect_gt(diff_survey, 0) + testthat::expect_gt(diff_time, 0) + testthat::expect_gt(diff_chat, 0) + testthat::expect_equal(diff_random, 0) + + # Test if deleted people are really deleted + test1 <- + !(otree2$info$deleted_cases$codes %in% + otree2$all_apps_wide$participant.code) + test2 <- + !(otree2$info$deleted_cases$codes %in% + otree2$dictator$participant.code) + test3 <- + !(otree2$info$deleted_cases$codes %in% + otree2$survey$participant.code) + test4 <- + !(otree2$info$deleted_cases$codes %in% + otree2$Time$participant_code) + test5 <- !(otree2$Chats$participant_code %in% + otree2$info$deleted_cases$codes) + + testthat::expect_true(all(c(test1, test2))) + testthat::expect_true(all(c(test3, test4))) + testthat::expect_true(all(test5)) + + # Test if participant is really deleted - version 2 + test1 <- !(part %in% otree2$all_apps_wide$participant.code) + test2 <- !(part %in% otree2$dictator$participant.code) + test3 <- !(part %in% otree2$start$participant.code) + test4 <- !(part %in% otree2$survey$participant.code) + test5 <- !(part %in% otree2$Time$participant__code) + test6 <- !(part %in% otree2$Chats$participant__code) + testthat::expect_true(all(c(test1, test2, test3, test4, test5, test6))) + + # Test if participant is really deleted - version 3 + test1 <- !(session %in% otree2$all_apps_wide$session.code) + test2 <- !(session %in% otree2$dictator$session.code) + test3 <- !(session %in% otree2$start$session.code) + test4 <- !(session %in% otree2$survey$session.code) + test5 <- !(session %in% otree2$Time$session_code) + test6 <- !(session %in% otree2$Chats$session_code) + testthat::expect_true(all(c(test1, test2, test3, test4, test5, + test6))) + + # Test for consistency of the info output + test1 <- setequal(otree2$info$deleted_cases$unique$participant.code, + otree2$info$deleted_cases$full$participant.code) + + test2 <- setequal(otree2$info$deleted_cases$unique$participant.code, + otree2$info$deleted_cases$codes) + test3 <- length(otree2$info$deleted_cases$codes) == + otree2$info$deleted_cases$count + test4 <- length(otree2$info$deleted_cases$codes) == + nrow(otree2$info$deleted_cases$unique) + testthat::expect_true(all(c(test1, test2, test3, test4))) +}) + +testthat::test_that("Delete sessions - new info = TRUE", { + # Prepare data (get a session with at least 4 cases) + otree2 <- otree_5_4_0 + session <- as.data.frame(table(otree2$all_apps_wide$session.code)) + session <- session[session$Freq >= 4, 1] + + # Run function + testthat::expect_message( + otree2 <- delete_sessions(otree2, + scodes = session, + reason = "Only tests", + info = TRUE), + "deleted") +}) + +testthat::test_that("Delete sessions - no cases", { + # Prepare data + otree2 <- otree_5_4_0 + + # Before + before_aaw <- nrow(otree2$all_apps_wide) + before_dictator <- nrow(otree2$dictator) + before_survey <- nrow(otree2$survey) + before_time <- nrow(otree2$Time) + before_chat <- nrow(otree2$Chat) + + # Run function + testthat::expect_warning( + otree2 <- delete_sessions(otree2, + scodes = "xyz", + reason = "Only tests"), + "The session can not be found in any of the data frames") + + # After + after_aaw <- nrow(otree2$all_apps_wide) + after_dictator <- nrow(otree2$dictator) + after_survey <- nrow(otree2$survey) + after_time <- nrow(otree2$Time) + after_chat <- nrow(otree2$Chat) + + # Diff + diff_aaw <- before_aaw - after_aaw + diff_dictator <- before_dictator - after_dictator + diff_survey <- before_survey - after_survey + diff_time <- before_time - after_time + diff_chat <- before_chat - after_chat + + # Test + testthat::expect_equal(diff_aaw, 0) + testthat::expect_equal(diff_dictator, 0) + testthat::expect_equal(diff_survey, 0) + testthat::expect_equal(diff_time, 0) + testthat::expect_equal(diff_chat, 0) + + # Test for consistency of the info output (everything is NULL!) + test1 <- setequal(otree2$info$deleted_cases$unique$participant.code, + otree2$info$deleted_cases$full$participant.code) + test2 <- setequal(otree2$info$deleted_cases$unique$participant.code, + otree2$info$deleted_cases$codes) + test3 <- length(otree2$info$deleted_cases$codes) == + otree2$info$deleted_cases$count + test4 <- length(otree2$info$deleted_cases$codes) == + nrow(otree2$info$deleted_cases$unique) + testthat::expect_true(all(c(test1, test2, test3, test4))) +}) + +testthat::test_that("Delete sessions - without aaw", { + # Prepare data (take a session with more people so there is a chat in it) + otree2 <- otree_5_4_0 + session <- as.data.frame(table(otree2$all_apps_wide$session.code)) + session <- session[session$Freq >= 4, 1] + part <- otree2$all_apps_wide$participant.code[ + otree2$all_apps_wide$session.code == session] + otree2$all_apps_wide <- NULL + + # Before + before_dictator <- nrow(otree2$dictator) + before_survey <- nrow(otree2$survey) + before_time <- nrow(otree2$Time) + before_chat <- nrow(otree2$Chat) + + # Run function + otree2 <- delete_sessions(otree2, + scodes = session, + reason = "Only tests") + + # After + after_dictator <- nrow(otree2$dictator) + after_survey <- nrow(otree2$survey) + after_time <- nrow(otree2$Time) + after_chat <- nrow(otree2$Chat) + + # Diff + diff_dictator <- before_dictator - after_dictator + diff_survey <- before_survey - after_survey + diff_time <- before_time - after_time + diff_chat <- before_chat - after_chat + + # Test + testthat::expect_gt(diff_dictator, 0) + testthat::expect_gt(diff_survey, 0) + testthat::expect_gt(diff_time, 0) + testthat::expect_gt(diff_chat, 0) # here greater 0 because all people + # in one group/chat are deleted + + # Test if deleted people are really deleted + test1 <- + !(otree2$info$deleted_cases$codes %in% + otree2$all_apps_wide$participant.code) + test2 <- + !(otree2$info$deleted_cases$codes %in% + otree2$dictator$participant.code) + test3 <- + !(otree2$info$deleted_cases$codes %in% + otree2$survey$participant.code) + test4 <- + !(otree2$info$deleted_cases$codes %in% + otree2$Time$participant_code) + test5 <- all(!(otree2$Chats$participant_code %in% + otree2$info$deleted_cases$codes)) + + testthat::expect_true(all(c(test1, test2))) + testthat::expect_true(all(c(test3, test4))) + testthat::expect_true(test5) + + # Test if participant is really deleted - version 2 + test1 <- !(part %in% otree2$all_apps_wide$participant.code) + test2 <- !(part %in% otree2$dictator$participant.code) + test3 <- !(part %in% otree2$start$participant.code) + test4 <- !(part %in% otree2$survey$participant.code) + test5 <- !(part %in% otree2$Time$participant__code) + test6 <- !(part %in% otree2$Chats$participant__code) + testthat::expect_true(all(c(test1, test2, test3, test4, test5, test6))) + + # Test for consistency of the info output + test1 <- setequal(otree2$info$deleted_cases$unique$participant.code, + otree2$info$deleted_cases$full$participant.code) + test2 <- setequal(otree2$info$deleted_cases$unique$participant.code, + otree2$info$deleted_cases$codes) + test3 <- length(otree2$info$deleted_cases$codes) == + otree2$info$deleted_cases$count + test4 <- length(otree2$info$deleted_cases$codes) == + nrow(otree2$info$deleted_cases$unique) + testthat::expect_true(all(c(test1, test2, test3, test4))) +}) + +testthat::test_that("Delete sessions - old - warning Chat", { + # Prepare data + otree2 <- otree_2_2_4 + session <- unique(otree2$Chats$participant__session__code)[1] + otree2$Chats$participant__session__code <- NULL + part <- otree2$all_apps_wide$participant.code[ + otree2$all_apps_wide$session.code == session] + + # Before + before_dictator <- nrow(otree2$dictator) + before_survey <- nrow(otree2$survey) + before_time <- nrow(otree2$Time) + before_chat <- nrow(otree2$Chat) + + # Run function + testthat::expect_warning( + otree2 <- delete_sessions(otree2, + scodes = session, + reason = "Only tests"), + "No variable called \"session code\"") + + # After + after_dictator <- nrow(otree2$dictator) + after_survey <- nrow(otree2$survey) + after_time <- nrow(otree2$Time) + after_chat <- nrow(otree2$Chat) + + # Diff + diff_dictator <- before_dictator - after_dictator + diff_survey <- before_survey - after_survey + diff_time <- before_time - after_time + diff_chat <- before_chat - after_chat + + # Test + testthat::expect_gt(diff_dictator, 0) + testthat::expect_gt(diff_survey, 0) + testthat::expect_gt(diff_time, 0) + testthat::expect_gt(diff_chat, 0) # here greater 0 because all people + # in one group/chat are deleted + + # Test if deleted people are really deleted + test1 <- + !(otree2$info$deleted_cases$codes %in% + otree2$all_apps_wide$participant.code) + test2 <- + !(otree2$info$deleted_cases$codes %in% + otree2$dictator$participant.code) + test3 <- + !(otree2$info$deleted_cases$codes %in% + otree2$survey$participant.code) + test4 <- + !(otree2$info$deleted_cases$codes %in% + otree2$Time$participant__code) + test5 <- all(!(otree2$Chats$participant__code %in% + otree2$info$deleted_cases$codes)) + + testthat::expect_true(all(c(test1, test2))) + testthat::expect_true(all(c(test3, test4))) + testthat::expect_true(test5) + + # Test if participant is really deleted - version 2 + test1 <- !(part %in% otree2$all_apps_wide$participant.code) + test2 <- !(part %in% otree2$dictator$participant.code) + test3 <- !(part %in% otree2$start$participant.code) + test4 <- !(part %in% otree2$survey$participant.code) + test5 <- !(part %in% otree2$Time$participant__code) + test6 <- !(part %in% otree2$Chats$participant__code) + testthat::expect_true(all(c(test1, test2, test3, test4, test5, test6))) + + # Test for consistency of the info output + test1 <- setequal(otree2$info$deleted_cases$unique$participant.code, + otree2$info$deleted_cases$full$participant.code) + test2 <- setequal(otree2$info$deleted_cases$unique$participant.code, + otree2$info$deleted_cases$codes) + test3 <- length(otree2$info$deleted_cases$codes) == + otree2$info$deleted_cases$count + test4 <- length(otree2$info$deleted_cases$codes) == + nrow(otree2$info$deleted_cases$unique) + testthat::expect_true(all(c(test1, test2, test3, test4))) +}) + +testthat::test_that("Delete sessions (e) - not oTree", { + x <- c(1, 2, 3) + testthat::expect_error(delete_sessions(x, + scodes = "t0rog7nz", + reason = "Only tests"), + "not a list of oTree") +}) + +testthat::test_that("Delete sessions (e) - app Test", { + x <- list(a = 1, b = 2, c = 3) + testthat::expect_error(delete_sessions(x, + scodes = "t0rog7nz", + reason = "Only tests"), + "not a list of oTree") +}) + +testthat::test_that("Delete sessions (e) - all messy time and chat", { + # Prepare data + otree2 <- otree_all + session <- as.data.frame(table(otree2$all_apps_wide$session.code)) + session <- session[session$Freq >= 4, 1] + + # Run function and test + testthat::expect_error( + otree2 <- delete_sessions(otree2, + scodes = session, + reason = "Only tests"), + "You combined data from old and new oTree versions") +}) + +testthat::test_that("Delete sessions (e) - all messy chat", { + # Prepare data + otree2 <- otree_all + session <- as.data.frame(table(otree2$all_apps_wide$session.code)) + session <- session[session$Freq >= 4, 1] + testthat::expect_warning( + otree2 <- messy_time(otree2, combine = TRUE, info = TRUE)) + + # Run function and test + testthat::expect_error( + otree2 <- delete_sessions(otree2, + scodes = session, + reason = "Only tests"), + "You combined data from old and new oTree versions") +}) + +testthat::test_that("Delete sessions (e) - all messy time", { + # Prepare data + otree2 <- otree_all + session <- as.data.frame(table(otree2$all_apps_wide$session.code)) + session <- session[session$Freq >= 4, 1] + otree2 <- messy_chat(otree2, combine = TRUE) + + # Run function and test + testthat::expect_error( + otree2 <- delete_sessions(otree2, + scodes = session, + reason = "Only tests"), + "You combined data from old and new oTree versions") +}) + +# Show dropouts #### +testthat::test_that("Show dropouts - new oTree, final_apps", { + # Prepare data + otree2 <- otree_5_4_0 + + # Run function + output <- show_dropouts(otree2, final_apps = "survey") + + # Test + + # Test if all data frames and other vectors/values are there + test1 <- "full" %in% names(output) + test2 <- "unique" %in% names(output) + test3 <- "all_end" %in% names(output) + test4 <- "codes" %in% names(output) + test5 <- "count" %in% names(output) + testthat::expect_true(all(c(test1, test2, test3, + test4, test5))) + + # Test for consistency of the info output + test1 <- setequal(output$unique$participant.code, + output$full$participant.code) + test2 <- setequal(output$unique$participant.code, output$codes) + test3 <- length(output$codes) == output$count + test4 <- length(output$codes) == nrow(output$unique) + testthat::expect_true(all(c(test1, test2, test3, test4))) +}) + +testthat::test_that("Show dropouts - new oTree, final_apps, one random df", { + # Prepare data + otree2 <- otree_5_4_0 + otree2$random_dataframe <- data.frame( + a = c(1, 2, 3), + b = c(4, 5, 6), + c = c(7, 8, 9)) + + # Run function + output <- show_dropouts(otree2, final_apps = "survey") + + # Test + + # Test if random df is not in list + test1 <- !(any(grepl("random_dataframe", output$full$reason))) + testthat::expect_true(test1) + + # Test if all data frames and other vectors/values are there + test1 <- "full" %in% names(output) + test2 <- "unique" %in% names(output) + test3 <- "all_end" %in% names(output) + test4 <- "codes" %in% names(output) + test5 <- "count" %in% names(output) + testthat::expect_true(all(c(test1, test2, test3, + test4, test5))) + + # Test for consistency of the info output + test1 <- setequal(output$unique$participant.code, + output$full$participant.code) + + test2 <- setequal(output$unique$participant.code, output$codes) + test3 <- length(output$codes) == output$count + test4 <- length(output$codes) == nrow(output$unique) + testthat::expect_true(all(c(test1, test2, test3, test4))) +}) + +testthat::test_that("Show dropouts - 2", { + # Prepare data (example with inconsistent end pages) + otree2 <- otree_5_4_0 + person <- otree2$all_apps_wide$participant.code[ + otree2$all_apps_wide$participant._current_app_name == "survey"][1] + otree2$all_apps_wide$participant._current_app_name[ + otree2$all_apps_wide$participant._current_app_name == "survey"][1] <- + "othername" + + # Before + before_aaw <- nrow(otree2$all_apps_wide) + before_dictator <- nrow(otree2$dictator) + before_survey <- nrow(otree2$survey) + before_time <- nrow(otree2$Time) + before_chat <- nrow(otree2$Chat) + + # Run function + testthat::expect_warning( + output <- show_dropouts(otree2, + final_apps = "survey"), + "At least one participant in the dropout") + + # Test + test1 <- person %in% output$unique$participant.code + test2 <- person %in% output$full$participant.code + test3 <- person %in% output$codes + testthat::expect_true(all(c(test1, test2, test3))) + + # Test for consistency of the info output + test1 <- setequal(output$unique$participant.code, + output$full$participant.code) + test2 <- setequal(output$unique$participant.code, output$codes) + test3 <- length(output$codes) == output$count + test4 <- length(output$codes) == nrow(output$unique) + testthat::expect_true(all(c(test1, test2, test3, test4))) +}) + +testthat::test_that("Show dropouts - 2.2.4", { + # Prepare data + otree2 <- otree_2_2_4 + + # Run function + output <- show_dropouts(otree2, final_apps = "survey") + + # Test + # Test if all data frames and other vectors/values are there + test1 <- "full" %in% names(output) + test2 <- "unique" %in% names(output) + test3 <- "all_end" %in% names(output) + test4 <- "codes" %in% names(output) + test5 <- "count" %in% names(output) + testthat::expect_true(all(c(test1, test2, test3, test4, test5))) + + # Test for consistency of the info output + test1 <- setequal(output$unique$participant.code, + output$full$participant.code) + test2 <- setequal(output$unique$participant.code, output$codes) + test3 <- length(output$codes) == output$count + test4 <- length(output$codes) == nrow(output$unique) + testthat::expect_true(all(c(test1, test2, test3, test4))) +}) + +testthat::test_that("Show dropouts - pagenames", { + # Prepare data + otree2 <- otree_5_4_0 + + # Run function + output <- show_dropouts(otree2, final_pages = "Demographics") + + # Test + # Test if all data frames and other vectors/values are there + test1 <- "full" %in% names(output) + test2 <- "unique" %in% names(output) + test3 <- "all_end" %in% names(output) + test4 <- "codes" %in% names(output) + test5 <- "count" %in% names(output) + testthat::expect_true(all(c(test1, test2, test3, test4, test5))) + + # Test for consistency of the info output + test1 <- setequal(output$unique$participant.code, + output$full$participant.code) + test2 <- setequal(output$unique$participant.code, output$codes) + test3 <- length(output$codes) == output$count + test4 <- length(output$codes) == nrow(output$unique) + testthat::expect_true(all(c(test1, test2, test3, test4))) +}) + +testthat::test_that("Show dropouts - final_apps and pagenames", { + # Prepare data + otree2 <- otree_5_4_0 + + # Run function + output <- show_dropouts(otree2, + final_apps = "survey", + final_pages = "Demographics") + + # Test + # Test if all data frames and other vectors/values are there + test1 <- "full" %in% names(output) + test2 <- "unique" %in% names(output) + test3 <- "all_end" %in% names(output) + test4 <- "codes" %in% names(output) + test5 <- "count" %in% names(output) + testthat::expect_true(all(c(test1, test2, test3, test4, test5))) + + # Test for consistency of the info output + test1 <- setequal(output$unique$participant.code, + output$full$participant.code) + + test2 <- setequal(output$unique$participant.code, output$codes) + test3 <- length(output$codes) == output$count + test4 <- length(output$codes) == nrow(output$unique) + testthat::expect_true(all(c(test1, test2, test3, test4))) +}) + +testthat::test_that("Show dropouts - saved vars", { + # Prepare data + otree2 <- otree_5_4_0 + + # Run function + output <- show_dropouts(otree2, "survey", + saved_vars = "dictator.1.group.id_in_subsession") + + # Test + # Test if all data frames and other vectors/values are there + test1 <- "full" %in% names(output) + test2 <- "unique" %in% names(output) + test3 <- "all_end" %in% names(output) + test4 <- "codes" %in% names(output) + test5 <- "count" %in% names(output) + testthat::expect_true(all(c(test1, test2, test3, test4, test5))) + + # Test for consistency of the info output + test1 <- setequal(output$unique$participant.code, + output$full$participant.code) + + test2 <- setequal(output$unique$participant.code, output$codes) + test3 <- length(output$codes) == output$count + test4 <- length(output$codes) == nrow(output$unique) + testthat::expect_true(all(c(test1, test2, test3, test4))) + + # Test if saved variable is there + test1 <- "dictator.1.group.id_in_subsession" %in% names(output$unique) + test2 <- "dictator.1.group.id_in_subsession" %in% names(output$full) + testthat::expect_true(all(c(test1, test2))) +}) + +testthat::test_that("Show dropouts - saved vars not there", { + # Prepare data + otree2 <- otree_5_4_0 + + # Run function and test + testthat::expect_error(show_dropouts(otree2, "survey", + saved_vars = "invalidvar"), + "saved_vars not in all_apps_wide") +}) + +testthat::test_that("Show dropouts (e) - specify", { + # Prepare data + otree2 <- otree_5_4_0 + + # Run function and test + expect_error(show_dropouts(otree2), + "Please specify final_apps or final_pages or both") +}) + +testthat::test_that("Show dropouts (w) - saved vars", { + # Prepare data + otree2 <- otree_5_4_0 + otree2$all_apps_wide <- NULL + + # Run function and test + testthat::expect_warning( + output <- + show_dropouts(otree2, + final_apps = "survey", + saved_vars = "dictator.1.group.id_in_subsession"), "is ignored.") + + # Test + # Test if all data frames and other vectors/values are there + test1 <- "full" %in% names(output) + test2 <- "unique" %in% names(output) + test3 <- !("all_end" %in% names(output)) # all_end is only shown if aaw exist + test4 <- "codes" %in% names(output) + test5 <- "count" %in% names(output) + testthat::expect_true(all(c(test1, test2, test3, + test4, test5))) + + # Test for consistency of the info output + test1 <- setequal(output$unique$participant.code, + output$full$participant.code) + + test2 <- setequal(output$unique$participant.code, output$codes) + test3 <- length(output$codes) == output$count + test4 <- length(output$codes) == nrow(output$unique) + testthat::expect_true(all(c(test1, test2, test3, test4))) +}) + +print("---- delete_dropouts -----") +# Delete dropouts #### +testthat::test_that("Delete dropouts - final_apps new oTree", { + # Prepare data + otree1 <- otree_5_4_0 + + # Before + before_aaw <- nrow(otree1$all_apps_wide) + before_dictator <- nrow(otree1$dictator) + before_survey <- nrow(otree1$survey) + before_time <- nrow(otree1$Time) + before_chat <- nrow(otree1$Chat) + + # Run function + otree2 <- delete_dropouts(otree1, + final_apps = "survey") + + # After + after_aaw <- nrow(otree2$all_apps_wide) + after_dictator <- nrow(otree2$dictator) + after_survey <- nrow(otree2$survey) + after_time <- nrow(otree2$Time) + after_chat <- nrow(otree2$Chat) + + # Diff + diff_aaw <- before_aaw - after_aaw + diff_dictator <- before_dictator - after_dictator + diff_survey <- before_survey - after_survey + diff_time <- before_time - after_time + diff_chat <- before_chat - after_chat + + # Test difference + testthat::expect_gt(diff_aaw, 0) + testthat::expect_gt(diff_dictator, 0) + testthat::expect_gt(diff_survey, 0) + testthat::expect_gt(diff_time, 0) + testthat::expect_equal(diff_chat, 0) # Equal zero!!! + + # Test if not all cases were deleted! + testthat::expect_gt(after_aaw, 0) + testthat::expect_gt(after_dictator, 0) + testthat::expect_gt(after_survey, 0) + testthat::expect_gt(after_time, 0) + testthat::expect_gt(after_chat, 0) + + # if deleted people are really deleted + test1 <- + !(otree2$info$deleted_cases$codes %in% + otree2$all_apps_wide$participant.code) + test2 <- + !(otree2$info$deleted_cases$codes %in% + otree2$dictator$participant.code) + test3 <- + !(otree2$info$deleted_cases$codes %in% + otree2$survey$participant.code) + test4 <- + !(otree2$info$deleted_cases$codes %in% + otree2$Time$participant_code) + + testthat::expect_true(all(c(test1, test2))) + testthat::expect_true(all(c(test3, test4))) + + # Chat differently + test5a <- (otree2$info$deleted_cases$codes %in% + otree1$Chats$participant_code) # Before + test5b <- (otree2$info$deleted_cases$codes %in% + otree2$Chats$participant_code) # After + + testthat::expect_equal(test5a, test5b) + + # Test for consistency of the info output + test1 <- setequal(otree2$info$deleted_cases$unique$participant.code, + otree2$info$deleted_cases$full$participant.code) + test2 <- setequal(otree2$info$deleted_cases$unique$participant.code, + otree2$info$deleted_cases$codes) + test3 <- length(otree2$info$deleted_cases$codes) == + otree2$info$deleted_cases$count + test4 <- length(otree2$info$deleted_cases$codes) == + nrow(otree2$info$deleted_cases$unique) + testthat::expect_true(all(c(test1, test2, test3, test4))) +}) + +testthat::test_that("Delete dropouts - final_apps new oTree, random df", { + # Prepare data + otree1 <- otree_5_4_0 + otree1$random_dataframe <- data.frame( + a = c(1, 2, 3), + b = c(4, 5, 6), + c = c(7, 8, 9)) + + # Before + before_aaw <- nrow(otree1$all_apps_wide) + before_dictator <- nrow(otree1$dictator) + before_survey <- nrow(otree1$survey) + before_time <- nrow(otree1$Time) + before_chat <- nrow(otree1$Chat) + before_random <- nrow(otree1$random_dataframe) + + # Run function + otree2 <- delete_dropouts(otree1, + final_apps = "survey") + + # After + after_aaw <- nrow(otree2$all_apps_wide) + after_dictator <- nrow(otree2$dictator) + after_survey <- nrow(otree2$survey) + after_time <- nrow(otree2$Time) + after_chat <- nrow(otree2$Chat) + after_random <- nrow(otree2$random_dataframe) + + # Diff + diff_aaw <- before_aaw - after_aaw + diff_dictator <- before_dictator - after_dictator + diff_survey <- before_survey - after_survey + diff_time <- before_time - after_time + diff_chat <- before_chat - after_chat + diff_random <- before_random - after_random + + # Test difference + testthat::expect_gt(diff_aaw, 0) + testthat::expect_gt(diff_dictator, 0) + testthat::expect_gt(diff_survey, 0) + testthat::expect_gt(diff_time, 0) + testthat::expect_equal(diff_chat, 0) # Equal zero!!! + testthat::expect_equal(diff_random, 0) + + # Test if not all cases were deleted! + testthat::expect_gt(after_aaw, 0) + testthat::expect_gt(after_dictator, 0) + testthat::expect_gt(after_survey, 0) + testthat::expect_gt(after_time, 0) + testthat::expect_gt(after_chat, 0) + testthat::expect_gt(after_random, 0) + + # Test if random df is not in list + test1 <- !(any(grepl("random_dataframe", + otree2$info$deleted_cases$full$reason))) + testthat::expect_true(test1) + + # Test if deleted people are really deleted + test1 <- + !(otree2$info$deleted_cases$codes %in% + otree2$all_apps_wide$participant.code) + test2 <- + !(otree2$info$deleted_cases$codes %in% + otree2$dictator$participant.code) + test3 <- + !(otree2$info$deleted_cases$codes %in% + otree2$survey$participant.code) + test4 <- + !(otree2$info$deleted_cases$codes %in% + otree2$Time$participant_code) + + testthat::expect_true(all(c(test1, test2))) + testthat::expect_true(all(c(test3, test4))) + + # Chat differently + test5a <- (otree2$info$deleted_cases$codes %in% + otree1$Chats$participant_code) # Before + test5b <- (otree2$info$deleted_cases$codes %in% + otree2$Chats$participant_code) # After + + testthat::expect_equal(test5a, test5b) + + # Test for consistency of the info output + test1 <- setequal(otree2$info$deleted_cases$unique$participant.code, + otree2$info$deleted_cases$full$participant.code) + test2 <- setequal(otree2$info$deleted_cases$unique$participant.code, + otree2$info$deleted_cases$codes) + test3 <- length(otree2$info$deleted_cases$codes) == + otree2$info$deleted_cases$count + test4 <- length(otree2$info$deleted_cases$codes) == + nrow(otree2$info$deleted_cases$unique) + testthat::expect_true(all(c(test1, test2, test3, test4))) +}) + +testthat::test_that("Delete dropouts - final_apps old oTree", { + # Prepare data + otree1 <- otree_2_2_4 + + # Before + before_aaw <- nrow(otree1$all_apps_wide) + before_dictator <- nrow(otree1$dictator) + before_survey <- nrow(otree1$survey) + before_time <- nrow(otree1$Time) + before_chat <- nrow(otree1$Chat) + + # Run function + otree2 <- delete_dropouts(otree1, + final_apps = "survey") + + # After + after_aaw <- nrow(otree2$all_apps_wide) + after_dictator <- nrow(otree2$dictator) + after_survey <- nrow(otree2$survey) + after_time <- nrow(otree2$Time) + after_chat <- nrow(otree2$Chat) + + # Diff + diff_aaw <- before_aaw - after_aaw + diff_dictator <- before_dictator - after_dictator + diff_survey <- before_survey - after_survey + diff_time <- before_time - after_time + diff_chat <- before_chat - after_chat + + # Test difference + testthat::expect_gt(diff_aaw, 0) + testthat::expect_gt(diff_dictator, 0) + testthat::expect_gt(diff_survey, 0) + testthat::expect_gt(diff_time, 0) + testthat::expect_equal(diff_chat, 0) # Equal zero!!! + + # Test if not all cases were deleted! + testthat::expect_gt(after_aaw, 0) + testthat::expect_gt(after_dictator, 0) + testthat::expect_gt(after_survey, 0) + testthat::expect_gt(after_time, 0) + testthat::expect_gt(after_chat, 0) + + # Test if deleted people are really deleted + test1 <- + !(otree2$info$deleted_cases$codes %in% + otree2$all_apps_wide$participant.code) + test2 <- + !(otree2$info$deleted_cases$codes %in% + otree2$dictator$participant.code) + test3 <- + !(otree2$info$deleted_cases$codes %in% + otree2$survey$participant.code) + test4 <- + !(otree2$info$deleted_cases$codes %in% + otree2$Time$participant_code) + + testthat::expect_true(all(c(test1, test2))) + testthat::expect_true(all(c(test3, test4))) + + # Chat differently + test5a <- (otree2$info$deleted_cases$codes %in% + otree1$Chats$participant_code) # Before + test5b <- (otree2$info$deleted_cases$codes %in% + otree2$Chats$participant_code) # After + + testthat::expect_equal(test5a, test5b) + + # Test for consistency of the info output + test1 <- setequal(otree2$info$deleted_cases$unique$participant.code, + otree2$info$deleted_cases$full$participant.code) + + test2 <- setequal(otree2$info$deleted_cases$unique$participant.code, + otree2$info$deleted_cases$codes) + test3 <- length(otree2$info$deleted_cases$codes) == + otree2$info$deleted_cases$count + test4 <- length(otree2$info$deleted_cases$codes) == + nrow(otree2$info$deleted_cases$unique) + testthat::expect_true(all(c(test1, test2, test3, test4))) +}) + +testthat::test_that("Delete dropouts - different otree versions", { + # Prepare data + otree1 <- otree_all + + # Before + before_aaw <- nrow(otree1$all_apps_wide) + before_dictator <- nrow(otree1$dictator) + before_survey <- nrow(otree1$survey) + before_time <- nrow(otree1$Time) + before_chat <- nrow(otree1$Chat) + + # Run function + otree2 <- delete_dropouts(otree1, + final_apps = "survey") + # After + after_aaw <- nrow(otree2$all_apps_wide) + after_dictator <- nrow(otree2$dictator) + after_survey <- nrow(otree2$survey) + after_time <- nrow(otree2$Time) + after_chat <- nrow(otree2$Chat) + + # Diff + diff_aaw <- before_aaw - after_aaw + diff_dictator <- before_dictator - after_dictator + diff_survey <- before_survey - after_survey + diff_time <- before_time - after_time + diff_chat <- before_chat - after_chat + + # Test difference + testthat::expect_gt(diff_aaw, 0) + testthat::expect_gt(diff_dictator, 0) + testthat::expect_gt(diff_survey, 0) + testthat::expect_gt(diff_time, 0) + testthat::expect_equal(diff_chat, 0) # Equal zero!!! + + # Test if not all cases were deleted! + testthat::expect_gt(after_aaw, 0) + testthat::expect_gt(after_dictator, 0) + testthat::expect_gt(after_survey, 0) + testthat::expect_gt(after_time, 0) + testthat::expect_gt(after_chat, 0) + + # Test if deleted people are really deleted + test1 <- + !(otree2$info$deleted_cases$codes %in% + otree2$all_apps_wide$participant.code) + test2 <- + !(otree2$info$deleted_cases$codes %in% + otree2$dictator$participant.code) + test3 <- + !(otree2$info$deleted_cases$codes %in% + otree2$survey$participant.code) + + testthat::expect_true(all(c(test1, test2))) + testthat::expect_true(all(c(test3))) + + # Time differently + test1 <- !any(otree2$info[["deleted_cases"]][["codes"]] %in% + unique(otree2$Time$participant_code)) + test2 <- !any(otree2$info[["deleted_cases"]][["codes"]] %in% + unique(otree2$Time$participant__code)) + testthat::expect_true(test1) + testthat::expect_true(test2) + + # Chat differently + test5a <- otree2$info$deleted_cases$codes %in% + otree1$Chats$participant_code # Before + test5b <- otree2$info$deleted_cases$codes %in% + otree2$Chats$participant_code # After + testthat::expect_equal(test5a, test5b) + + # Test for consistency of the info output + test1 <- setequal(otree2$info$deleted_cases$unique$participant.code, + otree2$info$deleted_cases$full$participant.code) + test2 <- setequal(otree2$info$deleted_cases$unique$participant.code, + otree2$info$deleted_cases$codes) + test3 <- length(otree2$info$deleted_cases$codes) == + otree2$info$deleted_cases$count + test4 <- length(otree2$info$deleted_cases$codes) == + nrow(otree2$info$deleted_cases$unique) + testthat::expect_true(all(c(test1, test2, test3, test4))) +}) + +testthat::test_that("Delete dropouts - final_apps & pagenames", { + # Prepare data + otree2 <- otree_5_4_0 + + # Before + before_aaw <- nrow(otree2$all_apps_wide) + before_dictator <- nrow(otree2$dictator) + before_survey <- nrow(otree2$survey) + before_time <- nrow(otree2$Time) + before_chat <- nrow(otree2$Chat) + + # Run function + otree2 <- delete_dropouts(otree2, + final_apps = "survey", + final_pages = "Demographics") + + # After + after_aaw <- nrow(otree2$all_apps_wide) + after_dictator <- nrow(otree2$dictator) + after_survey <- nrow(otree2$survey) + after_time <- nrow(otree2$Time) + after_chat <- nrow(otree2$Chat) + + # Diff + diff_aaw <- before_aaw - after_aaw + diff_dictator <- before_dictator - after_dictator + diff_survey <- before_survey - after_survey + diff_time <- before_time - after_time + diff_chat <- before_chat - after_chat + + # Test difference + testthat::expect_gt(diff_aaw, 0) + testthat::expect_gt(diff_dictator, 0) + testthat::expect_gt(diff_survey, 0) + testthat::expect_gt(diff_time, 0) + testthat::expect_equal(diff_chat, 0) + + # Test if not all cases were deleted! + testthat::expect_gt(after_aaw, 0) + testthat::expect_gt(after_dictator, 0) + testthat::expect_gt(after_survey, 0) + testthat::expect_gt(after_time, 0) + testthat::expect_gt(after_chat, 0) + + # Test if deleted people are really deleted (sample) + test1 <- + !(otree2$info$deleted_cases$codes %in% + otree2$all_apps_wide$participant.code) + test2 <- + !(otree2$info$deleted_cases$codes %in% + otree2$dictator$participant.code) + test3 <- + !(otree2$info$deleted_cases$codes %in% + otree2$survey$participant.code) + test4 <- + !(otree2$info$deleted_cases$codes %in% + otree2$Time$participant_code) + + testthat::expect_true(all(c(test1, test2))) + testthat::expect_true(all(c(test3, test4))) + + # Chat differently + test5a <- otree2$info$deleted_cases$codes %in% + otree2$Chats$participant_code # Before + test5b <- otree2$info$deleted_cases$codes %in% + otree2$Chats$participant_code # After + + testthat::expect_equal(test5a, test5b) + + # Test for consistency of the info output + test1 <- setequal(otree2$info$deleted_cases$unique$participant.code, + otree2$info$deleted_cases$full$participant.code) + test2 <- setequal(otree2$info$deleted_cases$unique$participant.code, + otree2$info$deleted_cases$codes) + test3 <- length(otree2$info$deleted_cases$codes) == + otree2$info$deleted_cases$count + test4 <- length(otree2$info$deleted_cases$codes) == + nrow(otree2$info$deleted_cases$unique) + testthat::expect_true(all(c(test1, test2, test3, test4))) +}) + +testthat::test_that("Delete dropouts - only pagenames", { + # Prepare data + otree1 <- otree_5_4_0 + + # Before + before_aaw <- nrow(otree1$all_apps_wide) + before_dictator <- nrow(otree1$dictator) + before_survey <- nrow(otree1$survey) + before_time <- nrow(otree1$Time) + before_chat <- nrow(otree1$Chat) + + # Run function + otree2 <- delete_dropouts(otree1, + final_pages = "Demographics") + + # After + after_aaw <- nrow(otree2$all_apps_wide) + after_dictator <- nrow(otree2$dictator) + after_survey <- nrow(otree2$survey) + after_time <- nrow(otree2$Time) + after_chat <- nrow(otree2$Chat) + + # Diff + diff_aaw <- before_aaw - after_aaw + diff_dictator <- before_dictator - after_dictator + diff_survey <- before_survey - after_survey + diff_time <- before_time - after_time + diff_chat <- before_chat - after_chat + + # Test difference + testthat::expect_gt(diff_aaw, 0) + testthat::expect_gt(diff_dictator, 0) + testthat::expect_gt(diff_survey, 0) + testthat::expect_gt(diff_time, 0) + testthat::expect_equal(diff_chat, 0) + + # Test if not all cases were deleted! + testthat::expect_gt(after_aaw, 0) + testthat::expect_gt(after_dictator, 0) + testthat::expect_gt(after_survey, 0) + testthat::expect_gt(after_time, 0) + testthat::expect_gt(after_chat, 0) + + # Test if deleted people are really deleted + test1 <- + !(otree2$info$deleted_cases$codes %in% + otree2$all_apps_wide$participant.code) + test2 <- + !(otree2$info$deleted_cases$codes %in% + otree2$dictator$participant.code) + test3 <- + !(otree2$info$deleted_cases$codes %in% + otree2$survey$participant.code) + test4 <- + !(otree2$info$deleted_cases$codes %in% + otree2$Time$participant_code) + + testthat::expect_true(all(c(test1, test2))) + testthat::expect_true(all(c(test3, test4))) + # Chat differently + test5a <- otree2$info$deleted_cases$codes %in% + otree1$Chats$participant_code # Before + test5b <- otree2$info$deleted_cases$codes %in% + otree2$Chats$participant_code # After + + testthat::expect_equal(test5a, test5b) + + # Test for consistency of the info output + test1 <- setequal(otree2$info$deleted_cases$unique$participant.code, + otree2$info$deleted_cases$full$participant.code) + test2 <- setequal(otree2$info$deleted_cases$unique$participant.code, + otree2$info$deleted_cases$codes) + test3 <- length(otree2$info$deleted_cases$codes) == + otree2$info$deleted_cases$count + test4 <- length(otree2$info$deleted_cases$codes) == + nrow(otree2$info$deleted_cases$unique) + testthat::expect_true(all(c(test1, test2, test3, test4))) +}) + +testthat::test_that("Delete dropouts 2 - inconsistent yes", { + # Prepare data (example with inconsistent end pages) + otree1 <- otree_5_4_0 + + person <- otree1$all_apps_wide$participant.code[ + otree1$all_apps_wide$participant._current_app_name == "survey"][1] + + otree1$all_apps_wide$participant._current_app_name[ + otree1$all_apps_wide$participant._current_app_name == "survey"][1] <- + "othername" + + # Before + before_aaw <- nrow(otree1$all_apps_wide) + before_dictator <- nrow(otree1$dictator) + before_start <- nrow(otree1$start) + before_survey <- nrow(otree1$survey) + before_time <- nrow(otree1$Time) + before_chat <- nrow(otree1$Chats) + + # Run function + otree2 <- delete_dropouts(otree1, + final_apps = "survey", + inconsistent = "yes") + + # After + after_aaw <- nrow(otree2$all_apps_wide) + after_dictator <- nrow(otree2$dictator) + after_survey <- nrow(otree2$survey) + after_time <- nrow(otree2$Time) + after_chat <- nrow(otree2$Chat) + + # Diff + diff_aaw <- before_aaw - after_aaw + diff_dictator <- before_dictator - after_dictator + diff_survey <- before_survey - after_survey + diff_time <- before_time - after_time + diff_chat <- before_chat - after_chat + + # Test difference + testthat::expect_gt(diff_dictator, 0) + testthat::expect_gt(diff_aaw, 0) + testthat::expect_gt(diff_time, 0) + testthat::expect_gt(diff_survey, 0) + testthat::expect_equal(diff_chat, 0) + + # Test if not all cases were deleted! + testthat::expect_gt(after_aaw, 0) + testthat::expect_gt(after_dictator, 0) + testthat::expect_gt(after_survey, 0) + testthat::expect_gt(after_time, 0) + testthat::expect_gt(after_chat, 0) + + # Test if deleted people are really deleted + test1 <- + !(otree2$info$deleted_cases$codes %in% + otree2$all_apps_wide$participant.code) + test2 <- + !(otree2$info$deleted_cases$codes %in% + otree2$dictator$participant.code) + test3 <- + !(otree2$info$deleted_cases$codes %in% + otree2$survey$participant.code) + test4 <- + !(otree2$info$deleted_cases$codes %in% + otree2$Time$participant_code) + test5a <- otree1$Chats$participant_code %in% + otree2$info$deleted_cases$codes # Chat differently: Before + test5b <- otree2$Chats$participant_code %in% + otree2$info$deleted_cases$codes # Chat differently: After + + testthat::expect_true(all(c(test1, test2))) + testthat::expect_true(all(c(test3, test4))) + testthat::expect_equal(test5a, test5b) + + # Test - check if person gets deleted anyways (version 2) + test3 <- person %in% otree2$info[["deleted_cases"]][["codes"]] + test4 <- !(person %in% otree2$all_apps_wide$participant.code) + test5 <- !(person %in% otree2$dictator$participant.code) + test6 <- !(person %in% otree2$Time$participant.code) + test7 <- !(person %in% otree2$start$participant.code) + test8 <- !(person %in% otree2$survey$participant.code) + testthat::expect_true(all(c(test1, test2, test3, test4, test5, test6, + test7, test8))) + + # Test for consistency of the info output + test1 <- setequal(otree2$info$deleted_cases$unique$participant.code, + otree2$info$deleted_cases$full$participant.code) + test2 <- setequal(otree2$info$deleted_cases$unique$participant.code, + otree2$info$deleted_cases$codes) + test3 <- length(otree2$info$deleted_cases$codes) == + otree2$info$deleted_cases$count + test4 <- length(otree2$info$deleted_cases$codes) == + nrow(otree2$info$deleted_cases$unique) + testthat::expect_true(all(c(test1, test2, test3, test4))) +}) + +testthat::test_that("Delete dropouts 2 - inconsistent no", { + # Prepare data (example with inconsistent end pages) + otree2 <- otree_5_4_0 + otree2$all_apps_wide$participant._current_app_name[ + otree2$all_apps_wide$participant._current_app_name == "survey"][1] <- + "othername" + before <- nrow(otree2$all_apps_wide) + + # Run function and test + testthat::expect_error(delete_dropouts(otree2, + final_apps = "survey", + inconsistent = "no"), + "The user requested termination") +}) + +testthat::test_that("Delete dropouts 2 - inconsistent check", { + # Prepare data (example with inconsistent end pages) + otree1 <- otree_5_4_0 + + otree1$all_apps_wide$participant._current_app_name[ + otree1$all_apps_wide$participant._current_app_name == "survey"][1] <- + "othername" + + # Before + before_aaw <- nrow(otree1$all_apps_wide) + before_dictator <- nrow(otree1$dictator) + before_survey <- nrow(otree1$survey) + before_time <- nrow(otree1$Time) + before_chat <- nrow(otree1$Chat) + + # Run function and capture user-interaction + ans <- paste(c("yes")) + my_file <- textConnection(ans) + options(mypkg.connection = my_file) + + output <- capture.output( + otree2 <- delete_dropouts(otree1, + final_apps = "survey")) + + # Test if the output from the cat() function is shown + cat_output_displayed <- + any(grepl("At least one participant in the dropout list", output)) + testthat::expect_true(cat_output_displayed) + + # Reset the mypkg.connection option to stdin() and close the text connection + options(mypkg.connection = stdin()) + close(my_file) + + # Test + # After + after_aaw <- nrow(otree2$all_apps_wide) + after_dictator <- nrow(otree2$dictator) + after_survey <- nrow(otree2$survey) + after_time <- nrow(otree2$Time) + after_chat <- nrow(otree2$Chat) + + # Diff + diff_aaw <- before_aaw - after_aaw + diff_dictator <- before_dictator - after_dictator + diff_survey <- before_survey - after_survey + diff_time <- before_time - after_time + diff_chat <- before_chat - after_chat + + # Test difference + testthat::expect_gt(diff_aaw, 0) + testthat::expect_gt(diff_dictator, 0) + testthat::expect_gt(diff_survey, 0) + testthat::expect_gt(diff_time, 0) + testthat::expect_equal(diff_chat, 0) # Equal zero!!! + + # Test if not all cases were deleted! + testthat::expect_gt(after_aaw, 0) + testthat::expect_gt(after_dictator, 0) + testthat::expect_gt(after_survey, 0) + testthat::expect_gt(after_time, 0) + testthat::expect_gt(after_chat, 0) + + # Test if deleted people are really deleted + test1 <- + !(otree2$info$deleted_cases$codes %in% + otree2$all_apps_wide$participant.code) + test2 <- + !(otree2$info$deleted_cases$codes %in% + otree2$dictator$participant.code) + test3 <- + !(otree2$info$deleted_cases$codes %in% + otree2$survey$participant.code) + test4 <- + !(otree2$info$deleted_cases$codes %in% + otree2$Time$participant_code) + test5a <- otree1$Chats$participant_code %in% + otree2$info$deleted_cases$codes # Chat differently: Before + test5b <- otree2$Chats$participant_code %in% + otree2$info$deleted_cases$codes # Chat differently: After + + testthat::expect_true(all(c(test1, test2))) + testthat::expect_true(all(c(test3, test4))) + testthat::expect_equal(test5a, test5b) + + # Test for consistency of the info output + test1 <- setequal(otree2$info$deleted_cases$unique$participant.code, + otree2$info$deleted_cases$full$participant.code) + test2 <- setequal(otree2$info$deleted_cases$unique$participant.code, + otree2$info$deleted_cases$codes) + test3 <- length(otree2$info$deleted_cases$codes) == + otree2$info$deleted_cases$count + test4 <- length(otree2$info$deleted_cases$codes) == + nrow(otree2$info$deleted_cases$unique) + testthat::expect_true(all(c(test1, test2, test3, test4))) +}) + +testthat::test_that("Delete dropouts (e) - specify final_apps or pages", { + # Prepare data + otree2 <- otree_5_4_0 + + # Run function and test + expect_error(delete_dropouts(otree2), + "Please specify final_apps or final_pages") +}) + +testthat::test_that("Delete dropouts (e) - saved vars no aaw", { + # Prepare data + otree2 <- otree_5_4_0 + otree2$all_apps_wide <- NULL + + # Run function and test + testthat::expect_error( + delete_dropouts(otree2, + final_apps = "survey", + saved_vars = "dictator.1.group.id_in_subsession"), + "The argument \"saved_vars\" only works when") +}) + +testthat::test_that("Delete dropouts (e) - saved vars 2 ", { + # Prepare data + otree2 <- otree_5_4_0 + + # Run function and test + testthat::expect_error(delete_dropouts(otree2, + final_apps = "survey", + saved_vars = "notthere"), + "not in all_apps_wide") +}) + +testthat::test_that("Delete dropouts (e) - no all apps wide", { + # Prepare data + otree1 <- otree_5_4_0 + otree1$all_apps_wide <- NULL + + # Before + before_dictator <- nrow(otree1$dictator) + before_survey <- nrow(otree1$survey) + before_time <- nrow(otree1$Time) + before_chat <- nrow(otree1$Chat) + + # Run function + testthat::expect_warning( + otree2 <- delete_dropouts(otree1, + final_pages = "Demographics"), "No") + + # Test + # After + after_dictator <- nrow(otree2$dictator) + after_survey <- nrow(otree2$survey) + after_time <- nrow(otree2$Time) + after_chat <- nrow(otree2$Chat) + + # Diff + diff_dictator <- before_dictator - after_dictator + diff_survey <- before_survey - after_survey + diff_time <- before_time - after_time + diff_chat <- before_chat - after_chat + + # Test difference + testthat::expect_gt(diff_dictator, 0) + testthat::expect_gt(diff_survey, 0) + testthat::expect_gt(diff_time, 0) + testthat::expect_equal(diff_chat, 0) # Equal zero!!! + + # Test if not all cases were deleted! + testthat::expect_gt(after_dictator, 0) + testthat::expect_gt(after_survey, 0) + testthat::expect_gt(after_time, 0) + testthat::expect_gt(after_chat, 0) + + # Test if deleted people are really deleted + test1 <- + !(otree2$info$deleted_cases$codes %in% + otree2$all_apps_wide$participant.code) + test2 <- + !(otree2$info$deleted_cases$codes %in% + otree2$dictator$participant.code) + test3 <- + !(otree2$info$deleted_cases$codes %in% + otree2$survey$participant.code) + test4 <- + !(otree2$info$deleted_cases$codes %in% + otree2$Time$participant_code) + + testthat::expect_true(all(c(test1, test2))) + testthat::expect_true(all(c(test3, test4))) + # Chat differently + test5a <- otree2$info$deleted_cases$codes %in% + otree1$Chats$participant_code # Before + test5b <- otree2$info$deleted_cases$codes %in% + otree2$Chats$participant_code # After + + testthat::expect_equal(test5a, test5b) +}) + +print("---- delete_sessions -----") + +# Combined deletion test #### +testthat::test_that("several deletions - version 1", { + otree2 <- otree_5_4_0 + + # Delete cases + person <- otree2$all_apps_wide$participant.code[c(1, 2, 3, 4)] + otree2 <- delete_cases(otree2, person, + reason = "Upon request") + + # Delete dropouts + otree2 <- delete_dropouts(otree2, + final_apps = "survey") + + # Session delete + session <- as.data.frame(table(otree2$all_apps_wide$session.code)) + session <- session[session$Freq >= 2, 1] + otree2 <- delete_sessions(otree2, + scodes = session, + reason = "Only tests") + + # Test + test0 <- !("" %in% otree2$info$deleted_cases$unique$reason) + test1 <- "ENC" %in% otree2$info$deleted_cases$unique$reason + test2 <- "Only tests" %in% otree2$info$deleted_cases$unique$reason + test3 <- "Upon request" %in% otree2$info$deleted_cases$unique$reason + testthat::expect_true(all(c(test0, test1, test2, test3))) + + # Test for consistency of the info output + test1 <- setequal(otree2$info$deleted_cases$unique$participant.code, + otree2$info$deleted_cases$full$participant.code) + + test2 <- setequal(otree2$info$deleted_cases$unique$participant.code, + otree2$info$deleted_cases$codes) + test3 <- length(otree2$info$deleted_cases$codes) == + otree2$info$deleted_cases$count + test4 <- length(otree2$info$deleted_cases$codes) == + nrow(otree2$info$deleted_cases$unique) + testthat::expect_true(all(c(test1, test2, test3, test4))) +}) + +testthat::test_that("several deletions - version 2", { + # Prepare data + otree2 <- otree_5_4_0 + unique(otree2$all_apps_wide$participant.code) + + # Delete dropouts + otree2 <- delete_dropouts(otree2, + final_apps = "survey") + + # Delete cases + person <- otree2$all_apps_wide$participant.code[1] + otree2 <- delete_cases(otree2, person, + reason = "Upon request") + + # Session delete + otree2$all_apps_wide$session.code[1] + otree2 <- delete_sessions(otree2, + scodes = otree2$all_apps_wide$session.code[1], + reason = "Only tests") + + # Test + test0 <- !("" %in% otree2$info$deleted_cases$unique$reason) + test1 <- "ENC" %in% otree2$info$deleted_cases$unique$reason + test2 <- "Only tests" %in% otree2$info$deleted_cases$unique$reason + test3 <- "Upon request" %in% otree2$info$deleted_cases$unique$reason + testthat::expect_true(all(c(test0, test1, test2, test3))) + + # Test for consistency of the info output + test1 <- setequal(otree2$info$deleted_cases$unique$participant.code, + otree2$info$deleted_cases$full$participant.code) + test2 <- setequal(otree2$info$deleted_cases$unique$participant.code, + otree2$info$deleted_cases$codes) + test3 <- length(otree2$info$deleted_cases$codes) == + otree2$info$deleted_cases$count + test4 <- length(otree2$info$deleted_cases$codes) == + nrow(otree2$info$deleted_cases$unique) + testthat::expect_true(all(c(test1, test2, test3, test4))) +}) + +testthat::test_that("several deletions - version 3", { + # Prepare data + otree2 <- otree_5_4_0 + + # Session delete + otree2 <- delete_sessions(otree2, + scodes = otree2$all_apps_wide$session.code[1], + reason = "Only tests") + + # Delete dropouts + otree2 <- delete_dropouts(otree2, + final_apps = "survey") + + # Delete cases + person <- otree2$all_apps_wide$participant.code[c(1, 2)] + otree2 <- delete_cases(otree2, person, + reason = "Upon request") + # Test + test0 <- !("" %in% otree2$info$deleted_cases$unique$reason) + test1 <- "ENC" %in% otree2$info$deleted_cases$unique$reason + test2 <- "Only tests" %in% otree2$info$deleted_cases$unique$reason + test3 <- "Upon request" %in% otree2$info$deleted_cases$unique$reason + testthat::expect_true(all(c(test0, test1, test2, test3))) + + # Test for consistency of the info output + test1 <- setequal(otree2$info$deleted_cases$unique$participant.code, + otree2$info$deleted_cases$full$participant.code) + + test2 <- setequal(otree2$info$deleted_cases$unique$participant.code, + otree2$info$deleted_cases$codes) + test3 <- length(otree2$info$deleted_cases$codes) == + otree2$info$deleted_cases$count + test4 <- length(otree2$info$deleted_cases$codes) == + nrow(otree2$info$deleted_cases$unique) + testthat::expect_true(all(c(test1, test2, test3, test4))) +}) + +# Make IDs #### +testthat::test_that("Make IDs - from_var, gmake = TRUE", { + # Prepare data + otree2 <- otree_5_4_0 + order_aaw_before <- otree2$all_apps_wide$participant.code + order_dictator_before <- otree2$dictator$participant.code + + # Run function + otree2 <- make_ids(otree2, + pmake = TRUE, + gmake = TRUE, + from_var = "dictator.1.group.id_in_subsession", + emptyrows = "yes") # ignore empty rows stop + # Test + # Test if order of DF entries did not change + order_aaw_after <- otree2$all_apps_wide$participant.code + order_dictator_after <- otree2$dictator$participant.code + + test1 <- all(order_aaw_before == order_aaw_after) + test2 <- all(order_dictator_before == order_dictator_after) + testthat::expect_true(all(c(test1, test2))) + + # Test if variables are there + test1 <- !is.null(otree2$dictator$group_id) + test2 <- !is.null(otree2$dictator$session_id) + testthat::expect_true(all(c(test1, test2))) + + # Test if all IDs are there + test1 <- all(seq_along(unique(otree2$all_apps_wide$participant.code)) %in% + otree2$all_apps_wide$participant_id) + test2 <- all(seq_along(unique(otree2$all_apps_wide$session.code)) %in% + otree2$all_apps_wide$session_id) + test3 <- all( + c(1:(length(otree2$dictator$group_id) / 3 / 2)) %in% + otree2$dictator$group_id) + + testthat::expect_true(all(c(test1, test2, test3))) + + # Test for increasing IDs + # Test if group_ids are increasing with session_id + otree2$dictator <- otree2$dictator[order(otree2$dictator$session_id, + otree2$dictator$group_id), ] + test1 <- all(diff(otree2$dictator$group_id) >= 0) + + # Test if participant_ids are increasing with group_ids + otree2$dictator <- otree2$dictator[order(otree2$dictator$group_id, + otree2$dictator$participant_id), ] + test2 <- all(diff(otree2$dictator$participant_id) >= 0) + testthat::expect_true(all(c(test1, test2))) +}) + +testthat::test_that("Make IDs - from_var, gmake = TRUE", { + # Prepare data + otree2 <- otree_5_4_0 + otree2$random_dataframe <- data.frame( + a = c(1, 2, 3), + b = c(4, 5, 6), + c = c(7, 8, 9)) + order_aaw_before <- otree2$all_apps_wide$participant.code + order_dictator_before <- otree2$dictator$participant.code + + # Run function + otree2 <- make_ids(otree2, + pmake = TRUE, + gmake = TRUE, + from_var = "dictator.1.group.id_in_subsession", + emptyrows = "yes") # ignore empty rows stop + + # Test + # Test if order of DF entries did not change + order_aaw_after <- otree2$all_apps_wide$participant.code + order_dictator_after <- otree2$dictator$participant.code + + test1 <- all(order_aaw_before == order_aaw_after) + test2 <- all(order_dictator_before == order_dictator_after) + testthat::expect_true(all(c(test1, test2))) + + # Test if variables are there + test1 <- !is.null(otree2$dictator$group_id) + test2 <- !is.null(otree2$dictator$session_id) + testthat::expect_true(all(c(test1, test2))) + + # Test if all IDs are there + test1 <- all(seq_along(unique(otree2$all_apps_wide$participant.code)) %in% + otree2$all_apps_wide$participant_id) + test2 <- all(seq_along(unique(otree2$all_apps_wide$session.code)) %in% + otree2$all_apps_wide$session_id) + test3 <- all( + c(1:(length(otree2$dictator$group_id) / 3 / 2)) %in% + otree2$dictator$group_id) + + testthat::expect_true(all(c(test1, test2, test3))) + + # Test for increasing IDs + # Test if group_ids are increasing with session_id + otree2$dictator <- otree2$dictator[order(otree2$dictator$session_id, + otree2$dictator$group_id), ] + test1 <- all(diff(otree2$dictator$group_id) >= 0) + + # Test if participant_ids are increasing with group_ids + otree2$dictator <- otree2$dictator[order(otree2$dictator$group_id, + otree2$dictator$participant_id), ] + test2 <- all(diff(otree2$dictator$participant_id) >= 0) + testthat::expect_true(all(c(test1, test2))) +}) + +testthat::test_that("Make IDs - two sessions na", { + # Prepare data + otree2 <- otree_5_4_0 + otree2$all_apps_wide$session.code[c(1, 2, 3)] <- NA + order_aaw_before <- otree2$all_apps_wide$participant.code + order_dictator_before <- otree2$dictator$participant.code + + # Run function + testthat::expect_warning( + otree2 <- make_ids(otree2, + pmake = TRUE, + gmake = TRUE, + from_var = "dictator.1.group.id_in_subsession", + emptyrows = "yes"), + "At least one of your session.codes in your from_app is NA") + + # Test + # Test if order of DF entries did not change + order_aaw_after <- otree2$all_apps_wide$participant.code + order_dictator_after <- otree2$dictator$participant.code + + test1 <- all(order_aaw_before == order_aaw_after) + test2 <- all(order_dictator_before == order_dictator_after) + testthat::expect_true(all(c(test1, test2))) + + # Test if variables are there + test1 <- !is.null(otree2$dictator$group_id) + test2 <- !is.null(otree2$dictator$session_id) + testthat::expect_true(all(c(test1, test2))) + + # Test if all IDs are there + test1 <- all(seq_along(unique(otree2$all_apps_wide$participant.code)) %in% + otree2$all_apps_wide$participant_id) + test2 <- all(seq_along(unique(otree2$all_apps_wide$session.code)) %in% + otree2$all_apps_wide$session_id) + test3 <- all( + c(1:(length(otree2$dictator$group_id) / 3 / 2)) %in% + otree2$dictator$group_id) + + testthat::expect_true(all(c(test1, test2, test3))) + + # Test for increasing IDs + # Test if group_ids are increasing with session_id + otree2$dictator <- otree2$dictator[order(otree2$dictator$session_id, + otree2$dictator$group_id), ] + test1 <- all(diff(otree2$dictator$group_id) >= 0) + + # Test if participant_ids are increasing with group_ids + otree2$dictator <- otree2$dictator[order(otree2$dictator$group_id, + otree2$dictator$participant_id), ] + test2 <- all(diff(otree2$dictator$participant_id) >= 0) + testthat::expect_true(all(c(test1, test2))) +}) + +testthat::test_that("Make IDs - from_var", { + # Prepare data + otree2 <- otree_5_4_0 + order_aaw_before <- otree2$all_apps_wide$participant.code + order_dictator_before <- otree2$dictator$participant.code + + # Run function + otree2 <- make_ids(otree2, + gmake = TRUE, + pmake = TRUE, + from_var = "dictator.1.group.id_in_subsession") + + # Test if order of DF entries did not change + order_aaw_after <- otree2$all_apps_wide$participant.code + order_dictator_after <- otree2$dictator$participant.code + + test1 <- all(order_aaw_before == order_aaw_after) + test2 <- all(order_dictator_before == order_dictator_after) + testthat::expect_true(all(c(test1, test2))) + + # Test if variables exist / don't exist + test1 <- !is.null(otree2$all_apps_wide$group_id) + test2 <- !is.null(otree2$all_apps_wide$session_id) + test3 <- !is.null(otree2$all_apps_wide$participant_id) + testthat::expect_true(all(c(test1, test2, test3))) + + # Test if all IDs are there + test1 <- all(seq_along(unique(otree2$all_apps_wide$participant.code)) %in% + otree2$all_apps_wide$participant_id) + test2 <- all(seq_along(unique(otree2$all_apps_wide$session.code)) %in% + otree2$all_apps_wide$session_id) + test3 <- all( + c(1:(length(otree2$dictator$group_id) / 3 / 2)) %in% + otree2$dictator$group_id) + testthat::expect_true(all(c(test1, test2, test3))) + + # Test for increasing Ids + # Test if group_ids are increasing with session_id + otree2$dictator <- otree2$dictator[order(otree2$dictator$session_id, + otree2$dictator$group_id), ] + test1 <- all(diff(otree2$dictator$group_id) >= 0) + + # Test if participant_ids are increasing with group_ids + otree2$dictator <- otree2$dictator[order(otree2$dictator$group_id, + otree2$dictator$participant_id), ] + test2 <- all(diff(otree2$dictator$participant_id) >= 0) + testthat::expect_true(all(c(test1, test2))) +}) + +testthat::test_that("Make IDs - from_var, other starts", { + # Prepare data + otree2 <- otree_5_4_0 + order_aaw_before <- otree2$all_apps_wide$participant.code + order_dictator_before <- otree2$dictator$participant.code + + # Run function + otree2 <- make_ids(otree2, + gmake = TRUE, + pmake = TRUE, + sstart = 3, + gstart = 4, + pstart = 8, + from_var = "dictator.1.group.id_in_subsession") + # Test + # Test if order of DF entries did not change + order_aaw_after <- otree2$all_apps_wide$participant.code + order_dictator_after <- otree2$dictator$participant.code + + test1 <- all(order_aaw_before == order_aaw_after) + test2 <- all(order_dictator_before == order_dictator_after) + testthat::expect_true(all(c(test1, test2))) + + # Test if variables exist / don't exist + test1 <- !is.null(otree2$all_apps_wide$group_id) + test2 <- !is.null(otree2$all_apps_wide$session_id) + test3 <- !is.null(otree2$all_apps_wide$participant_id) + testthat::expect_true(all(c(test1, test2, test3))) + + # Test for minimum values + test1 <- min(otree2$all_apps_wide$group_id) == 4 + test2 <- min(otree2$all_apps_wide$session_id) == 3 + test3 <- min(otree2$all_apps_wide$participant_id) == 8 + testthat::expect_true(all(c(test1, test2, test3))) + + # Test for increasing IDs + # Test if group_ids are increasing with session_id + otree2$dictator <- otree2$dictator[order(otree2$dictator$session_id, + otree2$dictator$group_id), ] + test1 <- all(diff(otree2$dictator$group_id) >= 0) + + # Test if participant_ids are increasing with group_ids + otree2$dictator <- otree2$dictator[order(otree2$dictator$group_id, + otree2$dictator$participant_id), ] + test2 <- all(diff(otree2$dictator$participant_id) >= 0) + testthat::expect_true(all(c(test1, test2))) +}) + +testthat::test_that("Make IDs - from_var, dictator.1.group.id_in_subsession", { + # Prepare data + otree2 <- otree_5_4_0 + order_aaw_before <- otree2$all_apps_wide$dictator.1.player.payoff + order_dictator_before <- otree2$dictator$player.payoff + + # Run function + testthat::expect_no_warning( + otree2 <- make_ids(otree2, + gmake = FALSE, # will be overwritten by code! + pmake = FALSE, + from_var = "dictator.1.group.id_in_subsession")) + + # Test if order of DF entries did not change + order_aaw_after <- otree2$all_apps_wide$dictator.1.player.payoff + order_dictator_after <- otree2$dictator$player.payoff + + test1 <- order_aaw_before == order_aaw_after + test2 <- order_dictator_before == order_dictator_after + testthat::expect_true(all(c(test1, test2))) + + # Test if variables exist / don't exist + test1 <- !is.null(otree2$all_apps_wide$group_id) + test2 <- !is.null(otree2$all_apps_wide$session_id) + test3 <- is.null(otree2$all_apps_wide$participant_id) + testthat::expect_true(all(c(test1, test2, test3))) + + # Test if all IDs are there + # No participants! + test2 <- all(seq_along(unique(otree2$all_apps_wide$session.code)) %in% + otree2$all_apps_wide$session_id) + test3 <- all( + c(1:(length(otree2$dictator$group_id) / 3 / 2)) %in% + otree2$dictator$group_id) + testthat::expect_true(all(c(test2, test3))) + + # Test for increasing IDs + # Test if group_ids are increasing with session_id + otree2$dictator <- otree2$dictator[order(otree2$dictator$session_id, + otree2$dictator$group_id), ] + test1 <- all(diff(otree2$dictator$group_id) >= 0) + testthat::expect_true(test1) +}) + +testthat::test_that("Make IDs - all the same", { + # Prepare data (make group IDs all the same) + otree2 <- otree_5_4_0 + + otree2$all_apps_wide$start.1.group.id_in_subsession <- + otree2$all_apps_wide$dictator.1.group.id_in_subsession + + otree2$all_apps_wide$survey.1.group.id_in_subsession <- + otree2$all_apps_wide$dictator.1.group.id_in_subsession + + otree2$all_apps_wide$chatapp.1.group.id_in_subsession <- + otree2$all_apps_wide$dictator.1.group.id_in_subsession + + order_aaw_before <- otree2$all_apps_wide$participant.code + order_dictator_before <- otree2$dictator$participant.code + + # Run function + otree2 <- make_ids(otree2, gmake = TRUE) + + # Test + max_part <- length(otree2$all_apps_wide$participant.code) + max_group <- length( + unique(paste(otree2$all_apps_wide$session.code, + otree2$all_apps_wide$dictator.1.group.id_in_subsession))) + + max_session <- length(unique(otree2$all_apps_wide$session.code)) + + testthat::expect_equal( + max(otree2$all_apps_wide$participant_id, na.rm = TRUE), max_part) + testthat::expect_equal( + max(otree2$all_apps_wide$group_id, na.rm = TRUE), max_group) + testthat::expect_equal( + max(otree2$all_apps_wide$session_id, na.rm = TRUE), max_session) + + # Test if order of DF entries did not change + order_aaw_after <- otree2$all_apps_wide$participant.code + order_dictator_after <- otree2$dictator$participant.code + + test1 <- all(order_aaw_before == order_aaw_after) + test2 <- all(order_dictator_before == order_dictator_after) + testthat::expect_true(all(c(test1, test2))) + + # Test if all IDs are there + test1 <- all(c(1:max_part) %in% + otree2$all_apps_wide$participant_id) + test2 <- all(c(1:max_session) %in% + otree2$all_apps_wide$session_id) + test3 <- all( + c(1:max_group) %in% + otree2$dictator$group_id) + testthat::expect_true(all(c(test1, test2, test3))) +}) + +testthat::test_that("Make IDs - no time start", { + # Prepare data + otree2 <- otree_5_4_0 + otree2$all_apps_wide$participant.time_started[ + seq_len(nrow(otree2$all_apps_wide))] <- NA + order_aaw_before <- otree2$all_apps_wide$dictator.1.player.payoff + order_dictator_before <- otree2$dictator$player.payoff + + # Run function + otree2 <- make_ids(otree2) + + # Test if order of DF entries did not change + order_aaw_after <- otree2$all_apps_wide$dictator.1.player.payoff + order_dictator_after <- otree2$dictator$player.payoff + + test1 <- order_aaw_before == order_aaw_after + test2 <- order_dictator_before == order_dictator_after + testthat::expect_true(all(c(test1, test2))) + + # Test if variables exist / don't exist + test1 <- !is.null(otree2$all_apps_wide$participant_id) + test2 <- is.null(otree2$dictator$group_id) + test3 <- !is.null(otree2$survey$participant_id) + test4 <- is.null(otree2$survey$group_id) + test5 <- !is.null(otree2$survey$session_id) + + testthat::expect_true(all(c(test1, test2, test3, test4, test5))) + + # Test - check if no two session codes have the same session id + id_code_pairs <- unique(paste( + otree2$all_apps_wide$session_id, + otree2$all_apps_wide$session.code)) + + numbers <- as.integer(sub("^([0-9]+).*", "\\1", id_code_pairs)) + strings <- sub("^[0-9]+ (.*)", "\\1", id_code_pairs) + test1 <- !any(duplicated(numbers)) + test2 <- !any(duplicated(strings)) + + testthat::expect_true(test1) + testthat::expect_true(test2) + + # Test - check if no two participant codes have the same participant id + id_code_pairs <- unique(paste( + otree2$all_apps_wide$participant_id, + otree2$all_apps_wide$participant.code)) + + numbers <- as.integer(sub("^([0-9]+).*", "\\1", id_code_pairs)) + strings <- sub("^[0-9]+ (.*)", "\\1", id_code_pairs) + test1 <- !any(duplicated(numbers)) + test2 <- !any(duplicated(strings)) + testthat::expect_true(all(c(test1, test2))) + + # Test if variables exist / don't exist + test1 <- all(seq_along(unique(otree2$all_apps_wide$participant.code)) %in% + otree2$all_apps_wide$participant_id) + test2 <- all(seq_along(unique(otree2$all_apps_wide$session.code)) %in% + otree2$all_apps_wide$session_id) + test3 <- is.null(otree2$dictator$group_id) + test4 <- is.null(otree2$all_apps_wide$group_id) + testthat::expect_true(all(c(test1, test2, test3, test4))) + + # Test for increasing IDs + # Test if participant_ids are increasing with session_ids + otree2$dictator <- otree2$dictator[order(otree2$dictator$session_id, + otree2$dictator$participant_id), ] + test2 <- all(diff(otree2$dictator$participant_id) >= 0) + testthat::expect_true(all(c(test1, test2))) +}) + +testthat::test_that("Make IDs - from_var - first constant", { + # Prepare data (make all group variables to 1) + otree2 <- otree_5_4_0 + order_aaw_before <- otree2$all_apps_wide$participant.code + order_dictator_before <- otree2$dictator$participant.code + + otree2$all_apps_wide$dictator.1.group.id_in_subsession <- + otree2$all_apps_wide$survey.1.group.id_in_subsession + + otree2$all_apps_wide$dictator.2.group.id_in_subsession <- + otree2$all_apps_wide$survey.1.group.id_in_subsession + + otree2$all_apps_wide$dictator.3.group.id_in_subsession <- + otree2$all_apps_wide$survey.1.group.id_in_subsession + + otree2$all_apps_wide$chatapp.1.group.id_in_subsession <- + otree2$all_apps_wide$survey.1.group.id_in_subsession + + # Run function + testthat::expect_warning( + + otree2 <- make_ids(otree2, + gmake = TRUE, + icw = TRUE), + "are constant. Group IDs now correspond to session IDs") + + # Test + test1 <- all(otree2$all_apps_wide$group_id == otree2$all_apps_wide$session_id) + testthat::expect_true(test1) + + # Test if order of DF entries did not change + order_aaw_after <- otree2$all_apps_wide$participant.code + order_dictator_after <- otree2$dictator$participant.code + + test1 <- all(order_aaw_before == order_aaw_after) + test2 <- all(order_dictator_before == order_dictator_after) + testthat::expect_true(all(c(test1, test2))) + + # Test - check if no two session codes have the same session id + id_code_pairs <- unique(paste( + otree2$all_apps_wide$session_id, + otree2$all_apps_wide$session.code)) + + numbers <- as.integer(sub("^([0-9]+).*", "\\1", id_code_pairs)) + strings <- sub("^[0-9]+ (.*)", "\\1", id_code_pairs) + test1 <- !any(duplicated(numbers)) + test2 <- !any(duplicated(strings)) + testthat::expect_true(all(c(test1, test2))) + + # Test - check if no two participant codes have the same participant id + id_code_pairs <- unique(paste( + otree2$all_apps_wide$participant_id, + otree2$all_apps_wide$participant.code)) + + numbers <- as.integer(sub("^([0-9]+).*", "\\1", id_code_pairs)) + strings <- sub("^[0-9]+ (.*)", "\\1", id_code_pairs) + test1 <- !any(duplicated(numbers)) + test2 <- !any(duplicated(strings)) + testthat::expect_true(all(c(test1, test2))) + + # Test if all IDs are there + test1 <- all(seq_along(unique(otree2$all_apps_wide$participant.code)) %in% + otree2$all_apps_wide$participant_id) + test2 <- all(seq_along(unique(otree2$all_apps_wide$session.code)) %in% + otree2$all_apps_wide$session_id) + test3 <- otree2$all_apps_wide$session_id == otree2$all_apps_wide$group_id + testthat::expect_true(all(c(test1, test2, test3))) +}) + +testthat::test_that("Make IDs - from_app", { + # Prepare data + otree2 <- otree_5_4_0 + order_aaw_before <- otree2$all_apps_wide$participant.code + order_dictator_before <- otree2$dictator$participant.code + + # Run function + otree2 <- make_ids(otree2, gmake = TRUE, from_app = "dictator") + + # Test if order of DF entries did not change + order_aaw_after <- otree2$all_apps_wide$participant.code + order_dictator_after <- otree2$dictator$participant.code + + test1 <- all(order_aaw_before == order_aaw_after) + test2 <- all(order_dictator_before == order_dictator_after) + testthat::expect_true(all(c(test1, test2))) + + # Test + test_participant <- + unique(otree2$all_apps_wide$participant.code[ + order(otree2$all_apps_wide$participant.code)]) + + testthat::expect_equal(length(otree2$all_apps_wide$participant_id), + length(test_participant)) + + # Test if variables exist / don't exist + test1 <- !is.null(otree2$dictator$group_id) + test2 <- !is.null(otree2$dictator$session_id) + testthat::expect_equal(test1, TRUE) + testthat::expect_equal(test2, TRUE) + + # Test if all IDs are there + test1 <- all(seq_along(unique(otree2$all_apps_wide$participant.code)) %in% + otree2$all_apps_wide$participant_id) + test2 <- all(seq_along(unique(otree2$all_apps_wide$session.code)) %in% + otree2$all_apps_wide$session_id) + test3 <- all( + c(1:(length(otree2$dictator$group_id) / 3 / 2)) %in% + otree2$dictator$group_id) + testthat::expect_true(all(c(test1, test2, test3))) +}) + +testthat::test_that("Make IDs - from_app, random_df", { + # Prepare data + otree2 <- otree_5_4_0 + otree2$random_dataframe <- data.frame( + a = c(1, 2, 3), + b = c(4, 5, 6), + c = c(7, 8, 9)) + + # Run function and test + testthat::expect_error( + otree2 <- make_ids(otree2, gmake = TRUE, + from_app = "random_dataframe"), + "Your from_app is not a normal oTree") +}) + +testthat::test_that("Make IDs - one participant not in from_app", { + # Prepare data + otree2 <- otree_5_4_0 + otree2 <- delete_duplicate(otree2) + delsomedictators <- unique(otree2$dictator$participant.code)[c(1)] + otree2$dictator <- otree2$dictator[ + !(otree2$dictator$participant.code %in% delsomedictators), ] + order_aaw_before <- otree2$all_apps_wide$participant.code + order_dictator_before <- otree2$dictator$participant.code + + # Run function + testthat::expect_warning( + otree2 <- make_ids(otree2, gmake = TRUE, from_app = "dictator"), + "all_apps_wide.*chatapp.*start.*survey.*Time.*has more participants than") + + # Test + # Test if order of DF entries did not change + order_aaw_after <- otree2$all_apps_wide$participant.code + order_dictator_after <- otree2$dictator$participant.code + + test1 <- all(order_aaw_before == order_aaw_after) + test2 <- all(order_dictator_before == order_dictator_after) + testthat::expect_true(all(c(test1, test2))) + + # Test + test_participant <- + unique(otree2$all_apps_wide$participant.code[ + order(otree2$all_apps_wide$participant.code)]) + + testthat::expect_equal(length(otree2$all_apps_wide$participant_id), + length(test_participant)) + + # Test if variables exist / don't exist + test1 <- !is.null(otree2$dictator$group_id) + test2 <- !is.null(otree2$dictator$session_id) + testthat::expect_equal(test1, TRUE) + testthat::expect_equal(test2, TRUE) + + # Test if all IDs are there + test1 <- all(c(1:(length(unique(otree2$all_apps_wide$participant.code)) - 1)) + %in% otree2$all_apps_wide$participant_id) + test2 <- all(seq_along(unique(otree2$all_apps_wide$session.code)) %in% + otree2$all_apps_wide$session_id) + test3 <- all( + c(1:(length(otree2$dictator$group_id) / 3 / 2)) %in% + otree2$dictator$group_id) + testthat::expect_true(all(c(test1, test2, test3))) +}) + +testthat::test_that("Make IDs - from_var constant", { + # Prepare data + otree2 <- otree_5_4_0 + order_aaw_before <- otree2$all_apps_wide$participant.code + order_dictator_before <- otree2$dictator$participant.code + + # Run function + testthat::expect_warning( + otree2 <- make_ids(otree2, + gmake = TRUE, + from_app = "survey"), + "values are constant") + + # Test if order of DF entries did not change + order_aaw_after <- otree2$all_apps_wide$participant.code + order_dictator_after <- otree2$dictator$participant.code + + test1 <- all(order_aaw_before == order_aaw_after) + test2 <- all(order_dictator_before == order_dictator_after) + testthat::expect_true(all(c(test1, test2))) + + # Test + testthat::expect_equal(otree2$group_id, otree2$session_id) + + # Test if variables exist / don't exist + test1 <- !is.null(otree2$all_apps_wide$participant_id) + test2 <- !is.null(otree2$dictator$group_id) + test3 <- !is.null(otree2$survey$participant_id) + test4 <- !is.null(otree2$survey$group_id) + test5 <- !is.null(otree2$survey$session_id) + testthat::expect_true(all(c(test1, test2, test3, test4, test5))) + + # Test if all IDs are there + test1 <- all(seq_along(unique(otree2$all_apps_wide$participant.code)) %in% + otree2$all_apps_wide$participant_id) + test2 <- all(seq_along(unique(otree2$all_apps_wide$session.code)) %in% + otree2$all_apps_wide$session_id) + test3 <- all(otree2$all_apps_wide$session_id == otree2$all_apps_wide$group_id) + testthat::expect_true(all(c(test1, test2, test3))) + + # Test for increasing IDs + # Test if group_ids are increasing with session_id + otree2$dictator <- otree2$dictator[order(otree2$dictator$session_id, + otree2$dictator$group_id), ] + test1 <- all(diff(otree2$dictator$group_id) >= 0) + + # Test if participant_ids are increasing with group_ids + otree2$dictator <- otree2$dictator[order(otree2$dictator$group_id, + otree2$dictator$participant_id), ] + test2 <- all(diff(otree2$dictator$participant_id) >= 0) + testthat::expect_true(all(c(test1, test2))) +}) + +testthat::test_that("Make IDs - others more cases than from-app", { + # Info: Cases are then shown as NA + # Prepare data + otree2 <- otree_5_4_0 + otree2$dictator <- otree2$dictator[c(7:nrow(otree2$dictator)), ] + order_aaw_before <- otree2$all_apps_wide$participant.code + order_dictator_before <- otree2$dictator$participant.code + + # Run function + testthat::expect_warning( + otree2 <- make_ids(otree2, + gmake = TRUE, + from_app = "dictator"), + "has more participants than") + + # Test + # Test if order of DF entries did not change + order_aaw_after <- otree2$all_apps_wide$participant.code + order_dictator_after <- otree2$dictator$participant.code + + test1 <- all(order_aaw_before == order_aaw_after) + test2 <- all(order_dictator_before == order_dictator_after) + testthat::expect_true(all(c(test1, test2))) + + # Test + test_participant <- + unique(otree2$all_apps_wide$participant.code[ + order(otree2$all_apps_wide$participant.code)]) + + testthat::expect_equal(length(otree2$all_apps_wide$participant_id), + length(test_participant)) + + # Test if variables exist / don't exist + test1 <- !is.null(otree2$dictator$group_id) + test2 <- !is.null(otree2$dictator$session_id) + test3 <- !is.null(otree2$dictator$participant_id) + + # Test if NAs are there + test4 <- NA %in% otree2$all_apps_wide$participant_id + testthat::expect_true(all(c(test1, test2, test3, test4))) + + # Test if all IDs are there + # Bit more complicated here, because some IDs are NA + test1 <- all(c(1:(length(otree2$all_apps_wide$participant.code) - + sum(is.na(otree2$all_apps_wide$participant_id)))) %in% + otree2$all_apps_wide$participant_id) + test2 <- all(c(1:(length(unique(otree2$all_apps_wide$session.code)) - 1)) %in% + otree2$all_apps_wide$session_id) + test3 <- all( + c(1:(length(otree2$dictator$group_id) / 3 / 2)) %in% + otree2$dictator$group_id) + + testthat::expect_true(all(c(test1, test2, test3))) + + # Test for NAs + test1 <- NA %in% otree2$all_apps_wide$participant_id + test2 <- NA %in% otree2$all_apps_wide$group_id + test3 <- NA %in% otree2$all_apps_wide$session_id + testthat::expect_true(all(c(test1, test2, test3))) + + # Test for increasing IDs + # Test if group_ids are increasing with session_id + otree2$dictator <- otree2$dictator[order(otree2$dictator$session_id, + otree2$dictator$group_id), ] + test1 <- all(diff(otree2$dictator$group_id) >= 0) + + # Test if participant_ids are increasing with group_ids + otree2$dictator <- otree2$dictator[order(otree2$dictator$group_id, + otree2$dictator$participant_id), ] + test2 <- all(diff(otree2$dictator$participant_id) >= 0) + testthat::expect_true(all(c(test1, test2))) +}) + +testthat::test_that("Make IDs - from_app more cases than all apps wide", { + # Prepare data + otree2 <- otree_5_4_0 + delperson <- otree2$dictator$participant.code[1] + + otree2$all_apps_wide <- + otree2$all_apps_wide[otree2$all_apps_wide$participant.code != delperson, ] + order_aaw_before <- otree2$all_apps_wide$participant.code + order_dictator_before <- otree2$dictator$participant.code + + # Run function + otree2 <- make_ids(otree2, + gmake = TRUE, + from_app = "dictator") + + # Test + test_participant <- + unique(otree2$all_apps_wide$participant.code) + + testthat::expect_equal(length(otree2$all_apps_wide$participant_id), + length(test_participant)) + + # Test if order of DF entries did not change + order_aaw_after <- otree2$all_apps_wide$participant.code + order_dictator_after <- otree2$dictator$participant.code + + test1 <- all(order_aaw_before == order_aaw_after) + test2 <- all(order_dictator_before == order_dictator_after) + testthat::expect_true(all(c(test1, test2))) + + # Test if variables are there + test3 <- !is.null(otree2$dictator$group_id) + test4 <- !is.null(otree2$dictator$session_id) + test5 <- !is.null(otree2$dictator$participant_id) + testthat::expect_true(all(c(test3, test4, test5))) + + # Test if values are not there twice + test <- length(otree2$all_apps_wide$participant_id) == + length(unique(otree2$all_apps_wide$participant_id)) + testthat::expect_true(test) + + # Test if all IDs are there + test6 <- all(c(2:(length(otree2$all_apps_wide$participant.code))) %in% + otree2$all_apps_wide$participant_id) + test7 <- all(seq_along(unique(otree2$all_apps_wide$session.code)) %in% + otree2$all_apps_wide$session_id) + test8 <- all( + c(1:(length(otree2$dictator$group_id) / 3 / 2)) %in% + otree2$dictator$group_id) + + testthat::expect_true(test6) + testthat::expect_true(test7) + testthat::expect_true(test8) + + # Test for increasing IDs + # Test if group_ids are increasing with session_id + otree2$dictator <- otree2$dictator[order(otree2$dictator$session_id, + otree2$dictator$group_id), ] + test9 <- all(diff(otree2$dictator$group_id) >= 0) + + # Test if participant_ids are increasing with group_ids + otree2$dictator <- otree2$dictator[order(otree2$dictator$group_id, + otree2$dictator$participant_id), ] + test10 <- all(diff(otree2$dictator$participant_id) >= 0) + testthat::expect_true(all(c(test9, test10))) +}) + +testthat::test_that("Make IDs (w) - from_var constant", { + # Prepare data + otree2 <- otree_5_4_0 + order_aaw_before <- otree2$all_apps_wide$dictator.1.player.payoff + order_dictator_before <- otree2$dictator$player.payoff + + # Run function + testthat::expect_warning( + otree2 <- make_ids(otree2, + from_var = "survey.1.group.id_in_subsession"), + "The group variable values are constant") + + # Test if order of DF entries did not change + order_aaw_after <- otree2$all_apps_wide$dictator.1.player.payoff + order_dictator_after <- otree2$dictator$player.payoff + + test1 <- order_aaw_before == order_aaw_after + test2 <- order_dictator_before == order_dictator_after + testthat::expect_true(all(c(test1, test2))) + + # Test + testthat::expect_equal(otree2$all_apps_wide$group_id, + otree2$all_apps_wide$session_id) + + # Test if variables exist / don't exist + test0 <- !is.null(otree2$all_apps_wide$group_id) + test1 <- !is.null(otree2$all_apps_wide$participant_id) + testthat::expect_true(all(c(test0, test1))) + + # Test if all IDs are there + test1 <- all(seq_along(unique(otree2$all_apps_wide$participant.code)) %in% + otree2$all_apps_wide$participant_id) + test2 <- all(seq_along(unique(otree2$all_apps_wide$session.code)) %in% + otree2$all_apps_wide$session_id) + test3 <- all(seq_along(unique(otree2$all_apps_wide$session.code)) %in% + otree2$all_apps_wide$group_id) # Because group is constant + testthat::expect_true(all(c(test1, test2, test3))) + + # Test for increasing IDs + # Test if group_ids are increasing with session_id + otree2$dictator <- otree2$dictator[order(otree2$dictator$session_id, + otree2$dictator$group_id), ] + test1 <- all(diff(otree2$dictator$group_id) >= 0) + + # Test if participant_ids are increasing with group_ids + otree2$dictator <- otree2$dictator[order(otree2$dictator$group_id, + otree2$dictator$participant_id), ] + test2 <- all(diff(otree2$dictator$participant_id) >= 0) + testthat::expect_true(all(c(test1, test2))) +}) + +testthat::test_that("Make IDs (w) - constant group variable", { + # Prepare data + otree2 <- otree_5_4_0 + order_aaw_before <- otree2$all_apps_wide$dictator.1.player.payoff + order_dictator_before <- otree2$dictator$player.payoff + + # Run function + testthat::expect_warning( + otree2 <- make_ids(otree2, + gmake = TRUE, + from_app = "survey"), + "group variable values are constant") + + # Test if order of DF entries did not change + order_aaw_after <- otree2$all_apps_wide$dictator.1.player.payoff + order_dictator_after <- otree2$dictator$player.payoff + + test1 <- order_aaw_before == order_aaw_after + test2 <- order_dictator_before == order_dictator_after + testthat::expect_true(all(c(test1, test2))) + + # Test + test1 <- !is.null(otree2$all_apps_wide$participant_id) + test2 <- !is.null(otree2$dictator$group_id) + test3 <- !is.null(otree2$survey$participant_id) + test4 <- !is.null(otree2$survey$group_id) + test5 <- !is.null(otree2$survey$session_id) + test6 <- otree2$survey$group_id == otree2$survey$session_id + test7 <- otree2$all_apps_wide$group_id == otree2$all_apps_wide$session_id + + testthat::expect_true(all(c(test1, test2, test3, + test4, test5, test6, + test7))) + + # Test if all IDs are there + test1 <- all(seq_along(unique(otree2$all_apps_wide$participant.code)) %in% + otree2$all_apps_wide$participant_id) + test2 <- all(seq_along(unique(otree2$all_apps_wide$session.code)) %in% + otree2$all_apps_wide$session_id) + testthat::expect_true(test1) + testthat::expect_true(test2) + + # Test for increasing IDs + # Test if group_ids are increasing with session_id + otree2$dictator <- otree2$dictator[order(otree2$dictator$session_id, + otree2$dictator$group_id), ] + test1 <- all(diff(otree2$dictator$group_id) >= 0) + + # Test if participant_ids are increasing with group_ids + otree2$dictator <- otree2$dictator[order(otree2$dictator$group_id, + otree2$dictator$participant_id), ] + test2 <- all(diff(otree2$dictator$participant_id) >= 0) + testthat::expect_true(all(c(test1, test2))) +}) + +testthat::test_that("Make IDs (w) - from_var - no participant code variable", { + # Prepare data + otree2 <- otree_5_4_0 + otree2 <- delete_duplicate(otree2) + otree2$survey$participant.code <- NULL + order_aaw_before <- otree2$all_apps_wide$dictator.1.player.payoff + order_dictator_before <- otree2$dictator$player.payoff + + # Run function + testthat::expect_warning( + otree2 <- make_ids(otree2, + gmake = TRUE, + pmake = TRUE, + from_app = "dictator"), + "Participant code variable couldn't be found") + + # Test if order of DF entries did not change + order_aaw_after <- otree2$all_apps_wide$dictator.1.player.payoff + order_dictator_after <- otree2$dictator$player.payoff + + test1 <- order_aaw_before == order_aaw_after + test2 <- order_dictator_before == order_dictator_after + testthat::expect_true(all(c(test1, test2))) + + # Test + test1 <- !is.null(otree2$all_apps_wide$participant_id) + test2 <- !is.null(otree2$dictator$group_id) + test3 <- is.null(otree2$survey$participant_id) + test4 <- is.null(otree2$survey$group_id) + test5 <- is.null(otree2$survey$session_id) + + testthat::expect_true(all(c(test1, test2, test3, test4, test5))) + + # Test if all IDs are there + test1 <- all(seq_along(unique(otree2$all_apps_wide$participant.code)) + %in% otree2$all_apps_wide$participant_id) + test2 <- all(seq_along(unique(otree2$all_apps_wide$session.code)) %in% + otree2$all_apps_wide$session_id) + test3 <- all( + c(1:(length(otree2$dictator$group_id) / 3 / 2)) %in% + otree2$dictator$group_id) + + testthat::expect_true(all(c(test1, test2, test3))) + + # Test for increasing IDs + # Test if group_ids are increasing with session_id + otree2$dictator <- otree2$dictator[order(otree2$dictator$session_id, + otree2$dictator$group_id), ] + test1 <- all(diff(otree2$dictator$group_id) >= 0) + + # Test if participant_ids are increasing with group_ids + otree2$dictator <- otree2$dictator[order(otree2$dictator$group_id, + otree2$dictator$participant_id), ] + test2 <- all(diff(otree2$dictator$participant_id) >= 0) + testthat::expect_true(all(c(test1, test2))) +}) + +testthat::test_that("Make IDs (e) - emtpy rows - from app aaw", { + # If there are empty rows, an error occurs + # Prepare data + testthat::expect_warning( + otree2 <- import_otree( + del_empty = FALSE, + path = ".\\exp_data_5.4.0", + onlybots = FALSE, + csv = TRUE, + info = TRUE), "globally but also room-specific") + + testthat::expect_error( + otree2 <- make_ids(otree2, + pmake = TRUE, + gmake = TRUE, + from_var = "dictator.1.group.id_in_subsession", + emptyrows = "yes"), + "length of participant codes is not equal the length of unique participant") + +}) + +testthat::test_that("Make IDs (e) - emtpy rows - from app dictator", { + # If there are empty rows, an error occurs + # Prepare data + testthat::expect_warning( + otree2 <- import_otree( + del_empty = FALSE, + path = ".\\exp_data_5.4.0", + onlybots = FALSE, + csv = TRUE, + info = TRUE), + "globally but also room-specific") + + # Run function and test + testthat::expect_error( + otree2 <- make_ids(otree2, + pmake = TRUE, + gmake = TRUE, + from_app = "dictator", + emptyrows = "yes"), + "The length of participant codes is not equal the length of unique part") +}) + +testthat::test_that("Make IDs (e) - empty rows yes", { + # Prepare data + otree2 <- otree_new_empty + + ans <- paste(c("yes")) + my_file <- textConnection(ans) + options(mypkg.connection = my_file) + + # Capture the output of make_ids + output <- capture.output( + make_ids(otree2, + pmake = TRUE, + gmake = TRUE, + from_var = "dictator.1.group.id_in_subsession")) + + # Test if the output from the cat() function is shown + cat_output_displayed <- + any(grepl("Your from_app contains empty rows", output)) + + testthat::expect_true(cat_output_displayed) + + # Reset the mypkg.connection option to stdin() + # and close the text connection + options(mypkg.connection = stdin()) + close(my_file) +}) + +testthat::test_that("Make IDs (e) - empty rows no", { + # Prepare data + otree2 <- otree_new_empty + + ans <- paste(c("no")) + my_file <- textConnection(ans) + options(mypkg.connection = my_file) + + # Capture the output of make_ids + testthat::expect_error( + output <- capture.output( + make_ids(otree2, + pmake = TRUE, + gmake = TRUE, + from_var = "dictator.1.group.id_in_subsession")), + "You chose to stop this function") + + # Reset the mypkg.connection option to stdin() + # and close the text connection + options(mypkg.connection = stdin()) + close(my_file) +}) + +testthat::test_that("Make IDs (e) - duplicate data", { + # Prepare data + otree2 <- otree_5_4_0_non_unique + + # Run function and test + testthat::expect_error( + make_ids(otree2, + pmake = TRUE, + gmake = TRUE, + from_var = "dictator.1.group.id_in_subsession", + emptyrows = "yes"), + "length of participant codes is not equal the length of unique participant") +}) + +testthat::test_that("Make IDs (e) - wrong from_app", { + # Prepare data + otree2 <- otree_5_4_0 + + # Run function and test + testthat::expect_error(make_ids(otree2, + gmake = TRUE, + from_app = "Chats", + emptyrows = "yes"), + "You are not supposed to use") +}) + +testthat::test_that("Make IDs (e) - no participant.code", { + # Prepare data + otree2 <- otree_5_4_0 + otree2$all_apps_wide$participant.code <- NULL + + # Run function and test + testthat::expect_error(make_ids(otree2, + gmake = FALSE, + emptyrows = "yes"), + "There is no participant.code in") +}) + +testthat::test_that("Make IDs (e) - participant.code is NA", { + # Prepare data + otree2 <- otree_5_4_0 + otree2$all_apps_wide$participant.code <- NA + + # Run function and test + testthat::expect_error(make_ids(otree2, + gmake = FALSE, + emptyrows = "yes"), + "There are NAs in your participant.code") +}) + +testthat::test_that("Make IDs (e) - from_app not found", { + # Prepare data + otree2 <- otree_2_2_4 + + # Run function and test + testthat::expect_error(make_ids(otree2, + gmake = TRUE, + from_app = "xyz", + emptyrows = "yes"), + "not found") +}) + +testthat::test_that("Make IDs (e) - from_app not data frame", { + # Prepare data + otree2 <- otree_2_2_4 + otree2$notadataframe <- c(1, 2, 3) + + # Run function + testthat::expect_error(make_ids(otree2, gmake = TRUE, + from_app = "notadataframe"), + "not a data frame") +}) + +testthat::test_that("Make IDs (e) - from_app empty data frame", { + # Prepare data + otree2 <- otree_5_4_0 + otree2$emptydataframe <- data.frame() + + # Run function and test + testthat::expect_error(make_ids(otree2, + gmake = TRUE, + from_app = "emptydataframe"), + "Your from_app is not a normal oTree all_apps_wide or apps data frame.") +}) + +testthat::test_that("Make IDs (e) - from_app empty data frame", { + # Prepare data + otree2 <- otree_5_4_0 + otree2$survey <- otree2$survey[c(), ] + + # Run function and test + testthat::expect_error(make_ids(otree2, + gmake = TRUE, + from_app = "survey"), + "has no entries") +}) + +testthat::test_that("Make IDs (e) - no variable", { + # Prepare data (delete group_id) + otree2 <- otree_5_4_0 + otree2$all_apps_wide <- otree2$all_apps_wide[ + , !(endsWith(names(otree2$all_apps_wide), "group.id_in_subsession"))] + + # Run function and test + testthat::expect_error(make_ids(otree2, + gmake = TRUE), + "No variable that ends with") +}) + +testthat::test_that("Make IDs (e) - group_id cannot be calculated", { + # Prepare data + otree2 <- otree_5_4_0 + + # Run function and test + testthat::expect_error(make_ids(otree2, gmake = TRUE), + "roup_id can not be calculated") +}) + +testthat::test_that("Make IDs (e) - participant_code and participant__code", { + # Prepare data + otree2 <- otree_all + + # Run function and test + testthat::expect_error( + make_ids(otree2, gmake = TRUE), + "You combined data.*messy_time.*messy_chat") +}) + +testthat::test_that("Make IDs (e) - participant_code and participant__code", { + # Prepare data + otree2 <- otree_all + otree2 <- messy_time(otree2, combine = TRUE) + + # Run function + error <- tryCatch( + make_ids(otree2, gmake = TRUE), + error = function(e) e) + + # Test + testthat::expect_true(grepl( + "You combined data from old and new oTree versions", error)) + testthat::expect_false(grepl( + "messy_time", error)) + testthat::expect_true(grepl( + "messy_chat", error)) +}) + +testthat::test_that("Make IDs (e) - participant_code and participant__code", { + # Prepare data + otree2 <- otree_all + otree2 <- messy_chat(otree2, combine = TRUE) + + # Run function + error <- tryCatch( + make_ids(otree2, gmake = TRUE), + error = function(e) e) + + # Test + testthat::expect_true(grepl( + "You combined data from old and new oTree versions", error)) + testthat::expect_false(grepl( + "messy_chat", error)) + testthat::expect_true(grepl( + "messy_time", error)) +}) + +testthat::test_that("Make IDs (e) - NA in participant__code", { + # Prepare data + otree2 <- otree_2_2_4 + otree2$Chats$participant__code[1] <- NA # leaves only nas in participant_code + + # Run function and test + testthat::expect_error( + make_ids(otree2, + gmake = TRUE), + "There are NAs in your participant__code variable in the") +}) + +testthat::test_that("Make IDs (e) - NA in participant_code", { + # Prepare data + otree2 <- otree_5_4_0 + otree2$Chats$participant_code[1] <- NA + + # Run function and test + testthat::expect_error( + make_ids(otree2, + gmake = TRUE), + "There are NAs in your participant_code variable in the") +}) + +testthat::test_that("Make IDs (e) - session_code and session__code", { + # Prepare data + otree2 <- otree_all + + # Run function and test + testthat::expect_error( + make_ids(otree2, + gmake = FALSE), + "You combined data from old and new oTree versions") +}) + +testthat::test_that("Make IDs (e) - group_id not the same", { + otree2 <- otree_5_4_0 + testthat::expect_error( + make_ids(otree2, + gmake = TRUE), + "You don't have the same group.id_in_subsession in every app") +}) + +testthat::test_that("Make IDs (e) - only use from_app or from_var", { + # Prepare data + otree2 <- otree_5_4_0 + + # Run function and test + testthat::expect_error( + make_ids(oTree = otree2, + from_app = "dictator", + from_var = "dictator.1.group.id_in_subsession", + gmake = TRUE), + "Please only use") +}) + +testthat::test_that("Make IDs (e) - from_var constant - nondistinct", { + # Prepare data + otree2 <- otree_5_4_0_non_unique + + # Run function and test + testthat::expect_error( + otree2 <- make_ids(otree2, + from_var = "survey.1.group.id_in_subsession"), + "length of participant codes is not equal the length of unique participant") +}) + +testthat::test_that("Make IDs (e) - from_var not found", { + # Prepare data + otree2 <- otree_5_4_0 + + # Run function and test + testthat::expect_error(make_ids(otree2, + gmake = TRUE, + from_var = "donotfind"), + "not found") + + # Test if variables exist / don't exist + test1 <- is.null(otree2$all_apps_wide$group_id) + test2 <- is.null(otree2$all_apps_wide$participant_id) + test3 <- is.null(otree2$all_apps_wide$session_id) + testthat::expect_true(all(c(test1, test2, test3))) +}) + +testthat::test_that("Make IDs (e) - from_var not found, session codes Na", { + # Prepare data + otree2 <- otree_5_4_0 + otree2$all_apps_wide$session.code[c(1, 5, 3)] <- NA + + # Run function + testthat::expect_error( + + otree2 <- make_ids(otree2, + gmake = TRUE, + from_var = "donotfind"), + "from_var.*not found") + + # Test if variables exist / don't exist + test1 <- is.null(otree2$all_apps_wide$group_id) + test2 <- is.null(otree2$all_apps_wide$participant_id) + test3 <- is.null(otree2$all_apps_wide$session_id) + testthat::expect_true(all(c(test1, test2, test3))) +}) + +testthat::test_that("Make IDs (e) - chat_warning", { + # Prepare data + otree2 <- otree_5_4_0 + otree2$Chats$participant_code <- 1 + + # Run function and test + testthat::expect_error(make_ids(otree2, icw = FALSE), + "bug") +}) + +testthat::test_that("Make IDs (e) - wrong from_var", { + # Prepare data + otree2 <- otree_5_4_0 + + # Run function and test + testthat::expect_error(make_ids(otree2, from_var = "gender"), + "not found") +}) + +testthat::test_that("Make IDs (e) - from_app & data there twice", { + # Prepare data + otree3 <- otree_5_4_0 + otree3$all_apps_wide <- rbind(otree3$all_apps_wide, + otree3$all_apps_wide) + otree3$dictator <- rbind(otree3$dictator, otree3$dictator) + + # Run function and test + testthat::expect_error( + otree3 <- make_ids(otree3, gmake = TRUE, from_app = "dictator"), + "The length of participant codes is not equal") +}) + +testthat::test_that("Make IDs - from_app (old)", { + # Prepare data + otree2 <- otree_2_2_4 + otree2 <- delete_duplicate(otree2) + otree2$all_apps_wide$session.code + otree2$dictator$session.code + order_aaw_before <- otree2$all_apps_wide$participant.code + order_dictator_before <- otree2$dictator$participant.code + + # Run function + otree2 <- make_ids(otree2, + gmake = TRUE, + from_app = "dictator", + emptyrows = "yes") + # Test + testthat::expect_equal(max(otree2$dictator$participant_id), + length(unique(otree2$dictator$participant.code))) + testthat::expect_equal(max(otree2$dictator$group_id), 6) + testthat::expect_equal(max(otree2$dictator$session_id), 2) + + # Test if variables exist / don't exist + test1 <- !is.null(otree2$all_apps_wide$participant_id) + test2 <- !is.null(otree2$dictator$group_id) + test3 <- !is.null(otree2$survey$participant_id) + test4 <- !is.null(otree2$survey$group_id) + test5 <- !is.null(otree2$survey$session_id) + + testthat::expect_true(all(c(test1, test2, test3, test4, test5))) + + # Test if order of DF entries did not change + order_aaw_after <- otree2$all_apps_wide$participant.code + order_dictator_after <- otree2$dictator$participant.code + + test1 <- all(order_aaw_before == order_aaw_after) + test2 <- all(order_dictator_before == order_dictator_after) + testthat::expect_true(all(c(test1, test2))) + + # Test - check if no two session codes have the same session id + id_code_pairs <- unique(paste( + otree2$all_apps_wide$session_id, + otree2$all_apps_wide$session.code)) + + numbers <- as.integer(sub("^([0-9]+).*", "\\1", id_code_pairs)) + strings <- sub("^[0-9]+ (.*)", "\\1", id_code_pairs) + test1 <- !any(duplicated(numbers)) + testthat::expect_true(test1) + test2 <- !any(duplicated(strings)) + testthat::expect_true(test2) + + # Test - check if no two participant codes have the same participant id + id_code_pairs <- unique(paste( + otree2$all_apps_wide$participant_id, + otree2$all_apps_wide$participant.code)) + + numbers <- as.integer(sub("^([0-9]+).*", "\\1", id_code_pairs)) + strings <- sub("^[0-9]+ (.*)", "\\1", id_code_pairs) + test1 <- !any(duplicated(numbers)) + testthat::expect_true(test1) + test2 <- !any(duplicated(strings)) + testthat::expect_true(test2) +}) + +print("---- extime -----") +# Experiment time #### +testthat::test_that("extime - all oTree", { + # Prepare data + otree2 <- otree_all + testthat::expect_warning( + otree2 <- messy_time(otree2, combine = TRUE, info = TRUE), + "referred to the time stamp.*participant code") + + # Run function + output <- extime(otree2) + + # Test + # Test if variables exist / don't exist + test1 <- !is.null(output$mean_duration) & !is.na(output$mean_duration) + test2 <- !is.null(output$min_duration) & !is.na(output$min_duration) + test3 <- !is.null(output$max_duration) & !is.na(output$max_duration) + test4 <- exists("single_durations", output) + + # Test if the values and the single_durations align + test5 <- round(output$min_duration, 2) == + round(min(output$single_durations$duration), 2) + test6 <- round(output$max_duration, 2) == + round(max(output$single_durations$duration), 2) + test7 <- round(output$mean_duration, 2) == + round(mean(output$single_durations$duration), 2) + testthat::expect_true(all(c(test1, test2, test3, test4, + test5, test6, test7))) +}) + +testthat::test_that("extime - new oTree", { + # Prepare data + otree2 <- otree_5_4_0 + + # Run function + output <- extime(otree2) + + # Test + test1 <- !is.null(output$mean_duration) & !is.na(output$mean_duration) + test2 <- !is.null(output$min_duration) & !is.na(output$min_duration) + test3 <- !is.null(output$max_duration) & !is.na(output$max_duration) + test4 <- exists("single_durations", output) + + test6 <- round(mean(output$single_durations$duration), + digits = 2) == output$mean_duration + + testthat::expect_true(all(c(test1, test2, test3, + test4, test6))) +}) + +testthat::test_that("extime - messy not included", { + # Prepare data + otree2 <- otree_all + + # Run function and test + testthat::expect_error( + output <- extime(otree2, combine = FALSE), # Is automatically TRUE + "using data from different " + ) +}) + +testthat::test_that("extime - messy included", { + # Prepare data + otree2 <- otree_all + + # Run function + output <- extime(otree2, combine = TRUE) # Is automatically TRUE + + # Test + + # Test if variables exist / don't exist + test1 <- !is.null(output$mean_duration) & !is.na(output$mean_duration) + test2 <- !is.null(output$min_duration) & !is.na(output$min_duration) + test3 <- !is.null(output$max_duration) & !is.na(output$max_duration) + test4 <- exists("single_durations", output) + + # Test if the values and the single_durations align + test5 <- round(output$min_duration, 2) == + round(min(output$single_durations$duration), 2) + test6 <- round(output$max_duration, 2) == + round(max(output$single_durations$duration), 2) + test7 <- round(output$mean_duration, 2) == + round(mean(output$single_durations$duration), 2) + testthat::expect_true(all(c(test1, test2, test3, test4, + test5, test6, test7))) +}) + +testthat::test_that("extime - 3 digits", { + # Prepare data + otree2 <- otree_5_4_0 + + # Run function + output <- extime(otree2, digits = 3) + + # Test + test1 <- round(mean(output$single_durations$duration), digits = 3) == + output$mean_duration + test2 <- round(min(output$single_durations$duration), digits = 3) == + output$min_duration + test3 <- round(max(output$single_durations$duration), digits = 3) == + output$max_duration + # Test if the values and the single_durations align + test5 <- round(output$min_duration, 2) == + round(min(output$single_durations$duration), 2) + test6 <- round(output$max_duration, 2) == + round(max(output$single_durations$duration), 2) + test7 <- round(output$mean_duration, 2) == + round(mean(output$single_durations$duration), 2) + testthat::expect_true(all(c(test1, test2, test3, + test5, test6, test7))) +}) + +testthat::test_that("extime - new", { + # Prepare data + otree2 <- otree_5_4_0 + + # Run function + output <- extime(otree2, startat = 1) + + # Test + + # Test if variables exist / don't exist + test1 <- !is.null(output$mean_duration) & !is.na(output$mean_duration) + test2 <- !is.null(output$min_duration) & !is.na(output$min_duration) + test3 <- !is.null(output$max_duration) & !is.na(output$max_duration) + test4 <- exists("single_durations", output) + + # Test if the values and the single_durations align + test5 <- round(output$min_duration, 2) == + round(min(output$single_durations$duration), 2) + test6 <- round(output$max_duration, 2) == + round(max(output$single_durations$duration), 2) + test7 <- round(output$mean_duration, 2) == + round(mean(output$single_durations$duration), 2) + testthat::expect_true(all(c(test1, test2, test3, test4, + test5, test6, test7))) +}) + +testthat::test_that("extime - for a specific group", { + # Prepare data + otree2 <- otree_5_4_0 + otree2 <- make_ids(otree2, gmake = TRUE, from_app = "dictator") + + # Run + output <- extime(otree2, group_id = 1) + + # Test + test1 <- !is.null(output$mean_duration) & !is.na(output$mean_duration) + test2 <- !is.null(output$min_duration) & !is.na(output$min_duration) + test3 <- !is.null(output$max_duration) & !is.na(output$max_duration) + test4 <- exists("single_durations", output) + testthat::expect_true(all(c(test1, test2, test3, test4))) +}) + +testthat::test_that("extime - experiment just one page", { + otree2 <- otree_2_2_4 + + # Run + output <- extime(otree2, sinfo = NULL) + + # Test + + # Test if variables exist / don't exist + test1 <- !is.null(output$mean_duration) & !is.na(output$mean_duration) + test2 <- !is.null(output$min_duration) & !is.na(output$min_duration) + test3 <- !is.null(output$max_duration) & !is.na(output$max_duration) + test4 <- exists("single_durations", output) + + test5 <- grepl("the experiment only has one page", output$messages) + test6 <- is.vector(output$only_one_page) + + # Test if the values and the single_durations align + test7 <- round(output$min_duration, 2) == + round(min(output$single_durations$duration), 2) + test8 <- round(output$max_duration, 2) == + round(max(output$single_durations$duration), 2) + test9 <- round(output$mean_duration, 2) == + round(mean(output$single_durations$duration), 2) + testthat::expect_true(all(c(test1, test2, test3, test4, + test5, test6, test7, test8, + test9))) +}) + +testthat::test_that("extime - with sinfo session_code", { + otree2 <- otree_all + testthat::expect_warning( + otree2 <- messy_time(otree2, combine = TRUE, info = TRUE), + "More than one variable referred to") + + # Run function + output <- extime(otree2, sinfo = "session_code") + + # Test + + # Test if variables exist / don't exist + test1 <- !is.null(output$mean_duration) & !is.na(output$mean_duration) + test2 <- !is.null(output$min_duration) & !is.na(output$min_duration) + test3 <- !is.null(output$max_duration) & !is.na(output$max_duration) + test4 <- exists("single_durations", output) + + # Test if the values and the single_durations align + test5 <- round(output$min_duration, 2) == + round(min(output$single_durations$duration), 2) + test6 <- round(output$max_duration, 2) == + round(max(output$single_durations$duration), 2) + test7 <- round(output$mean_duration, 2) == + round(mean(output$single_durations$duration), 2) + testthat::expect_true(all(c(test1, test2, test3, test4, + test5, test6, test7))) +}) + +testthat::test_that("extime - session_id", { + # Prepare data + otree2 <- otree_all + otree2 <- delete_duplicate(otree2) + testthat::expect_warning( + otree2 <- messy_chat(otree2, combine = TRUE, info = TRUE), + "More than one variable referred to") + + testthat::expect_warning( + otree2 <- messy_time(otree2, combine = TRUE, info = TRUE), + "More than one variable referred to") + + otree2 <- make_ids(otree2, pmake = TRUE) + + # Run function + output <- extime(otree2, + combine = TRUE, + sinfo = "session_id") + + # Test + test1 <- is.numeric(output$mean_duration) + test2 <- is.numeric(output$max_duration) + test3 <- is.numeric(output$min_duration) + test4 <- is.numeric(output$single_durations$session) + + # Test if the values and the single_durations align + test5 <- round(output$min_duration, 2) == + round(min(output$single_durations$duration), 2) + test6 <- round(output$max_duration, 2) == + round(max(output$single_durations$duration), 2) + test7 <- round(output$mean_duration, 2) == + round(mean(output$single_durations$duration), 2) + + # Test warnings + test8 <- !is.null(output$only_one_page) + test9 <- any(grepl( + "For at least one participant, the experiment only has one page", + output$messages)) + testthat::expect_true(all(c(test1, test2, test3, test4, + test5, test6, test7, test8, test9))) +}) + +testthat::test_that("extime - otree all: no session_id", { + # Prepare data + otree2 <- otree_all + otree2 <- delete_duplicate(otree2) + + # Run function + output <- extime(otree2, + combine = TRUE, + sinfo = "session_id") + # Test + test1 <- is.numeric(output$single_durations$session) + testthat::expect_true(test1) +}) + +testthat::test_that("extime - otree all: session_code", { + # Prepare data + otree2 <- otree_all + otree2 <- delete_duplicate(otree2) + + # Run function + output <- extime(otree2, + combine = TRUE, + sinfo = "session_code") + # Test + test1 <- is.vector(output$single_durations$session) + testthat::expect_true(test1) + + # Test if the values and the single_durations align + test5 <- round(output$min_duration, 2) == + round(min(output$single_durations$duration), 2) + test6 <- round(output$max_duration, 2) == + round(max(output$single_durations$duration), 2) + test7 <- round(output$mean_duration, 2) == + round(mean(output$single_durations$duration), 2) + testthat::expect_true(all(c(test5, test6, test7))) +}) + +testthat::test_that("extime - one person only one page", { + # Prepare data + otree2 <- otree_2_2_4 + person <- aggregate(otree2$Time, + list(person = otree2$Time$participant__code), + FUN = "max") + person <- unlist(person[person$page_index == 1, ][1]) + + # Run function + testthat::expect_warning( + output <- extime(otree2, + combine = TRUE, + sinfo = NULL, + person), "the experiment only has one page") + + # Test + test1 <- is.na(output) + testthat::expect_true(test1) +}) + +testthat::test_that("extime - startat real", { + # Prepare data + otree2 <- otree_5_4_0 + + # Run function + output <- extime(otree2, + startat = "real", + seconds = TRUE, + sinfo = NULL) + + # Test + test1 <- !is.null(output$mean_duration) & !is.na(output$mean_duration) + test2 <- !is.null(output$min_duration) & !is.na(output$min_duration) + test3 <- !is.null(output$max_duration) & !is.na(output$max_duration) + test4 <- exists("single_durations", output) + + # Test if the values and the single_durations align + test5 <- round(output$min_duration, 2) == + round(min(output$single_durations$duration), 2) + test6 <- round(output$max_duration, 2) == + round(max(output$single_durations$duration), 2) + test7 <- round(output$mean_duration, 2) == + round(mean(output$single_durations$duration), 2) + testthat::expect_true(all(c(test1, test2, test3, test4, + test5, test6, test7))) +}) + +testthat::test_that("extime - startat comparison - comparison real und 1", { + # Prepare data + otree2 <- otree_5_4_0 + + # Run function + output <- extime(otree2, + startat = "real", + seconds = TRUE, + sinfo = NULL) + + output2 <- extime(otree2, + startat = 1, + seconds = TRUE, + sinfo = NULL) + + # Der unterschied zu start1 ist, dass bei start1 nicht kommazahlen kommen. + # Das liegt daran, dass "real" eine genauere Anfangszeit hat!!! + + # Test + test1 <- !is.null(output$mean_duration) & !is.na(output$mean_duration) + test2 <- !is.null(output$min_duration) & !is.na(output$min_duration) + test3 <- !is.null(output$max_duration) & !is.na(output$max_duration) + test4 <- exists("single_durations", output) + # Test if the values and the single_durations align + test5 <- round(output$min_duration, 2) == + round(min(output$single_durations$duration), 2) + test6 <- round(output$max_duration, 2) == + round(max(output$single_durations$duration), 2) + test7 <- round(output$mean_duration, 2) == + round(mean(output$single_durations$duration), 2) + testthat::expect_true(all(c(test1, test2, test3, test4, + test5, test6, test7))) +}) + +testthat::test_that("extime - seconds", { + otree2 <- otree_5_4_0 + + # Run function + output <- extime(otree2, seconds = TRUE) + + # Test + test1 <- !is.null(output$mean_duration) & !is.na(output$mean_duration) + test2 <- !is.null(output$min_duration) & !is.na(output$min_duration) + test3 <- !is.null(output$max_duration) & !is.na(output$max_duration) + test4 <- exists("single_durations", output) + + # Test if the values and the single_durations align + test5 <- round(output$min_duration, 2) == + round(min(output$single_durations$duration), 2) + test6 <- round(output$max_duration, 2) == + round(max(output$single_durations$duration), 2) + test7 <- round(output$mean_duration, 2) == + round(mean(output$single_durations$duration), 2) + testthat::expect_true(all(c(test1, test2, test3, test4, + test5, test6, test7))) +}) + +testthat::test_that("extime - old", { + # Prepare data + otree2 <- otree_2_2_4 + + # Run function + output <- extime(otree2, sinfo = NULL) + + # Test + test1 <- !is.null(output$mean_duration) & !is.na(output$mean_duration) + test2 <- !is.null(output$min_duration) & !is.na(output$min_duration) + test3 <- !is.null(output$max_duration) & !is.na(output$max_duration) + test4 <- exists("single_durations", output) + + # Test if the values and the single_durations align + test5 <- round(output$min_duration, 2) == + round(min(output$single_durations$duration), 2) + test6 <- round(output$max_duration, 2) == + round(max(output$single_durations$duration), 2) + test7 <- round(output$mean_duration, 2) == + round(mean(output$single_durations$duration), 2) + testthat::expect_true(all(c(test1, test2, test3, test4, + test5, test6, test7))) +}) + +testthat::test_that("extime - oTree version 2.2.4", { + # Prepare data + otree2 <- otree_2_2_4 + # otree2$Time$session_id # There is already a variable called session_id + otree2 <- make_ids(otree2) + # otree2$Time$session_id # The new session_id looks the same + + # Run function + output <- extime(otree2, sinfo = "session_id") + + # Test + test1 <- !is.null(output$mean_duration) & !is.na(output$mean_duration) + test2 <- !is.null(output$min_duration) & !is.na(output$min_duration) + test3 <- !is.null(output$max_duration) & !is.na(output$max_duration) + test4 <- exists("single_durations", output) + # Test if the values and the single_durations align + test5 <- round(output$min_duration, 2) == + round(min(output$single_durations$duration), 2) + test6 <- round(output$max_duration, 2) == + round(max(output$single_durations$duration), 2) + test7 <- round(output$mean_duration, 2) == + round(mean(output$single_durations$duration), 2) + testthat::expect_true(all(c(test1, test2, test3, test4, + test5, test6, test7))) +}) + +testthat::test_that("extime - old specific", { + # Prepare data + otree2 <- otree_2_2_4 + person <- otree2$all_apps_wide$participant.code[1] + + # Run function + output <- extime(otree2, + pcode = person, + sinfo = NULL) + + # Test + test <- !is.null(output) & !is.na(output) + testthat::expect_true(test) +}) + +testthat::test_that("extime - old startatreal without session info", { + # Prepare data + otree2 <- otree_2_2_4 + otree2 <- make_ids(otree2, gmake = TRUE, from_app = "dictator") + + # Run function + output <- extime(otree2, startat = "real", sinfo = NULL) + + # Test + testthat::expect_output(str(output), "List of 6") + + # Test if the values and the single_durations align + test5 <- round(output$min_duration, 2) == + round(min(output$single_durations$duration), 2) + test6 <- round(output$max_duration, 2) == + round(max(output$single_durations$duration), 2) + test7 <- round(output$mean_duration, 2) == + round(mean(output$single_durations$duration), 2) + testthat::expect_true(all(c(test5, test6, test7))) +}) + +testthat::test_that("extime - old startatreal with session info", { + # Prepare data + otree2 <- otree_2_2_4 + otree2 <- make_ids(otree2, gmake = TRUE, from_app = "dictator") + + # Run function and test + # If sinfo is not NULL, there will be an error in some of the old oTree + # versions because they don't save the session_code there + testthat::expect_error( + output <- extime(otree2, startat = "real", sinfo = "session_code"), + "There is no variable called session_code or session__code") +}) + +testthat::test_that("extime - for a specific individual", { + # Prepare data + otree2 <- otree_5_4_0 + otree2 <- make_ids(otree2, gmake = TRUE, from_app = "dictator") + person <- otree2$all_apps_wide$participant.code[1] + + # Run function + output <- extime(otree2, person) + + # Test + max <- max(otree2$Time$epoch_time_completed[ + otree2$Time$participant_code == person]) + min <- min(otree2$Time$epoch_time_completed[ + otree2$Time$participant_code == person]) + duration <- max - min + duration <- duration / 60 + testthat::expect_equal(output, round(duration, 2)) +}) + +testthat::test_that("extime - for a specific individual (real)", { + # Prepare data + otree2 <- otree_5_4_0 + otree2 <- make_ids(otree2, gmake = TRUE, from_app = "dictator") + person1 <- unique(otree2$Time$participant_code)[1] + + # Run function + output <- extime(otree2, person1, startat = "real") + + # Test + max <- max(otree2$Time$epoch_time_completed[ + otree2$Time$participant_code == person1]) + min <- (as.numeric( + as.POSIXct(otree2$all_apps_wide$participant.time_started[ + otree2$all_apps_wide$participant.code == person1], tz = "UTC"))) + + duration <- max - min + duration <- duration / 60 + testthat::expect_equal(output, round(duration, 2)) +}) + +testthat::test_that("extime - old specific, warning not enough entries", { + # Prepare data (get a person with only one index entry) + otree2 <- otree_2_2_4 + person <- aggregate(otree2$Time, + list(person = otree2$Time$participant__code), + FUN = "max") + person <- unlist(person[person$page_index == 1, ][1]) + + # Run function and test + testthat::expect_warning( + output <- extime(otree2, + pcode = person, + sinfo = NULL), + "the experiment only has one page") + + test1 <- is.na(output) + testthat::expect_true(test1) +}) + +testthat::test_that("extime - old specific, startat", { + # Prepare data + otree2 <- otree_2_2_4 + person <- otree2$all_apps_wide$participant.code[1] + + # Run function + output <- extime(otree2, + pcode = person, + sinfo = NULL, + startat = "real") + + # Test + test <- !is.null(output) & !is.na(output) + testthat::expect_true(test) +}) + +testthat::test_that("extime - old startatreal", { + # Prepare data + otree2 <- otree_2_2_4 + + # Run function + output <- extime(otree2, startat = "real", sinfo = NULL) + + # Test + testthat::expect_output(str(output), "List of 6") + test1 <- is.numeric(output$mean_duration) + test2 <- is.numeric(output$max_duration) + test3 <- is.numeric(output$min_duration) + test4 <- !is.null(output$single_durations) + test5 <- is.null(output$single_durations$session) + test6 <- !is.null(output$messages) + test7 <- !is.null(output$only_one_page) + testthat::expect_true(all(c(test1, test2, test3, test4, + test5, test6, test7))) + + # Test if the values and the single_durations align + test5 <- round(output$min_duration, 2) == + round(min(output$single_durations$duration), 2) + test6 <- round(output$max_duration, 2) == + round(max(output$single_durations$duration), 2) + test7 <- round(output$mean_duration, 2) == + round(mean(output$single_durations$duration), 2) + testthat::expect_true(all(c(test5, test6, test7))) +}) + +testthat::test_that("extime - old startat and 0 comparison", { + # Prepare data + otree2 <- otree_5_4_0 + person <- otree2$all_apps_wide$participant.code[1] + + # Run function + startattime_real <- extime(otree2, + startat = "real", + seconds = TRUE, + digits = 5, + sinfo = NULL) + startattime_0 <- extime(otree2, + startat = 1, + seconds = TRUE, + digits = 5, + sinfo = NULL) + + # Test + val_real <- otree2$all_apps_wide$participant.time_started_utc[ + otree2$all_apps_wide$participant.code == person] + + # Delete last part of val_real (more detailed time than val0) + # val0 only seconds + val_real <- stringr::str_remove(val_real, ".[0-9]{6}") + + val0 <- otree2$Time$epoch_time_completed[ + otree2$Time$participant_code == person & + otree2$Time$page_index == 0] + + val0 <- as.POSIXct(val0, tz = "UTC", origin = "1970-01-01") + # Remove UTC + val0 <- stringr::str_remove(val0, " UTC") + test1 <- val_real == val0 + testthat::expect_true(test1) +}) + +testthat::test_that("extime (w) - warning only one page for old specific", { + # Prepare data + otree2 <- otree_2_2_4 + person <- aggregate(otree2$Time, + list(person = otree2$Time$participant__code), + FUN = "max") + person <- unlist(person[person$page_index == 1, ][1]) + + # Run function and test + testthat::expect_warning( + output <- extime(otree2, + pcode = person, + sinfo = NULL), + "the experiment only has one page") + test <- is.na(output) + testthat::expect_true(test) +}) + +testthat::test_that("extime (e) - plabel and group_id", { + # Prepare data + otree2 <- otree_5_4_0 + + # Run function and test + testthat::expect_error( + extime(otree2, + plabel = "Person 1", + group_id = 1, + sinfo = NULL), + "Please enter only plabel or group_id") +}) + +testthat::test_that("extime (e) - plabel and pcode", { + # Prepare data + otree2 <- otree_5_4_0 + person <- otree2$all_apps_wide$participant.code[1] + + # Run function and test + testthat::expect_error( + extime(otree2, + plabel = "Person 1", + pcode = person, + sinfo = NULL), + "Please enter only pcode or plabel") +}) + +testthat::test_that("extime (e) - several plabels", { + # Prepare data + otree2 <- otree_5_4_0 + + # Run function and test + testthat::expect_error( + extime(otree2, + plabel = c("Person 1", "Person 2"), + sinfo = NULL), + "Please enter only one participant label") +}) + +testthat::test_that("extime (e) - plabel but no aaw", { + # Prepare data + otree2 <- otree_5_4_0 + otree2$all_apps_wide <- NULL + + # Run function and test + testthat::expect_error( + extime(otree2, + plabel = "Person 1", + sinfo = NULL), + "if there is an all_apps_wide-data frame") +}) + +testthat::test_that("extime (e) - old specific: TIME empty", { + # Prepare data (delete everything from time) + otree2 <- otree_2_2_4 + otree2$Time <- otree2$Time[c(), ] + + # Run function and test + testthat::expect_error(extime(otree2, + sinfo = NULL), + "data frame is empty") +}) + +testthat::test_that("extime (e) - old specific: TIME for one empty", { + # Prepare data + otree2 <- otree_2_2_4 + person <- otree2$all_apps_wide$participant.code[2] + otree2$Time <- otree2$Time[otree2$Time$participant__code != person, ] + + # Run function and test + testthat::expect_error(extime(otree2, + pcode = person, + sinfo = NULL), + "The participant is not in the") +}) + +testthat::test_that("extime (e) - starting value old specific", { + # Prepare data + otree2 <- otree_2_2_4 + person <- otree2$all_apps_wide$participant.code[2] + + # Run function and test + testthat::expect_error( + extime(otree2, + pcode = person, + sinfo = NULL, + startat = 20), + "The chosen starting value startat is higher than the total") +}) + +testthat::test_that("extime (e) - startat specific - old", { + # Prepare data + otree2 <- otree_2_2_4 + person <- otree2$all_apps_wide$participant.code[1] + + # Run function and test + testthat::expect_error( + extime(otree2, + startat = 400, + pcode = person, + sinfo = NULL), + "The chosen starting value startat is higher than the total number") +}) + +testthat::test_that("extime (e) - startat: old", { + # Prepare data + otree2 <- otree_2_2_4 + + # Run function and test + testthat::expect_error( + extime(otree2, + startat = 400, + sinfo = NULL), + "The chosen starting value startat is higher than the total number") +}) + +testthat::test_that("extime (e) - startat: new", { + # Prepare data + otree2 <- otree_5_4_0 + + # Run function and test + testthat::expect_error( + extime(otree2, + startat = 400, + sinfo = NULL), + "The chosen starting value startat is higher than the total number") +}) + +testthat::test_that("extime (e) - startat: new specific", { + # Prepare data + otree2 <- otree_5_4_0 + person <- otree2$all_apps_wide$participant.code[1] + + # Run function and test + testthat::expect_error( + extime(otree2, + pcode = person, + startat = 400, + sinfo = NULL), + "The chosen starting value startat is higher than the total number") +}) + +testthat::test_that("extime (e) - startat: old specific", { + # Prepare data + otree2 <- otree_2_2_4 + otree2 <- delete_duplicate(otree2) + person <- otree2$all_apps_wide$participant.code[1] + + # Run function and test + testthat::expect_error( + extime(otree2, + pcode = person, + startat = 400, + sinfo = NULL), + "The chosen starting value startat is higher than the total number") +}) + +testthat::test_that("extime (e) - startat: new too low", { + # Prepare data + otree2 <- otree_2_2_4 + otree2$Time <- otree2$Time[otree2$Time$page_index > 2, ] + + # Run function and test + testthat::expect_error( + extime(otree2, + startat = 1, + sinfo = NULL), + "is lower than") +}) + +testthat::test_that("extime (e) - startat: new too low", { + # Prepare data + otree2 <- otree_2_2_4 + otree2$Time <- otree2$Time[otree2$Time$page_index > 2, ] + person <- otree2$Time$participant__code[otree2$Time$page_index > 5][1] + + # Run function and test + testthat::expect_error( + extime(otree2, + pcode = person, + startat = 1, + sinfo = NULL), + "is lower than") +}) + +testthat::test_that("extime (e) - startat real and no aaw", { + # Prepare data + otree2 <- otree_5_4_0 + otree2$all_apps_wide <- NULL + + # Run function and test + testthat::expect_error(extime(otree2, + startat = "real", + sinfo = NULL), + "only works if there is a") +}) + +testthat::test_that("extime (e) - nonexistent specific individual ", { + # Prepare data + otree2 <- otree_5_4_0 + + # Run function and test + testthat::expect_error(extime(otree2, + "fake_individual"), + "The participant is not in the") +}) + +testthat::test_that("extime (e) - individual + group specified", { + # Prepare data + otree2 <- otree_5_4_0 + + # Run function and test + testthat::expect_error(extime(otree2, + pcode = "3ttf7yix", + group_id = 1), + "specify either the pcode or the group_id") +}) + +testthat::test_that("extime (e) - variable group_id not there", { + # Run function and test + otree2 <- otree_5_4_0 + + # Run function and test error if group_id is not defined yet + testthat::expect_error(extime(otree2, group_id = 7)) +}) + +testthat::test_that("extime (e) - this group_id not there", { + # Prepare data + otree2 <- otree_5_4_0 + otree2 <- make_ids(otree2, gmake = TRUE, from_app = "dictator") + + # Run function and test error if chosen group_id is not in data frame + testthat::expect_error(extime(otree2, group_id = 47)) +}) + +testthat::test_that("extime (e) - no session_code", { + # Prepare data + otree2 <- otree_5_4_0 + otree2$Time$session_code <- NULL + + # Run function and test error if chosen group_id is not in data frame + testthat::expect_error(extime(otree2), + "no variable called session_code") +}) + +testthat::test_that("extime (e) - valid session info", { + # Prepare data + otree2 <- otree_5_4_0 + + # Run function and test + testthat::expect_error(extime(otree2, + sinfo = "any"), + "Please specify a valid sinfo") +}) + +testthat::test_that("extime (e) - no session id", { + # Prepare data + otree2 <- otree_5_4_0 + otree2$Time$session_id <- NULL + + # Run function and test + testthat::expect_error(extime(otree2, + sinfo = "session_id"), + "There is no session_id in the") +}) + +testthat::test_that("extime (e) - only one participant", { + # Prepare data + otree2 <- otree_5_4_0 + + # Run function and test + testthat::expect_error( + extime(otree2, + pcode = c("164r1hs4", "7wa8kk3d")), + "Please enter only one participant") +}) + +testthat::test_that("extime (e) - no Time data frame", { + # Prepare data + otree2 <- otree_5_4_0 + otree2$Time <- NULL + + # Run function and test + testthat::expect_error(extime(otree2), + "There is no \"Time\" data frame") +}) + +testthat::test_that("extime (e) - participant not there", { + # Prepare data + otree2 <- otree_all + + # Run function and test + testthat::expect_error( + extime(otree2, + sinfo = "session_id", + combine = TRUE, + pcode = "wrongcode"), "The participant is not in the ") +}) + +testthat::test_that("extime (e) - messy data", { + # Prepare data + otree2 <- otree_all + + # Run function and test error + testthat::expect_error( + extime(otree2, + sinfo = "session_id", + combine = FALSE), + "It seems as if you are using data from different oTree versions") +}) + +testthat::test_that("extime (e) - starting value", { + # Prepare data + otree2 <- otree_all + namesbefore <- names(otree2$Time) + + # Run function + testthat::expect_error(extime(otree2, + combine = TRUE, + startat = 400), + "The chosen starting value startat") + + # Test + namesafter <- names(otree2$Time) + test1 <- length(namesbefore) == length(namesafter) # of course + testthat::expect_true(test1) +}) + +testthat::test_that("extime (e) - otree new - no session_id", { + # Prepare data + otree2 <- otree_5_4_0 + otree2 <- delete_duplicate(otree2) + + # Run function + testthat::expect_error( + extime(otree2, + combine = TRUE, + sinfo = "session_id"), + "no session_id in the") +}) + +testthat::test_that("extime (e) - no time stamp", { + otree2 <- otree_5_4_0 + otree2$Time$epoch_time_completed <- NULL + testthat::expect_error(extime(otree2), + "There is no variable") +}) + +testthat::test_that("extime (e) - no valid starttime", { + otree2 <- otree_5_4_0 + testthat::expect_error(extime(otree2, + startat = -3), + "Please choose a valid") +}) + +testthat::test_that("extime (e) - no paticipant var", { + otree2 <- otree_5_4_0 + otree2$Time$participant_code <- NULL + testthat::expect_error(extime(otree2), + "There is no variable") +}) + +print("---- apptime -----") +# App time #### +testthat::test_that("App time - all apps, seconds = FALSE", { + # Prepare data + otree2 <- otree_5_4_0 + + # Run function + output <- apptime(otree2, + sinfo = NULL) + + # Test + testthat::expect_output(str(output), "List of 6") + + # Important. In new oTree, there is no need for a first-app-one-stage + # warning, because there is a index number 0! + # Also: firstappwarning is also not shown for new oTree. + test1 <- !is.null(output$dictator$mean_duration) & + !is.na(output$dictator$mean_duration) + test2 <- !is.null(output$dictator$min_duration) & + !is.na(output$dictator$min_duration) + test3 <- !is.null(output$dictator$max_duration) & + !is.na(output$dictator$max_duration) + test4 <- (nrow(output$dictator$single_durations) + + length(output$dictator$warnings)) == nrow(otree2$dictator) / 3 + # Test if the values and the single_durations align + test5 <- round(output$dictator$min_duration, 2) == + round(min(output$dictator$single_durations$duration), 2) + test6 <- round(output$dictator$max_duration, 2) == + round(max(output$dictator$single_durations$duration), 2) + test7 <- round(output$dictator$mean_duration, 2) == + round(mean(output$dictator$single_durations$duration), 2) + testthat::expect_true(all(c(test1, test2, test3, test4, + test5, test6, test7))) +}) + +testthat::test_that("App time - all apps, without session info", { + # Prepare data + otree2 <- otree_5_4_0 + + # Run function + output <- apptime(otree2) + + # Test + testthat::expect_output(str(output), "List of 4") + # Test fi values are there + test1 <- !is.null(output$dictator$mean_duration) & + !is.na(output$dictator$mean_duration) + test2 <- !is.null(output$dictator$min_duration) & + !is.na(output$dictator$min_duration) + test3 <- !is.null(output$dictator$max_duration) & + !is.na(output$dictator$max_duration) + test4 <- (nrow(output$dictator$single_durations) + + length(output$dictator$warnings)) == nrow(otree2$dictator) / 3 + # Test if the values and the single_durations align + test5 <- round(output$dictator$min_duration, 2) == + round(min(output$dictator$single_durations$duration), 2) + test6 <- round(output$dictator$max_duration, 2) == + round(max(output$dictator$single_durations$duration), 2) + test7 <- round(output$dictator$mean_duration, 2) == + round(mean(output$dictator$single_durations$duration), 2) + # Test warnings + test8 <- + !(any(output$survey$first_app_one_page %in% output$survey$warnings)) + testthat::expect_true(all(c(test1, test2, test3, test4, + test5, test6, test7, test8))) +}) + +testthat::test_that("App time - all apps, seconds = TRUE", { + # Prepare data + otree2 <- otree_5_4_0 + + # Run function + output_second <- apptime(otree2, seconds = TRUE, digits = 4) + output_minutes <- apptime(otree2, seconds = FALSE, digits = 4) + + # Test + testthat::expect_output(str(output_second), "List of 4") + test1 <- + round(output_minutes$dictator$mean_duration * 60, 2) == + round(output_second$dictator$mean_duration, 2) + test2 <- + round(output_minutes$dictator$min_duration * 60, 2) == + round(output_second$dictator$min_duration, 2) + test3 <- + round(output_minutes$dictator$max_duration * 60, 2) == + round(output_second$dictator$max_duration, 2) + testthat::expect_true(all(c(test1, test2, test3))) +}) + +testthat::test_that("App time - all apps, old oTree", { + # Prepare data + otree2 <- otree_2_2_4 + otree2 <- make_ids(otree2) + + # Run function + output <- apptime(otree2, + sinfo = "session_id") + + # Test + testthat::expect_output(str(output$start), "List of 2") + testthat::expect_output(str(output), "List of 4") + + test1 <- grepl("Durations not calculated", output$start$message) + test2 <- is.vector(output$start$first_app_one_page) + nrow(otree2$dictator) # 36 / 3 = 12 + test3 <- !is.null(output$dictator$mean_duration) & + !is.na(output$dictator$mean_duration) + test4 <- !is.null(output$dictator$min_duration) & + !is.na(output$dictator$min_duration) + test5 <- !is.null(output$dictator$max_duration) & + !is.na(output$dictator$max_duration) + # Solche Tests gehen im alten oTree nicht, + # weil nicht alle Personen auch in der Time-File sind. + # test4 <- (nrow(output$dictator$single_durations) + + # length(output$dictator$warnings)) == nrow(otree2$dictator) / 3 + # Test if the values and the single_durations align + + test6 <- round(output$dictator$min_duration, 2) == + round(min(output$dictator$single_durations$duration), 2) + test7 <- round(output$dictator$max_duration, 2) == + round(max(output$dictator$single_durations$duration), 2) + test8 <- round(output$dictator$mean_duration, 2) == + round(mean(output$dictator$single_durations$duration), 2) + testthat::expect_true(all(c(test1, test2, test3, test4, + test5, test6, test7, test8))) +}) + +testthat::test_that("App time - one app", { + # Prepare data + otree2 <- otree_5_4_0 + + # Run function + output <- apptime(otree2, + "dictator") + + # Test + testthat::expect_output(str(output), "List of 6") + test1 <- !is.null(output$mean_duration) & + !is.na(output$mean_duration) + test2 <- !is.null(output$min_duration) & + !is.na(output$min_duration) + test3 <- !is.null(output$max_duration) & + !is.na(output$max_duration) + # Test if the values and the single_durations align + + test5 <- round(output$min_duration, 2) == + round(min(output$single_durations$duration), 2) + test6 <- round(output$max_duration, 2) == + round(max(output$single_durations$duration), 2) + test7 <- round(output$mean_duration, 2) == + round(mean(output$single_durations$duration), 2) + testthat::expect_true(all(c(test1, test2, test3, + test5, test6, test7))) +}) + +testthat::test_that("App time - one app", { + # Prepare data + otree2 <- otree_5_4_0 + + # Run function + output <- apptime(otree2, + "dictator") + + # Test + testthat::expect_output(str(output), "List of 6") + test1 <- !is.null(output$mean_duration) & + !is.na(output$mean_duration) + test2 <- !is.null(output$min_duration) & + !is.na(output$min_duration) + test3 <- !is.null(output$max_duration) & + !is.na(output$max_duration) + testthat::expect_true(all(c(test1, test2, test3))) + # Test if the values and the single_durations align + test5 <- round(output$min_duration, 2) == + round(min(output$single_durations$duration), 2) + test6 <- round(output$max_duration, 2) == + round(max(output$single_durations$duration), 2) + test7 <- round(output$mean_duration, 2) == + round(mean(output$single_durations$duration), 2) + testthat::expect_true(all(c(test1, test2, test3, + test5, test6, test7))) +}) + +testthat::test_that("App time - Time df empty", { + # Prepare data + otree2 <- otree_2_2_4 + otree2$Time <- otree2$Time[c(), ] + + # Run function and test + testthat::expect_error(apptime(otree2, + sinfo = NULL), + "data frame is empty") +}) + +testthat::test_that("App time - epoch time ", { + # Prepare data + otree2 <- otree_old_one + + # Run function + output <- apptime(otree2) + + # Test + testthat::expect_output(str(output), "List of 4") + + test1 <- "chatapp" %in% names(output) + test2 <- "survey" %in% names(output) + test3 <- "dictator" %in% names(output) + test4 <- "survey" %in% names(output) + testthat::expect_true(all(c(test1, test2, test3, test4))) + + # Test if the values and the single_durations align + test5 <- round(output$dictator$mean_duration, 2) == + round(min(output$dictator$single_durations$duration), 2) + test6 <- round(output$dictator$max_duration, 2) == + round(max(output$dictator$single_durations$duration), 2) + test7 <- round(output$dictator$mean_duration, 2) == + round(mean(output$dictator$single_durations$duration), 2) + testthat::expect_true(all(c(test1, test2, test3, + test5, test6, test7))) +}) + +testthat::test_that("App time - all apps old oTree specified person", { + # Prepare data + otree2 <- otree_2_2_4 + otree2 <- make_ids(otree2) + person <- otree_2_2_4$all_apps_wide$participant.code[ + otree_2_2_4$all_apps_wide$participant._current_app_name == "survey" + ][1] + + # Run function + output <- apptime(otree2, + pcode = person, + sinfo = "session_id") + + # Test + test1 <- is.numeric(output$chatapp) + test2 <- is.numeric(output$dictator) + test3 <- is.numeric(output$start) + + testthat::expect_true(all(c(test1, test2, test3))) + testthat::expect_output(str(output), "List of 4") +}) + +testthat::test_that("App time - all apps old oTree group", { + # Prepare data + otree2 <- otree_2_2_4 + otree2 <- make_ids(otree2, + gmake = TRUE, + from_var = "dictator.1.group.id_in_subsession") + + # Run function + output <- apptime(otree2, + group_id = 3, + sinfo = "session_id") + + # Test + test <- setequal(names(output), + c("chatapp", "dictator", "start", "survey")) + testthat::expect_true(test) + + # Test for start + test1 <- setequal(names(output$start), c("first_app_one_page", "message")) + testthat::expect_true(test1) + + # Test for chatapp + test1 <- is.numeric(output$chatapp$mean_duration) + test2 <- is.numeric(output$chatapp$max_duration) + test3 <- is.numeric(output$chatapp$min_duration) + test4 <- !is.null(output$chatapp$single_durations) + testthat::expect_true(all(c(test1, test2, test3, test4))) + + # Test for dictator + test1 <- is.numeric(output$dictator$mean_duration) + test2 <- is.numeric(output$dictator$max_duration) + test3 <- is.numeric(output$dictator$min_duration) + test4 <- !is.null(output$dictator$single_durations) + testthat::expect_true(all(c(test1, test2, test3, test4))) + + # Test for survey + test1 <- is.numeric(output$survey$mean_duration) + test2 <- is.numeric(output$survey$max_duration) + test3 <- is.numeric(output$survey$min_duration) + test4 <- !is.null(output$survey$single_durations) + testthat::expect_true(all(c(test1, test2, test3, test4))) +}) + +testthat::test_that("App time - all apps old oTree session code", { + # Prepare data + otree2 <- otree_2_2_4 + otree2 <- make_ids(otree2) + + # Run function and test + testthat::expect_error(apptime(otree2, sinfo = "session_code"), + "There is no session_code or session__code") +}) + +testthat::test_that("App time - all apps no session info ", { + # Prepare data + otree2 <- otree_2_2_4 + otree2 <- make_ids(otree2) + + # Run function + output <- apptime(otree2, sinfo = NULL) + + # Test + testthat::expect_output(str(output), "List of 4") + test1 <- setequal(names(output), c("chatapp", "dictator", "start", "survey")) + testthat::expect_true(test1) + + # Test for survey + test1 <- is.numeric(output$survey$mean_duration) + test2 <- is.numeric(output$survey$max_duration) + test3 <- is.numeric(output$survey$min_duration) + test4 <- is.null(output$survey$single_durations$session) + testthat::expect_true(all(c(test1, test2, test3, test4))) + + # Test for dictator + test1 <- is.numeric(output$dictator$mean_duration) + test2 <- is.numeric(output$dictator$max_duration) + test3 <- is.numeric(output$dictator$min_duration) + test4 <- is.null(output$dictator$single_durations$session) + testthat::expect_true(all(c(test1, test2, test3, test4))) + + # Test for start (only old otree not startreal) + test1 <- setequal(names(output$start), c("first_app_one_page", "message")) +}) + +testthat::test_that("App time - one app: one wrong app", { + # Prepare data + otree2 <- otree_5_4_0 + otree2 <- make_ids(otree2) + + # Run function and test + testthat::expect_error( + apptime(otree2, + apps = "wrongapp"), + "The apps specified in the argument apps are not in the") +}) + +testthat::test_that("App time - one app: no error one app okay", { + # Prepare data + otree2 <- otree_5_4_0 + otree2 <- make_ids(otree2) + + # Run function + testthat::expect_warning( + output <- apptime(otree2, + apps = c("wrongapp", "dictator")), + "not in the list of oTree data fram") + + # Test + testthat::expect_output(str(output), "List of 6") + test1 <- !is.null(output$mean_duration) & !is.na(output$mean_duration) + test2 <- !is.null(output$min_duration) & !is.na(output$min_duration) + test3 <- !is.null(output$max_duration) & !is.na(output$max_duration) + test4 <- exists("single_durations", output) + testthat::expect_true(all(c(test1, test2, test3, test4))) +}) + +testthat::test_that("App time - one app: single durations didnt make it", { + # Prepare data + otree2 <- otree_5_4_0 + otree2 <- make_ids(otree2) + + # Run function + output <- apptime(otree2, + pcode = "2scvem7a", + apps = "survey") + + # Test + test <- is.na(output) + testthat::expect_true(test) +}) + +testthat::test_that("App time - two apps: single durations didnt make it", { + # Prepare data + otree2 <- otree_5_4_0 + otree2 <- make_ids(otree2) + person <- otree2$all_apps_wide$participant.code[ + otree2$all_apps_wide$participant._current_app_name == "dictator"][1] + + # Run function + output <- apptime(otree2, + pcode = "2scvem7a", + apps = c("survey", "chatapp")) + + # Test + test1 <- setequal(names(output), c("survey", "chatapp")) + test2 <- is.na(output$chatapp) + test3 <- is.na(output$survey) + testthat::expect_true(all(c(test1, test2, test3))) +}) + +testthat::test_that("App time - all apps: single durations didnt make it", { + # Prepare data + otree2 <- otree_5_4_0 + otree2 <- make_ids(otree2) + person <- otree2$all_apps_wide$participant.code[ + otree2$all_apps_wide$participant._current_app_name == "dictator"][1] + + # Run function + output <- apptime(otree2, + pcode = person) + + # Test + test1 <- is.numeric(output$start) + test2 <- is.numeric(output$dictator) + test3 <- is.na(output$chatapp) + test4 <- is.na(output$survey) + testthat::expect_true(all(test1, test2, test3, test4)) +}) + +testthat::test_that("App time - one app: several durations didnt make it", { + # Prepare data + otree2 <- otree_5_4_0 + otree2 <- make_ids(otree2) + + # Run function + output <- apptime(otree2, + apps = "survey") + + # Test + test1 <- is.numeric(output$mean_duration) + test2 <- is.numeric(output$max_duration) + test3 <- is.numeric(output$min_duration) + test4 <- !is.null(output$single_durations) + test5 <- grepl("For some participants, no duration could", + output$messages) + test6 <- is.vector(output$warnings) + test7 <- !(output$warnings %in% output$single_durations) + testthat::expect_true(all(c(test1, test2, test3, + test4, test5, test6, + test7))) +}) + +testthat::test_that("App time - several apps: several didnt make it", { + # Prepare data + otree2 <- otree_5_4_0 + otree2 <- make_ids(otree2) + + # Run function + output <- apptime(otree2) + + # Test + warningmessage <- grepl("For some participants, no duration could", + output$survey$messages) + testthat::expect_true(warningmessage) + + sum1 <- nrow(output$survey$single_durations) + + length(output$survey$warnings) + sum2 <- nrow(output$dictator$single_durations) + + length(output$dictator$warnings) + sum3 <- nrow(output$chatapp$single_durations) + + length(output$chatapp$warnings) + + testthat::expect_true(sum1 == sum2) + testthat::expect_true(sum1 == sum3) + # Dictator should have more cases than survey + testthat::expect_gte(nrow(output$dictator$single_durations), + nrow(output$survey$single_durations)) +}) + +testthat::test_that("App time - one app oTree old", { + # Prepare data + otree2 <- otree_2_2_4 + otree2 <- make_ids(otree2) + + # Run function + output <- apptime(otree2, "dictator", sinfo = "session_id") + + # Test + testthat::expect_output(str(output), "List of 6") + test1 <- !is.null(output$mean_duration) & !is.na(output$mean_duration) + test2 <- !is.null(output$min_duration) & !is.na(output$min_duration) + test3 <- !is.null(output$max_duration) & !is.na(output$max_duration) + test4 <- exists("single_durations", output) + testthat::expect_true(all(c(test1, test2, test3, test4))) +}) + +testthat::test_that("App time - all duplicate participants", { + # Prepare data (make duplicate data) + otree2 <- otree_5_4_0 + otree2$Time <- rbind(otree2$Time, otree2$Time) + + # Run function + output <- apptime(otree2, + apps = "survey") + + # Test + test <- grepl("Durations not calculated", output$survey) + testthat::expect_true(test) +}) + +testthat::test_that("App time - all duplicate participants all apps", { + # Prepare data (make duplicate data) + otree2 <- otree_5_4_0 + otree2$Time <- rbind(otree2$Time, otree2$Time) + + # Run function + output <- apptime(otree2) + + # Test + test <- grepl("Durations not calculated", output$survey) + testthat::expect_true(test) +}) + +testthat::test_that("App time - one duplicate participant - all data one app", { + # Prepare data + otree2 <- otree_5_4_0 + person1 <- unique(otree2$Time$participant_code)[1] + + # Make duplicate data + otree2$Time <- rbind(otree2$Time, + otree2$Time[otree2$Time$participant_code == person1, ]) + + # Run function and test dictator + output <- apptime(otree2, + apps = "dictator") + + test0 <- all(output$duplicate_participants == person1) + test1 <- is.numeric(output$mean_duration) + test2 <- is.numeric(output$max_duration) + test3 <- is.numeric(output$min_duration) + + test4 <- all(output$duplicate_participants %in% (c(person1))) + test5 <- any(grepl("have duplicate data", output$messages)) + test6 <- any(grepl("no duration could be calculated", output$messages)) + + test7 <- !(output$single_durations$participant %in% + output$duplicate_participants) + test8 <- !(output$single_durations$participant %in% + output$warnings) + test9 <- !(output$duplicate_participants %in% + output$warnings) + test10 <- !(output$warnings %in% + output$duplicate_participants) + + testthat::expect_true(all(c(test0, test1, test2, test3, + test4, test5, test6, + test7, test8, test9, + test10))) + + # Run function and test start + output <- apptime(otree2, + apps = "start") + test0 <- all(output$duplicate_participants == person1) + test1 <- is.numeric(output$mean_duration) + test2 <- is.numeric(output$max_duration) + test3 <- is.numeric(output$min_duration) + test4 <- all(output$duplicate_participants %in% (c(person1))) + test5 <- any(grepl("have duplicate data", output$messages)) + + test7 <- !(output$single_durations$participant %in% + output$duplicate_participants) + test8 <- !("warnings" %in% names(output)) + + testthat::expect_true(all(c(test0, test1, test2, test3, + test4, test5, test6, + test7, test8))) +}) + +testthat::test_that("App time - some duplicate participants", { + # Prepare data (make duplicate data) + otree2 <- otree_5_4_0 + person1 <- unique(otree2$Time$participant_code)[1] + person2 <- unique(otree2$Time$participant_code)[2] + otree2$Time <- rbind(otree2$Time, + otree2$Time[otree2$Time$participant_code == person1, ], + otree2$Time[otree2$Time$participant_code == person2, ]) + + # Run function + output <- apptime(otree2, + apps = "dictator") + + # Test + test1 <- is.numeric(output$mean_duration) + test2 <- is.numeric(output$max_duration) + test3 <- is.numeric(output$min_duration) + test4 <- all(output$duplicate_participants %in% (c(person1, person2))) + test5 <- any(grepl("have duplicate data", output$messages)) + test6 <- any(grepl("no duration could be calculated", output$messages)) + test7 <- !(output$single_durations$participant %in% + output$duplicate_participants) + test8 <- !(output$single_durations$participant %in% + output$warnings) + test9 <- !(output$duplicate_participants %in% + output$warnings) + test10 <- !(output$warnings %in% + output$duplicate_participants) + + testthat::expect_true(all(c(test1, test2, test3, + test4, test5, test6, + test7, test8, test9, + test10))) +}) + +testthat::test_that("App time - a whole session not there", { + # Prepare data + otree2 <- otree_5_4_0 + otree2$Time$app_name[otree2$Time$app_name == "survey"] <- NA + + # Run function + output <- apptime(otree2) + + # Test + test <- grepl("Durations not calculated", output$survey) + testthat::expect_true(test) # Die überall schön machen +}) + +testthat::test_that("App time - participant is there more often ", { + # Prepare data + otree2 <- otree_5_4_0 + persons <- unique(otree2$Time$participant_code)[c(1, 2, 3, 4)] + + otree2$Time <- rbind(otree2$Time, + otree2$Time[ + otree2$Time$participant_code %in% persons, ]) + + # Run and test dictator + output <- apptime(otree2, + apps = "dictator") + test1 <- all(output$duplicate_participants == persons) + testthat::expect_true(test1) + test2 <- any(grepl("have duplicate data", output$messages)) + testthat::expect_true(test2) + test3 <- any(grepl("no duration could be calculated", output$messages)) + testthat::expect_true(test3) + + # Rund and test start + output <- apptime(otree2, + apps = "start") + test1 <- all(output$duplicate_participants == persons) + testthat::expect_true(test1) + test2 <- any(grepl("have duplicate data", output$messages)) + testthat::expect_true(test2) +}) + +testthat::test_that("App time - participant code", { + # Prepare data + otree2 <- otree_5_4_0 + + person1 <- unique(otree2$Time$participant_code[ + otree2$Time$page_index > 10])[1] + + # Expect + x <- otree2$Time[otree2$Time$participant_code == person1 & + otree2$Time$app_name == "dictator", ] + max <- max(x$epoch_time_completed) + + min <- min(x$epoch_time_completed) + min <- max(otree2$Time$epoch_time_completed[ + otree2$Time$participant_code == person1 & + otree2$Time$epoch_time_completed < min]) + + diff <- max - min + diff <- diff / 60 + + # Run function + output <- apptime(otree2, pcode = c(person1)) + + # Test + testthat::expect_equal( + output$dictator, + round(diff, digits = 2)) +}) + +testthat::test_that("App time - participant code not in any + combine yes", { + # Prepare data + otree2 <- otree_all + + # Run function + testthat::expect_warning( + output <- apptime(otree2, + combine = TRUE, + pcode = c("something")), + "referred to") + + # Test + test <- is.na(output$survey) + testthat::expect_true(test) +}) + +testthat::test_that("App time - two apps oTree old", { + # Prepare data + otree2 <- otree_2_2_4 + otree2 <- make_ids(otree2) + + # Run function + output <- apptime(otree2, + apps = c("survey", "dictator"), + sinfo = "session_id") + + # Test + testthat::expect_output(str(output), "List of 2") +}) + +testthat::test_that("App time - group", { + # Prepare data + otree2 <- otree_5_4_0 + otree2 <- make_ids(otree2, gmake = TRUE, from_app = "dictator") + + # Run function + output <- apptime(otree2, group_id = 2, apps = "dictator") + + # Test + test1 <- !is.null(output$mean_duration) & + !is.na(output$mean_duration) + test2 <- !is.null(output$min_duration) & + !is.na(output$min_duration) + test3 <- !is.null(output$max_duration) & + !is.na(output$max_duration) + test4 <- exists("single_durations", output) + test5 <- round(mean(output$single_durations$duration), + digits = 2) == output$mean_duration + + testthat::expect_true(all(c(test1, test2, + test3, test4, + test5))) +}) + +testthat::test_that("App time - one app durations not calculated", { + # Prepare data + otree2 <- otree_5_4_0 + # Keep only cases that didn't make it to the app + delcases <- otree2$all_apps_wide$participant.code[ + otree2$all_apps_wide$participant._current_app_name == "survey" + ] + otree2 <- delete_cases(otree2, + delcases, + reason = "test") + # Run function + output <- apptime(otree2, + apps = "survey") + + # Test + test1 <- setequal(names(output$survey), c("message")) + test2 <- grepl("Durations not calculated", output$survey$message) + + testthat::expect_true(all(c(test1, test2))) +}) + +testthat::test_that("App time - participant code not in any", { + # Prepare data + otree2 <- otree_all + + # Run function + testthat::expect_error( + output <- apptime(otree2, + combine = FALSE, + pcode = c("something")), + "referred to the time stamp.*referred to the participant code") +}) + +testthat::test_that("App time - participant label", { + # Prepare data + otree2 <- otree_5_4_0 + otree2 <- make_ids(otree2, pmake = TRUE) + + # Make new participant labels + otree2$all_apps_wide$participant.label <- + paste("Person", + data.table::rleidv(otree2$all_apps_wide$participant.code)) + + # Expect + person_code <- otree2$all_apps_wide$participant.code[ + otree2$all_apps_wide$participant._current_app_name == "survey" & + otree2$all_apps_wide$participant.label != ""][1] + + person_label <- otree2$all_apps_wide$participant.label[ + otree2$all_apps_wide$participant._current_app_name == "survey" & + otree2$all_apps_wide$participant.label != ""][1] + + # Comparison data frame + xminus1 <- max(otree2$Time[ + otree2$Time$participant_code == person_code & + otree2$Time$app_name == "chatapp", ]$epoch_time_completed) + + x <- otree2$Time[ + otree2$Time$participant_code == person_code & + otree2$Time$app_name == "survey", ] + + max <- max(x$epoch_time_completed) + + diff <- max - xminus1 + diff <- diff / 60 + + # Run function + output <- apptime(otree2, + plabel = person_label, + digits = 2) + + # Test + testthat::expect_equal( + output$survey, + round(diff, digits = 2)) +}) + +testthat::test_that("App time - two apps", { + # Prepare data + otree2 <- otree_5_4_0 + + # Run function + output <- apptime(otree2, + apps = c("survey", "dictator")) + + # Test + testthat::expect_output(str(output), "List of 2") + test1 <- !is.null(output$dictator$mean_duration) & + !is.na(output$dictator$mean_duration) + test2 <- !is.null(output$dictator$min_duration) & + !is.na(output$dictator$min_duration) + test3 <- !is.null(output$dictator$max_duration) & + !is.na(output$dictator$max_duration) + + test4 <- !is.null(output$survey$mean_duration) & + !is.na(output$survey$mean_duration) + test5 <- !is.null(output$survey$min_duration) & + !is.na(output$survey$min_duration) + test6 <- !is.null(output$survey$max_duration) & + !is.na(output$survey$max_duration) + + test7 <- exists("single_durations", output$dictator) + test8 <- exists("single_durations", output$survey) + + testthat::expect_true(test1) + testthat::expect_true(test2) + testthat::expect_true(test3) + testthat::expect_true(test4) + testthat::expect_true(test5) + testthat::expect_true(test6) + testthat::expect_true(test7) + testthat::expect_true(test8) +}) + +testthat::test_that("App time (e) - two apps no session_code - old", { + # Prepare data + otree2 <- otree_2_2_4 + + # Run function and test + testthat::expect_error( + apptime(otree2, + apps = c("survey", "dictator")), + "no session_code or session__code") +}) + +testthat::test_that("App time (e) - no group_id", { + # Prepare data + otree2 <- otree_5_4_0 + + # Run function and test + testthat::expect_error( + apptime(otree2, group_id = 6, apps = "dictator"), + "Variable group_id is not in \"Time\" data frame") +}) + +testthat::test_that("App time (e) - nonunique participant label", { + # Prepare data + otree2 <- otree_5_4_0 + + # Run function + testthat::expect_error( + apptime(otree2, + plabel = c("Person2")), + "You do not have unique participant labels in your") +}) + +testthat::test_that("App time (e) - app", { + # Prepare data + otree2 <- otree_5_4_0 + + # Run function + testthat::expect_error(apptime(otree2, apps = "Hinz")) +}) + +testthat::test_that("App time (e) - no epoch time old", { + # Prepare data + otree2 <- otree_old_one + otree2$Time$epoch_time <- NULL + + # Run function and test + testthat::expect_error(apptime(otree2), + "No variable referring to") +}) + +testthat::test_that("App time (e) - no participant code old", { + # Prepare data + otree2 <- otree_old_one + otree2$Time$participant_code <- NULL + + # Run function and test + testthat::expect_error(apptime(otree2), + "No variable referring to") +}) + +testthat::test_that("App time (e) - no Time data frame", { + # Prepare data + otree2 <- otree_5_4_0 + otree2$Time <- NULL + + # Run function and test + testthat::expect_error(apptime(otree2, + apps = "survey"), + "There is no") +}) + +testthat::test_that("App time (e) - wrong group_id", { + # Prepare data + otree2 <- otree_5_4_0 + otree2 <- make_ids(otree2, gmake = TRUE, + from_var = "dictator.1.group.id_in_subsession") + + # Run function and test + testthat::expect_error(apptime(otree2, + group_id = 400, + apps = "survey"), + "group_id is not in \"Time\" data frame") +}) + +testthat::test_that("App time (e) - participant.label and no all_apps_wide", { + # Prepare data + otree2 <- otree_5_4_0 + otree2$all_apps_wide <- NULL + + # Run function and test + testthat::expect_error(apptime(otree2, + plabel = "Person1", + apps = "survey"), + "You can only use") +}) + +testthat::test_that("App time (e) - no session_id in the Time data frame", { + # Prepare data + otree2 <- otree_5_4_0 + + # Run function and test + testthat::expect_error(apptime(otree2, + sinfo = "session_id", + apps = "survey"), + "There is no session_id in the Time data frame") +}) + +testthat::test_that("App time (e) - no session_id in the Time data frame", { + # Prepare data + otree2 <- otree_5_4_0 + + # Run function and test + testthat::expect_error(apptime(otree2, + sinfo = "session.id", + apps = "survey"), + "Please specify a valid sinfo") +}) + +testthat::test_that("App time (e) - only group or participant", { + # Prepare data + otree2 <- otree_5_4_0 + + # Run function and test + testthat::expect_error(apptime(otree2, + plabel = "Person1", + group_id = 1, + apps = "survey"), + "Please enter only") +}) + +testthat::test_that("App time (e) - specified duplicate participant", { + # Prepare data + otree2 <- otree_5_4_0 + + # Make duplicate data + person1 <- unique(otree2$Time$participant_code)[1] + otree2$Time <- rbind(otree2$Time, + otree2$Time[otree2$Time$participant_code == person1, ]) + + # Run function + testthat::expect_error( + apptime(otree2, + pcode = person1, + apps = "dictator"), + "This person has duplicate data in their Time data") +}) + +testthat::test_that("App time (e) - only participant.code or group_id", { + # Prepare data + otree2 <- otree_5_4_0 + + # Run function and test + testthat::expect_error(apptime(otree2, + pcode = "46kxib6w", + group_id = 1, + apps = "survey"), + "Please enter only pcode or group_id") +}) + +testthat::test_that("App time (e) - only p.label or p.code", { + # Prepare data + otree2 <- otree_5_4_0 + + # Run function and test + testthat::expect_error(apptime(otree2, + plabel = "Person1", + pcode = "46kxib6w", + apps = "survey"), + "Please enter only") +}) + +testthat::test_that("App time (e) - two participants (label)", { + # Prepare data + otree2 <- otree_5_4_0 + part <- c("xx78b3x0", "46kxib6w") + + # Run function and test + part <- c("Person1", "Person2") + testthat::expect_error( + apptime(otree2, + plabel = part), + "Please enter only one participant") +}) + +testthat::test_that("App time (e) - two participants (code)", { + # Prepare data + otree2 <- otree_5_4_0 + part <- c("xx78b3x0", "46kxib6w") + + # Run function and test + testthat::expect_error( + apptime(otree2, + pcode = part), + "Please enter only one participant") +}) + +print("---- pagesec -----") +# Page seconds #### +testthat::test_that("pagesec", { + # Run function + # Make minutes + otree2 <- pagesec(otree_5_4_0, minutes = TRUE) + # Make seconds + otree2 <- pagesec(otree2, minutes = FALSE) + + # Test + test1 <- mean(otree2$Time$minutes_on_page, + na.rm = TRUE) > 0 + + test2 <- mean(otree2$Time$seconds_on_page2, + na.rm = TRUE) > 0 + test3 <- all( + !is.na(otree2$Time$minutes_on_page) == + (!is.na(otree2$Time$seconds_on_page2) / 60)) + + testthat::expect_true(all(c(test1, test2, test3))) +}) + +testthat::test_that("pagesec - minutes ", { + # Run function + otree2 <- pagesec(otree_5_4_0, minutes = TRUE) + otree2 <- pagesec(otree_5_4_0, minutes = FALSE) + + # Test + variable <- otree2$Time$seconds_on_page2 + test1 <- mean(variable, na.rm = TRUE) > 0 + + test2 <- all( + !is.na(otree2$Time$minutes_on_page) == + !is.na(otree2$Time$seconds_on_page2 / 60)) + + testthat::expect_true(all(c(test1, test2))) +}) + +testthat::test_that("pagesec - oTree 2.2.4", { + # Prepare data + otree2 <- otree_2_2_4 + + # Run function + otree2 <- pagesec(otree2) + + # Test + testthat::expect_false(is.null(otree2$Time$seconds_on_page2)) + + test1 <- all(otree2$Time$seconds_on_page2[ + !is.na(otree2$Time$seconds_on_page2)] == + otree2$Time$seconds_on_page[!is.na(otree2$Time$seconds_on_page2)]) + + testthat::expect_true(test1) +}) + +testthat::test_that("pagesec - messy time", { + # Prepare data + otree2 <- otree_all + + # Run function + testthat::expect_warning( + otree2 <- pagesec(otree2, + minutes = TRUE, + combine = TRUE), + "referred to ") + + otree2 <- pagesec(otree2, + minutes = FALSE) + + # Test + test1 <- mean(otree2$Time$minutes_on_page, + na.rm = TRUE) > 0 + + test2 <- mean(otree2$Time$seconds_on_page2, + na.rm = TRUE) > 0 + test3 <- all( + otree2$Time$seconds_on_page2[!is.na(otree2$Time$seconds_on_page2) & + !is.na(otree2$Time$seconds_on_page)] == + otree2$Time$seconds_on_page[!is.na(otree2$Time$seconds_on_page2) & + !is.na(otree2$Time$seconds_on_page)]) + test4 <- all( + !is.na(otree2$Time$minutes_on_page) == + !is.na(otree2$Time$seconds_on_page2 / 60)) + + testthat::expect_true(all(c(test1, test2, test3, test4))) +}) + +testthat::test_that("pagesec (e) - messy time", { + # Prepare data + otree2 <- otree_all + + # Run function and test + testthat::expect_error( + pagesec(otree2, + minutes = TRUE), + "referred to the time stamp.*referred to the participant code") +}) + +testthat::test_that("pagesec (e) - no epoch time", { + # Prepare data + otree2 <- otree_5_4_0 + otree2$Time$epoch_time_completed <- NULL + + # Run function and test + testthat::expect_error( + pagesec(otree2, minutes = TRUE), + "no variable referring to the epoch time") +}) + +testthat::test_that("pagesec (e) - no participant code", { + # Prepare data + otree2 <- otree_5_4_0 + otree2$Time$participant_code <- NULL + + # Run function and test + testthat::expect_error( + pagesec(otree2, minutes = TRUE), + "no variable referring to the participant") +}) + +testthat::test_that("pagesec (e) - no Time files", { + # Prepare data + otree2 <- otree_5_4_0 + otree2$Time <- NULL + + # Run function and test + testthat::expect_error(pagesec(otree2), "No time data frame") +}) + +print("---- show_constant -----") +# Show constant #### +testthat::test_that("Show constant - empty ", { + # Prepare data + otree2 <- otree_5_4_0 + + # Run function + output <- show_constant(otree2, value = "donotfind") + + # Test + test1 <- "all_apps_wide" %in% names(output) + test2 <- "chatapp" %in% names(output) + test3 <- "dictator" %in% names(output) + test4 <- "start" %in% names(output) + test5 <- "survey" %in% names(output) + test6 <- "Time" %in% names(output) + test7 <- "Chats" %in% names(output) + testthat::expect_true(all(c(test1, test2, test3, test4, + test5, test6, test7))) + + test1 <- length(output$all_apps_wide) == 0 + test2 <- length(output$chatapp) == 0 + test3 <- length(output$dictator) == 0 + test4 <- length(output$start) == 0 + test5 <- length(output$survey) == 0 + test6 <- length(output$Time) == 0 + test7 <- length(output$Chats) == 0 + testthat::expect_true(all(c(test1, test2, test3, test4, + test5, test6, test7))) +}) + +testthat::test_that("Show constant - NA ", { + # Prepare data + otree2 <- otree_5_4_0 + + # Run function + output <- show_constant(otree2, value = NA) + + # Test + test1 <- "all_apps_wide" %in% names(output) + test2 <- "chatapp" %in% names(output) + test3 <- "dictator" %in% names(output) + test4 <- "start" %in% names(output) + test5 <- "survey" %in% names(output) + test6 <- "Time" %in% names(output) + test7 <- "Chats" %in% names(output) + testthat::expect_true(all(c(test1, test2, test3, test4, + test5, test6, test7))) +}) + +testthat::test_that("Show constant - any", { + # Run function + output <- show_constant(otree_5_4_0, value = "any") + + # Test + test1 <- "all_apps_wide" %in% names(output) + test2 <- "chatapp" %in% names(output) + test3 <- "dictator" %in% names(output) + test4 <- "start" %in% names(output) + test5 <- "survey" %in% names(output) + test6 <- "Time" %in% names(output) + test7 <- "Chats" %in% names(output) + testthat::expect_true(all(c(test1, test2, test3, test4, + test5, test6, test7))) +}) + +testthat::test_that("Show constant - -99", { + # Prepare data + otree2 <- otree_5_4_0 + otree2$all_apps_wide$constant_col <- -99 # Make fake column + + # Run function + output <- show_constant(otree2, value = -99) + + # Test + test1 <- "all_apps_wide" %in% names(output) + test2 <- "chatapp" %in% names(output) + test3 <- "dictator" %in% names(output) + test4 <- "start" %in% names(output) + test5 <- "survey" %in% names(output) + test6 <- "Time" %in% names(output) + test7 <- "Chats" %in% names(output) + testthat::expect_true(all(c(test1, test2, test3, test4, + test5, test6, test7))) + + test1 <- length(output$all_apps_wide) == 1 + test2 <- length(output$chatapp) == 0 + test3 <- length(output$dictator) == 0 + test4 <- length(output$start) == 0 + test5 <- length(output$survey) == 0 + test6 <- length(output$Time) == 0 + test7 <- length(output$Chats) == 0 + testthat::expect_true(all(c(test1, test2, test3, test4, + test5, test6, test7))) +}) + +testthat::test_that("Show constant (e) - only one value", { + # Run function and test + testthat::expect_error(show_constant(otree_5_4_0, + c(-99, NA)), + "Please only enter only one value") +}) + +testthat::test_that("Show constant (e) - valid value", { + # Run function and test + testthat::expect_error(show_constant(otree_5_4_0, + NULL), + "Please enter a valid value!") +}) + +print("---- assignv -----") +# Assign variable #### +testthat::test_that("Assign variable - new", { + # Prepare data + otree2 <- otree_5_4_0 + + # Run function + otree2 <- assignv(oTree = otree2, + variable = "survey.1.player.gender", + newvar = "gender") + # Test + testthat::expect_vector(otree2$survey$gender) +}) + +testthat::test_that("Assign variable - new, one random df", { + # Prepare data + otree2 <- otree_5_4_0 + otree2$random_dataframe <- data.frame( + a = c(1, 2, 3), + b = c(4, 5, 6), + c = c(7, 8, 9)) + + # Run function + otree2 <- assignv(oTree = otree2, + variable = "survey.1.player.gender", + newvar = "gender") + # Test + testthat::expect_vector(otree2$survey$gender) + testthat::expect_null(otree2$random_dataframe$gender) +}) + +testthat::test_that("Assign variable - old", { + # Prepare data + otree2 <- otree_2_2_4 + + # Run function + otree2 <- assignv(oTree = otree2, + variable = "survey.1.player.gender", + newvar = "gender") + # Test + testthat::expect_vector(otree2$survey$gender) +}) + +testthat::test_that("Assign variable - res after", { + # Prepare data + otree2 <- otree_5_4_0 + otree2$survey$younger30 <- ifelse(otree2$survey$player.age < 30, 0, 1) + + # Run function + otree2 <- assignv_to_aaw(otree2, + app = "survey", + variable = "younger30", + newvar = "younger30", + resafter = "survey.1.player.age") + + # Test + diff <- match("younger30", names(otree2$all_apps_wide)) - + match("survey.1.player.age", names(otree2$all_apps_wide)) + testthat::expect_equal(diff, 1) +}) + +testthat::test_that("Assign variable (e) - no aaw", { + # Prepare data + otree2 <- otree_5_4_0 + otree2$all_apps_wide <- NULL + + # Run function and test + testthat::expect_error(assignv(oTree = otree2, + variable = "survey.1.player.gender", + newvar = "gender"), + "There is no \"all_apps_wi") +}) + +testthat::test_that("Assign variable (e) - too many vars", { + # Prepare data + otree2 <- otree_5_4_0 + + # Run function and test + testthat::expect_error( + assignv(oTree = otree2, + variable = c("survey.1.player.gender", "asdfasfd"), + newvar = "gender"), "Plase enter only one variable name") +}) + +testthat::test_that("Assign variable (e) - too many vars", { + # Prepare data + otree2 <- otree_5_4_0 + + # Run function and test + testthat::expect_error( + assignv(oTree = otree2, + variable = c("survey.1.player.gender", "asdfasfd"), + newvar = c("gender", "asfasdf")), + "Plase enter only one variable name") +}) + +testthat::test_that("Assign variable (e) - too many newvars", { + # Prepare data + otree2 <- otree_5_4_0 + + # Run function and test + testthat::expect_error( + assignv(oTree = otree2, + variable = c("asdfasfd"), + newvar = c("gender", "asfasdf")), + "Plase enter only one new variable name") +}) + +testthat::test_that("Assign variable (e) - aaw not there", { + # Prepare data + otree2 <- otree_5_4_0 + otree2$survey$younger30 <- ifelse(otree2$survey$player.age < 30, 0, 1) + otree2$all_apps_wide <- NULL + + # Run function + testthat::expect_error( + otree2 <- assignv_to_aaw(otree2, + app = "survey", + variable = "younger30", + newvar = "younger30", + resafter = "survey.1.player.age"), "There is no") +}) + +testthat::test_that("Assign variable (e) - nonexistent variable", { + # Prepare data + otree2 <- otree_5_4_0 + + # Run function and test + testthat::expect_error( + assignv(oTree = otree2, + variable = "fake_variable", + newvar = "gender"), + "The variable does not exist") +}) + +print("---- assign to AAW ----") +# Assign to AAW #### +testthat::test_that("Assign variable to aaw", { + # Prepare data + otree2 <- otree_5_4_0 + + otree2$survey$younger30 <- + ifelse(otree2$survey$player.age < 30, 0, 1) + + # Run function + otree2 <- assignv_to_aaw(otree2, + app = "survey", + variable = "younger30", + newvar = "younger30") + + # Test + testthat::expect_vector(otree2$all_apps_wide$younger30) +}) + +testthat::test_that("Assign variable to aaw - random df", { + # Prepare data + otree2 <- otree_5_4_0 + otree2$random_dataframe <- data.frame( + a = c(1, 2, 3), + b = c(4, 5, 6), + c = c(7, 8, 9)) + + # Run function + testthat::expect_error( + otree2 <- assignv_to_aaw(otree2, + app = "random_dataframe", + variable = "a", + newvar = "a"), + "This function does not work with random_dataframe" + ) +}) + +testthat::test_that("Assign variable to aaw - one person missing", { + # Prepare data + otree2 <- otree_5_4_0 + otree2$survey$player.age[1] <- 15 # Make sure the first player has a value + person <- otree2$survey$participant.code[1] + otree2$survey$younger30 <- + ifelse(otree2$survey$player.age < 30, 0, 1) + otree2$survey <- otree2$survey[c(3:nrow(otree2$survey)), ] + + # Run function + testthat::expect_warning( + otree2 <- assignv_to_aaw(otree2, + app = "survey", + variable = "younger30", + newvar = "younger30"), + "However, there is an unequal number of participants") + + # Test + testthat::expect_vector(otree2$all_apps_wide$younger30) + testthat::expect_true(is.na(otree2$all_apps_wide$younger30[ + otree2$all_apps_wide$participant.code == person + ])) +}) + +testthat::test_that("Assign variable to aaw - all NA", { + # Prepare data + otree2 <- otree_5_4_0 + otree2$survey$younger30 <- NA + + # Run function + otree2 <- assignv_to_aaw(otree2, + app = "survey", + variable = "younger30", + newvar = "younger30") + + # Test + testthat::expect_vector(otree2$all_apps_wide$younger30) + testthat::expect_true(all(is.na(otree2$all_apps_wide$younger30))) +}) + +testthat::test_that("Assign variable to aaw (w)", { + # Prepare data + otree2 <- otree_5_4_0 + + # Create new variable + person <- otree2$survey$participant.code[1] + otree2$survey <- otree2$survey[c(2:nrow(otree2$survey)), ] # Delete first row + otree2$survey$younger30 <- ifelse(otree2$survey$player.age < 30, 0, 1) + + # Run function + testthat::expect_warning( + otree2 <- assignv_to_aaw(otree2, + app = "survey", + variable = "younger30", + newvar = "younger30"), + "unequal number of") + + # Test + testthat::expect_vector(otree2$all_apps_wide$younger30) + test1 <- is.na(otree2$all_apps_wide$younger30[ + otree2$all_apps_wide$participant.code == person]) + testthat::expect_true(test1) +}) + +testthat::test_that("Assign variable to aaw (e) - no aaw", { + # Prepare data + otree2 <- otree_5_4_0 + otree2$survey$younger30 <- ifelse(otree2$survey$player.age < 30, 0, 1) + otree2$survey$younger30 + otree2$all_apps_wide <- NULL + + # Run function and test + testthat::expect_error(assignv_to_aaw(otree2, + app = "survey", + variable = "younger30", + newvar = "younger30"), + "There is no \"all_apps_wide\" in your oTree") +}) + +testthat::test_that("Assign variable to aaw (e) - only one var", { + # Prepare data + otree2 <- otree_5_4_0 + otree2$survey$younger30 <- ifelse(otree2$survey$player.age < 30, 0, 1) + otree2$survey$younger30 + + # Run function and test + testthat::expect_error(assignv_to_aaw(otree2, + app = "survey", + variable = c("younger30", "asdfsadf"), + newvar = "younger30"), + "Plase enter only one variable name!") +}) + +testthat::test_that("Assign variable to aaw (e) - only one var and newvar", { + # Prepare data + otree2 <- otree_5_4_0 + otree2$survey$younger30 <- ifelse(otree2$survey$player.age < 30, 0, 1) + otree2$survey$younger30 + + # Run function and test + testthat::expect_error(assignv_to_aaw(otree2, + app = "survey", + variable = c("younger30", "asdfsadf"), + newvar = c("younger30", "asdfasdf")), + "Plase enter only one variable name!") +}) + +testthat::test_that("Assign variable to aaw (e) - only one newvar", { + # Prepare data + otree2 <- otree_5_4_0 + otree2$survey$younger30 <- ifelse(otree2$survey$player.age < 30, 0, 1) + otree2$survey$younger30 + + # Run function and test + testthat::expect_error(assignv_to_aaw(otree2, + app = "survey", + variable = c("younger30"), + newvar = c("younger30", "asdfasdf")), + "Plase enter only one new variable name!") +}) + +testthat::test_that("Assign variable to aaw (e) - nonexistent variable", { + # Prepare data + otree2 <- otree_5_4_0 + + # Run function and test + testthat::expect_error(assignv_to_aaw(otree2, + app = "survey", + variable = "fake_variable", + newvar = "younger30" + ), "The variable does not exist in the app") +}) + +testthat::test_that("Assign variable to aaw (e) - Chats", { + # Prepare data + otree2 <- otree_5_4_0 + + # Run function and test + testthat::expect_error(assignv_to_aaw(otree2, + app = "Chats", + variable = "nickname", + newvar = "nickname"), + "This function does not work with Chats") +}) + +print("---- delete_plabels ----") +# Delete participant labels #### +testthat::test_that("Delete participant labels", { + # Prepare data + otree2 <- otree_5_4_0 + + # Run function + otree2 <- delete_plabels(otree2) + + # Test + testthat::expect_null(otree2$all_apps_wide$participant.label) + testthat::expect_null(otree2$Time$participant_label) + testthat::expect_null(otree2$Time$participant__label) + testthat::expect_null(otree2$Chats$participant_label) + testthat::expect_null(otree2$Chats$participant__label) + testthat::expect_null(otree2$dictator$participant.label) + testthat::expect_null(otree2$survey$participant.label) +}) + +testthat::test_that("Delete participant labels - random df", { + # Prepare data + otree2 <- otree_5_4_0 + otree2$random_dataframe <- data.frame( + a = c(1, 2, 3), + b = c(4, 5, 6), + c = c(7, 8, 9)) + + # Run function + otree2 <- delete_plabels(otree2) + + # Test + testthat::expect_null(otree2$all_apps_wide$participant.label) + testthat::expect_null(otree2$Time$participant_label) + testthat::expect_null(otree2$Time$participant__label) + testthat::expect_null(otree2$Chats$participant_label) + testthat::expect_null(otree2$Chats$participant__label) + testthat::expect_null(otree2$dictator$participant.label) + testthat::expect_null(otree2$survey$participant.label) +}) +}) +} diff --git a/vignettes/intro_to_gmoTree.Rmd b/vignettes/intro_to_gmoTree.Rmd new file mode 100644 index 0000000..bbfc5c0 --- /dev/null +++ b/vignettes/intro_to_gmoTree.Rmd @@ -0,0 +1,479 @@ +--- +title: "Introduction to gmoTree" +author: "Patricia F. Zauchner" +date: "`r Sys.Date()`" +output: + rmarkdown::html_vignette: + toc: yes +vignette: > + %\VignetteIndexEntry{Introduction to gmoTree} + %\VignetteEngine{knitr::rmarkdown} + %\VignetteEncoding{UTF-8} +--- + +```{r collapse=TRUE, include=FALSE} +library(gmoTree) +``` + +Handling data from online experiments made with oTree (https://www.otree.org/) can be challenging, especially when dealing with complex experimental designs that span multiple sessions and return numerous files that must be combined. This is where the gmoTree package comes in. gmoTree is not an official package of the oTree team but is built to complement the oTree open-source platform. It helps streamline the data processing workflow by providing tools designed to import, merge, and manage data from oTree experiments. + +# Importing and cleaning up data + +## Background information on the data downloaded by oTree + +An oTree experiment is structured around one or more +modular units called 'apps,' which encompass one or multiple 'pages.' +Data generated from each app can be downloaded individually, +offering the flexibility to analyze separate components of the experiment. +For an all-encompassing view of the experiment, the data from all apps +can also be downloaded in a comprehensive file labeled 'all_apps_wide.' + +In addition to the aforementioned app data and the cumulative all_apps_wide +file, oTree generates a file with time stamps for every page. A file +documenting all chat interactions is also provided if the experiment +includes one or multiple chat rooms. In newer oTree versions, also custom +data can be downloaded. + +When an oTree experiment is run across different databases, this set of +data files is downloaded for each database. This would include individual +app data files, the all_apps_wide file, a file for the time stamps of every +page, and a chat log file if a chat room was used in the experiment. + +The gmoTree package's functionality lies in its ability to load and aggregate all of these files with ease. + +## import_otree() + +We can import all oTree data and combine them into a list of data frames +using the ```import otree() ``` function. +Each data frame is named according to its associated app, and the function +generates an accompanying info list that details essential information regarding +the imported files, such as any deleted cases. +This information list is updated as we use other functions within the package. + +It is worth noting that even if we only use one all_apps_wide file, +we should still load the data with ```import otree() ``` if we want to access other functions within the gmoTree package. Alternatively, we could reproduce the structure created by this function by hand. The following example shows how to import oTree data, the structure of the oTree list of data frames after importing the data, and all of the information provided in ```oTree$info```. + +```{r, collapse=TRUE} +# Get path to the package data +path <- system.file("extdata/exp_data_5.4.0", package = "gmoTree") + +# Import without specifications +# Import all oTree files in this folder and its subfolders +otree <- gmoTree::import_otree(path = path) + +# Check the structure of the oTree list of data frames +str(otree, 1) + +# The initial info list +otree$info +``` +Caution: This function only works if the oTree data is saved using the typical oTree file pattern! + +## delete_duplicate() + +Sometimes, the same data is imported several times. This could happen for several reasons. First, one data set might be part of another because of the download of temporarily stored data before downloading the final data frame. Second, if room-specific and global data is imported, the data in the ```all_apps_wide``` data frame are there two times. Third, the same data is stored in several imported folders. The function ```delete_duplicate()``` deletes duplicate data from all apps and ```all_apps_wide```. It, however, does not change the ```Time``` and ```Chats``` data frames. + +Before running the function, let us first check the number of participant codes and the initial count before executing the ```delete_duplicate()``` function. In the imported ```all_apps_wide``` data frame, we have 12 participant codes. However, among these, only 8 are unique, which indicates the presence of duplicate data. The ```info``` data frame suggests that there are initially 12 entries. + +```{r, collapse=TRUE} +# Initial check before deletion +length(otree$all_apps_wide$participant.code) +length(unique(otree$all_apps_wide$participant.code)) +otree$info$initial_n +``` + +To remove these duplicates, we employ the ```delete_duplicate()``` function: + +```{r, collapse=TRUE} +# Delete duplicate cases +otree <- delete_duplicate(otree) +``` + +Please note that details about the deleted rows are not added to a list of deleted cases. This is because the list might be used for analysis, and this function mainly focuses on cleaning up an untidy data import. However, the count in ```info$initial_n``` is adjusted accordingly. + +After the deletion operation, we should find that all participant codes are unique, and the count ```info$initial_n``` matches the number of unique participant codes. + +```{r, collapse=TRUE} +# Check participant codes and initial_n after deletion +length(otree$all_apps_wide$participant.code) +length(unique(otree$all_apps_wide$participant.code)) +otree$info$initial_n +``` + + +## Dealing with messy Chats and Time data frames + +If we combine data from experiments that ran on different versions of oTree, +it might happen that there are several variables referring to the same +attribute in the ```Time``` and in the ```Chats``` data frames. The functions ```messy_chat()``` and ```messy_time()``` integrate the corresponding variables if used with the argument ```combine = TRUE```. + +To show an example, let us first load data from different versions of oTree. + +```{r, collapse=TRUE} +# Import data from different oTree versions +otree_all <- gmoTree::import_otree( + path = system.file("extdata", package = "gmoTree")) + +# Check names of Time data frame +names(otree_all$Time) + +# Check names of Chats data frame +names(otree_all$Chats) +``` + +Now we can run the functions ```messy_time()``` and ```messy_chat()```. The warning messages are part of the expected output, indicating precisely which variables were combined. There is no need for concern when we see them. However, you can also turn them off using ```info = FALSE```. + +```{r, collapse=TRUE} +otree_all <- messy_time(otree_all, + combine = TRUE, + info = TRUE) +``` + +```{r, collapse=TRUE} +otree_all <- messy_chat(otree_all, + combine = TRUE, + info = TRUE) +``` + +```{r, collapse=TRUE} +# Check names of Time data frame again +names(otree_all$Time) + +# Check names of Chats data frame again +names(otree_all$Chats) +``` + + +# Dealing with dropouts and deleting cases + +## show_dropouts() + +Sometimes, participants drop out of experiments. To get an overview of +the dropouts, we can use the function ```show_dropouts()```. +It creates three data frames/tables with information on the participants +that did not finish at (a) certain app(s) or page(s). + +First, the function ```show_dropouts()``` creates a data frame ```full``` that provides specific information on the apps and pages where participants left the experiment prematurely. Additionally, this data frame indicates which apps were affected by the participants who dropped out. + +```{r show dropouts, collapse=TRUE} +# Show everyone that has not finished with the app "survey" +dropout_list <- show_dropouts(otree, "survey") + +head(dropout_list$full) +``` + +Second, the function ```show_dropouts()``` also generates a smaller data frame ```unique``` that only includes information on each person once. +```{r, collapse=TRUE} +dropout_list$unique +``` + +Third, the function ```show_dropouts()``` furthermore creates a table ```all_end```, which contains information on all participants and where they ended the experiment. The columns contain the names of the pages of the experiment; the rows contain the names of the apps. + +```{r, collapse=TRUE} +dropout_list$all_end +``` + + +## delete_dropouts() + +Normally, we want to exclude dropouts from our analysis. +The function ```delete_dropouts()``` removes all data related to participants +who prematurely terminated the experiment from the data frames +in the oTree list, except the data contained within the info list +and the ```Chats``` data frame. I highly recommend personally deleting the chat data because it can occasionally become unintelligible once one person's input is removed. Therefore, this function does not delete the chat input of the participants who dropped out of the experiment. + +Before running the example, let us first check the row numbers of some data frames. + +```{r, collapse=TRUE} +# First, check some row numbers +nrow(otree$all_apps_wide) +nrow(otree$survey) +nrow(otree$Time) +nrow(otree$Chats) +``` + +When we run the function ```delete_dropouts()``` and check the row numbers again, we see that cases were deleted in each data frame but not in the `Chats` data frame. + +```{r delete dropouts, collapse=TRUE} +# Delete all cases that didn't end the experiment on the page "Demographics" +# within the app "survey" +otree2 <- delete_dropouts(otree, + final_apps = c("survey"), + final_pages = c("Demographics"), + info = TRUE) + +# Check row numbers again +nrow(otree2$all_apps_wide) +nrow(otree2$survey) +nrow(otree2$Time) +nrow(otree2$Chats) + +``` + +Just as ```show_dropouts()```, the ```delete_dropouts()``` function also gives detailed information on all the deleted cases. + +```{r, collapse=TRUE} +head(otree2$info$deleted_cases$full) + + +otree2$info$deleted_cases$unique + + +otree2$info$deleted_cases$all_end +``` + +Caution: This function does not delete any data from the original +CSV and Excel files! + + +## delete_cases() + +Sometimes, participants ask for their data to be deleted. The ```delete_cases()``` function can delete a person from each app's data frame, ```all_apps_wide```, and the ```Time``` data frame. Again, data in the ```Chats``` data frame must be deleted by hand. + +```{r, collapse=TRUE} +# First, check some row numbers +nrow(otree2$all_apps_wide) +nrow(otree2$survey) +nrow(otree2$Time) +nrow(otree2$Chats) +``` + +```{r delete cases, collapse=TRUE} +# Delete one participant +person <- otree2$all_apps_wide$participant.code[1] +otree2 <- delete_cases(otree2, + pcodes = person, + reason = "requested", + saved_vars = "participant._index_in_pages", + info = TRUE) + +``` + +```{r, collapse=TRUE} +# Check row numbers again +nrow(otree2$all_apps_wide) +nrow(otree2$survey) +nrow(otree2$Time) +nrow(otree2$Chats) +``` + +This function adds the information of all these deleted cases to the previously created information on all deleted cases. + +```{r, collapse=TRUE} +# Check for all deleted cases (also dropouts): +tail(otree2$info$deleted_cases$full) +``` + + +Caution: This function does not delete any data from the original +CSV and Excel files! + +## delete_sessions() + +While we certainly hope that it never becomes necessary, there may be instances where an entire session needs to be removed from the data set due to unforeseen issues. However, if that occurs, we can use the function ```delete_sessions()```. +This function removes not only the sessions' data in all apps, ```all_apps_wide```, and the ```Time``` data frame but also the sessions' chat data in the ```Chats``` data frame because chatting is usually restricted within a session. + +In the following, we see the row numbers before deletion, the application of the function, and the row numbers after deletion. Apart from the other functions, the sessions' entries in the ```Chats``` data frame are destroyed here since chat data occurs just once per session and may thus be eliminated without impacting the comprehensibility of the chat data. + +```{r, collapse=TRUE} +# First, check some row numbers +nrow(otree2$all_apps_wide) +nrow(otree2$survey) +nrow(otree2$Time) +nrow(otree2$Chats) +``` + +```{r delete sessions, collapse=TRUE} +# Delete one session +otree2 <- delete_sessions(otree, + scodes = "jk9ekpl0", + reason = "Only tests", + info = TRUE) +``` + +```{r, collapse=TRUE} +# Check row numbers again +nrow(otree2$all_apps_wide) +nrow(otree2$survey) +nrow(otree2$Time) +nrow(otree2$Chats) +``` + + +# Deleting sensitive information + +## delete_pabels() + +It is not uncommon for the participant.label variable to contain sensitive information like an MTurk worker ID. This can raise serious privacy concerns. The function ```delete_plabels()``` automatically removes the ```participant.label``` variable from all data frames. Additionally, the function has the option to delete all MTurk-related variables. + +In the following, we see the application of the ```delete_plabels()``` function, preceded by information on the sensitive variables before running the function and followed by information on the sensitive variables after running the function. + +```{r delete plables, collapse=TRUE} +# Check variables +head(otree2$all_apps_wide$participant.label) +head(otree2$all_apps_wide$participant.mturk_worker_id) +head(otree2$survey$participant.label) + +# Delete all participant labels +otree2 <- delete_plabels(otree2, del_mturk = TRUE) + +# Check variables +head(otree2$all_apps_wide$participant.label) +head(otree2$all_apps_wide$participant.mturk_worker_id) +head(otree2$survey$participant.label) +``` + +Caution: This function does not delete the variable from the +original CSV and Excel files! + +# Making IDs + +## make_ids() + +When working with oTree, participant codes, session codes, and group IDs are used to identify the cases. However, often, researchers prefer a streamlined, consecutive numbering system that spans all sessions, beginning with the first participant, session, or group and concluding with the last. The ```make_ids()``` function provides a way to achieve this goal. Before using the function, let us inspect the underlying variables first. + + +```{r, collapse=TRUE} +# Check variables first +otree2$all_apps_wide$participant.code +otree2$all_apps_wide$session.code +otree2$all_apps_wide$dictator.1.group.id_in_subsession +``` + + +```{r, collapse=TRUE} +# Make session IDs only +otree2 <- make_ids(otree2) +``` + +This function returns the following variables. + +```{r, collapse=TRUE} +# Check variables +otree2$all_apps_wide$participant_id +otree2$all_apps_wide$session_id +``` + +In the prior example, Group IDs were not calculated because group IDs must be called specifically. Since the group IDs per app in our data do not match (groups are only relevant in the dictator app), just using `group_id = TRUE` would lead to an error message. + +For cases where the group IDs vary among apps, it can be specified in ```make_ids()``` which app or variable should be used for extracting group information. For instance, the following syntax can be used to obtain group IDs from the variable `dictator.1.group.id_in_subsession` in `all_apps_wide`. + +```{r, collapse=TRUE} +# Get IDs from "from_variable" in the data frame "all_apps_wide" +otree2 <- make_ids(otree2, + # gmake = TRUE, # Not necessary if from_var is not NULL + from_var = "dictator.1.group.id_in_subsession") +``` + +```{r, collapse=TRUE} +# Check variables +otree2$all_apps_wide$participant_id +otree2$all_apps_wide$group_id +otree2$all_apps_wide$session_id +``` + +# Calculating the time + +## apptime() + +If we need to determine how much time the participants spent on a specific app, the ````apptime()```` function is a powerful tool that can help. This function calculates summary statistics such as the mean, minimum, and maximum time spent on each page, as well as a detailed list of durations for each participant in the app. The following example shows how much time the participants spent on the app 'survey' in minutes. + +```{r apptime, collapse=TRUE} +# Calculate the time all participants spent on app "survey" +apptime(otree2, apps = "survey", digits = 3) +``` + +We can also get the time for specified individuals only. Without the specification of the apps, we get their durations for all apps individually. + +```{r apptime with participant, collapse=TRUE} +# Calculate the time one participant spent on app "dictator" +apptime(otree2, pcode = "c9inx5wl", digits = 3) +``` + +## extime() + +If we need to determine how much time participants spent on the complete experiment, we can use the ````extime()```` function. This function calculates summary statistics such as the mean, minimum, and maximum time spent on the experiment, as well as a detailed list of durations for each participant. (Note that these min, max, and mean values only have two digits because of the underlying data.) + +```{r extime, collapse=TRUE} +# Calculate the time that all participants spent on the experiment +extime(otree2, digits = 3) +``` + +We can also get the duration for just one participant. + +```{r extime with pcode, collapse=TRUE} +# Calculate the time one participant spent on the experiment +extime(otree2, pcode = "c9inx5wl", digits = 3) +``` + +## pagesec() + +The older versions of oTree included a variable called `seconds_on_page` in the `Time` data frame. Although there is a good reason to omit it, we sometimes want to have more detailed information on the time spent on one page. Therefore, I created the function ```pagesec()``` that adds a new variable `seconds_on_page2` to the `Time` data frame. + +```{r pagesec, collapse=TRUE} +# Create two new columns: seconds_on_page2 and minutes_on_page +otree2 <- pagesec(otree2, rounded = TRUE, minutes = TRUE) +tail(otree2$Time) +``` + +# Transferring variables between the apps + +## assignv() + +The function ```assignv()``` copies a variable from the `all_apps_wide` data frame to the data frames of all other apps. In the following example, the variable survey.1.player.gender is copied from `all_apps_wide` to all other app data frames; in all of these data frames, the new variable is named `gender`. It also copies the variable to `all_apps_wide` to keep some degree of consistency. + +```{r assignv, collapse=TRUE} +# Assign variable "survey.1.player.gender" and name it "gender" +otree2 <- assignv(oTree = otree2, + variable = "survey.1.player.gender", + newvar = "gender") +# Control +otree2$dictator$gender +otree2$chatapp$gender +# In app "survey", the variable is now twice because it is taken from here +otree2$survey$gender +otree2$survey$player.gender +# In app "all_apps_wide," the variable is also there twice +# (This can be avoided by calling the new variable the same +# as the old variable) +otree2$all_apps_wide$gender +otree2$all_apps_wide$survey.1.player.gender +``` + +## assignv_to_aaw() + +The function ```assignv_to_aaw()``` copies a variable from one of the data frames to the ```all_apps_wide``` data frame. In the following example, a variable from the app `survey` is copied to ```all_apps_wide``` and placed directly after the variable ```survey.1.player.age```. + +```{r assignv_to_aaw, collapse=TRUE} +# Create a new variable +otree2$survey$younger30 <- ifelse(otree2$survey$player.age < 30, 0, 1) + +# Get variable younger30 from survey to all_apps_wide +# and put the new variable right behind the old age variable +otree2 <- assignv_to_aaw(otree2, + app = "survey", + variable = "younger30", + newvar = "younger30", + resafter = "survey.1.player.age") + +# Control +otree2$all_apps_wide$survey.1.player.age + +# Check the position of the old age variable and the new variable +match("survey.1.player.age", colnames(otree2$all_apps_wide)) +match("younger30", colnames(otree2$all_apps_wide)) +``` + +# Before running the experiment + +## show_constant() + +When we program experiments, we frequently add variables that turn out to be useless later. When we forget to remove them, especially in experiments with numerous rounds, the data frame becomes unreasonably huge. With the function ```show_constant()```, we may identify variables that have no variation and remove them before the experiment. In the following example, a variable named ```constant``` is created, which does not vary. The function ```show_constant()``` shows us many variables that are also unchanging; however, we cannot delete most of them because they are oTree internal. Yet, to prevent an unreasonably large data frame, we should remove the variable ```constant``` before running the experiment. + +```{r show constant, collapse=TRUE} +# Make a constant column (this variable is usually created in oTree) +otree2$dictator$constant <- 3 + +# Show all columns that contain columns containing only one specified value +show_constant(oTree = otree2) +```