From 90f2f0e63b6cd2d749e9c5ab960d0413bf7f417a Mon Sep 17 00:00:00 2001 From: Alexander Christensen Date: Mon, 5 Oct 2020 09:39:35 -0400 Subject: [PATCH] CRAN 1.4.0 --- DESCRIPTION | 8 +- NAMESPACE | 2 + NEWS | 8 +- R/convert2snafu.R | 141 ++++++++++++ R/correct.changes.R | 13 +- R/open.clean.R | 26 +++ R/textcleaner.R | 74 +++++-- R/utils-SemNetCleaner.R | 466 +++++++++++++++++++++++++++------------- R/zzz.R | 4 +- data/open.clean.RData | Bin 0 -> 22479 bytes man/convert2snafu.Rd | 59 +++++ man/open.clean.Rd | 26 +++ man/textcleaner.Rd | 20 +- 13 files changed, 651 insertions(+), 196 deletions(-) create mode 100644 R/convert2snafu.R create mode 100644 R/open.clean.R create mode 100644 data/open.clean.RData create mode 100644 man/convert2snafu.Rd create mode 100644 man/open.clean.Rd diff --git a/DESCRIPTION b/DESCRIPTION index 9bd1c19..e1e447e 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,7 +1,7 @@ Package: SemNetCleaner Title: An Automated Cleaning Tool for Semantic and Linguistic Data -Version: 1.2.1 -Date: 2020-08-28 +Version: 1.3.0 +Date: 2020-09-23 Authors@R: c(person("Alexander P.", "Christensen", email = "alexpaulchristensen@gmail.com", role = c("aut", "cre"), comment = c(ORCID = "0000-0002-9798-7037"))) Maintainer: Alexander P. Christensen Description: Implements several functions that automates the cleaning and spell-checking of text data. Also converges, finalizes, removes plurals and continuous strings, and puts text data in binary format for semantic network analysis. Uses the 'SemNetDictionaries' package to make the cleaning process more accurate, efficient, and reproducible. @@ -12,7 +12,5 @@ NeedsCompilation: no Encoding: UTF-8 LazyData: true Depends: R (>= 3.6.0), SemNetDictionaries (>= 0.1.5) -Imports: stringdist, hunspell, searcher, tcltk, foreign, readxl, R.matlab, stringi -Suggests: knitr, rmarkdown, htmlTable -VignetteBuilder: knitr +Imports: stringdist, searcher, tcltk, foreign, readxl, R.matlab, stringi, rstudioapi, easycsv RoxygenNote: 7.1.1 diff --git a/NAMESPACE b/NAMESPACE index d5dac67..cbe3b6e 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -2,6 +2,7 @@ export(best.guess) export(bin2resp) +export(convert2snafu) export(correct.changes) export(pluralize) export(qwerty.dist) @@ -21,3 +22,4 @@ importFrom(utils,read.csv) importFrom(utils,read.table) importFrom(utils,setTxtProgressBar) importFrom(utils,txtProgressBar) +importFrom(utils,write.table) diff --git a/NEWS b/NEWS index 962a970..ee69238 100644 --- a/NEWS +++ b/NEWS @@ -1,4 +1,6 @@ -Changes in version 1.2.1 +Changes in version 1.4.0 + +o ADD: function to convert cleaned data to the SNAFU library's format in Python: `convert2snafu` o UPDATE: `correct.changes` included within `textcleaner` to streamline code for single function preprocessing @@ -6,6 +8,10 @@ o UPDATE: `edit` function added within the `correct.changes` function to allow m o UPDATE: change tracking has been added to `correct.changes` in the output (`$spellcheck$changes`) +o UPDATE: `textcleaner`'s help is now more helpful + +o UPDATE: text styling (face and color) are now adaptive to OS, software (R and RStudio), and RStudio theme + Changes in version 1.2.0 diff --git a/R/convert2snafu.R b/R/convert2snafu.R new file mode 100644 index 0000000..b7cfd80 --- /dev/null +++ b/R/convert2snafu.R @@ -0,0 +1,141 @@ +#' Pathfinder Network +#' +#' @description Estimates a pathfinder network using the MST-Pathfinder +#' Network method from Quirin et al. (2008; see also Schvaneveldt, 1990) +#' +#' @param ... Matrix or data frame. +#' A clean response matrices +#' +#' @param category Character. +#' Category of verbal fluency data +#' +#' @return A .csv file formatted for SNAFU +#' +#' @details The format of the file has 7 columns: +#' \itemize{ +#' \item{id}{Defaults to the row names of the inputted \code{data}} +#' +#' \item{listnum}{The list number for the fluency category. Defaults to 0. +#' Future implementations will allow more lists} +#' +#' \item{category}{The verbal fluency category that is input into the +#' \code{category} argument} +#' +#' \item{item}{The verbal fluency responses for every participant} +#' +#' \item{RT}{Response time. Currently not implemented. Defaults to 0} +#' +#' \item{RTstart}{Start of response time. Currently not implemented. Defaults to 0} +#' +#' \item{group}{Names of groups. Defaults to the names of the objects input into +#' the function (\code{...})} +#' } +#' +#' @examples +#' # Convert data to SNAFU +#' if(interactive()) +#' {convert2snafu(open.clean, category = "animals")} +#' +#' @references +#' # For SNAFU, see: +#' Zemla, J. C., Cao, K., Mueller, K. D., & Austerweil, J. L. (2020). +#' SNAFU: The Semantic Network and Fluency Utility. +#' \emph{Behavior Research Methods}, 1-19. +#' https://doi.org/10.3758/s13428-019-01343-w +#' +#' @author Alexander Christensen +#' +#' @importFrom utils write.table +#' +#' @export +# Convert data to SNAFU +# Updated 24.09.2020 +convert2snafu <- function (..., category) +{ + # Data list + data.list <- list(...) + + # Initialize snafu matrix + snafu.mat <- matrix(0, nrow = 0, ncol = 7) + colnames(snafu.mat) <- c("id", "listnum", "category", "item", "RT", "RTstart", "group") + + if(length(data.list) == 1) + { + + }else{ + + # Get group names + name <- as.character(substitute(list(...))) + name <- name[-which(name=="list")] + + for(i in 1:length(data.list)) + { + # Target data + target.data <- as.matrix(data.list[[i]]) + + # Number of possible responses + n <- ncol(target.data) + + # IDs + if(is.null(row.names(target.data))) + {id <- paste("A", 1:nrow(target.data), sep = "") + }else{id <- paste("A", formatC(as.numeric(row.names(target.data)), digits = 2, format = "d", flag = 0), sep = "")} + + for(j in 1:nrow(target.data)) + { + # Target participant + target.part <- target.data[j,] + + # Item + item <- na.omit(target.part) + + # Target ID + target.id <- rep(id[j], length(item)) + + # List number + listnum <- rep(0, length(item)) + + # Category + categorey <- rep(category, length(item)) + + # RT + RT <- rep(0, length(item)) + + # RTstart + RTstart <- rep(0, length(item)) + + # Group + group <- rep(name[i], length(item)) + + # Bind data + target.mat <- cbind(target.id, listnum, + categorey, item, + RT, RTstart, group) + + row.names(target.mat) <- NULL + colnames(target.mat) <- colnames(snafu.mat) + + # Append snafu matrix + snafu.mat <- rbind(snafu.mat, target.mat) + } + } + + } + + # Choose directory + DIR <- easycsv::choose_dir() + + # Get file name + FILENAME <- readline("Name of file: ") + + # Set up path + PATH <- paste(DIR, FILENAME, sep = "/") + PATH <- gsub("\\\\", "/", PATH) + PATH <- paste(PATH, "csv", sep = ".") + + write.table(snafu.mat, file = PATH, + quote = FALSE, sep = ",", row.names = FALSE) + + # Message to user + message(paste("SNAFU formatted file was saved in: "), PATH) +} diff --git a/R/correct.changes.R b/R/correct.changes.R index 34cbe64..a99afc2 100644 --- a/R/correct.changes.R +++ b/R/correct.changes.R @@ -81,7 +81,7 @@ #' @export #' # Correct changes---- -# Updated 21.08.2020 +# Updated 10.09.2020 # Major update: 19.04.2020 correct.changes <- function(textcleaner.obj) { @@ -94,7 +94,7 @@ correct.changes <- function(textcleaner.obj) readline("Press ENTER to continue...") - cat(colortext("\n\nThe first column of the spreadsheet corresponds to the", defaults = "message")) + cat(colortext("\nThe first column of the spreadsheet corresponds to the", defaults = "message")) cat(colortext("\nrow number provided in the output object `$spellcheck$correspondence`", defaults = "message")) cat(colortext("\n(see ?textcleaner for more information about this output).", defaults = "message")) @@ -146,14 +146,15 @@ correct.changes <- function(textcleaner.obj) for(i in 1:length(target.changes)) { ## Set up change matrix - chn.mat <- rbind(automated[target.changes[i],-1], changes[target.changes[i],-1]) - colnames(chn.mat) <- rep("to", ncol(chn.mat)) - row.names(chn.mat) <- c("Automated", "Corrected") + chn.mat <- rbind(automated[target.changes[i],], changes[target.changes[i],]) + colnames(chn.mat)[-1] <- rep("to", ncol(chn.mat)-1) + row.names(chn.mat) <- c("Previous", "Corrected") + chn.mat <- chn.mat[,-which(apply(chn.mat, 2, function(x){all(is.na(x))}))] track.changes[[automated[target.changes[i],1]]] <- chn.mat } - res$spellcheck$changes <- track.changes + res$spellcheck$verified <- track.changes ## Original is used (rather than corrected) to run through same preprocessing ## as in textcleaner (far more efficient than actually changing through each diff --git a/R/open.clean.R b/R/open.clean.R new file mode 100644 index 0000000..1f5cd4c --- /dev/null +++ b/R/open.clean.R @@ -0,0 +1,26 @@ +# Cleaned response Matrices (Openness and Verbal Fluency)---- +#' Cleaned response Matrices (Openness and Verbal Fluency) +#' +#' Cleaned response matrices for the Animals verbal fluency data (\emph{n} = 516) +#' from Christensen et al. (2018). +#' +#' @name open.clean +#' +#' @docType data +#' +#' @usage data(open.clean) +#' +#' @format open.clean (matrix, 516 x 35) +#' +#' @keywords datasets +#' +#' @references +#' Christensen, A. P., Kenett, Y. N., Cotter, K. N., Beaty, R. E., & Silvia, P. J. (2018). +#' Remotely close associations: Openness to experience and semantic memory structure. +#' \emph{European Journal of Personality}, \emph{32}, 480-492. +#' doi:\href{https://doi.org/10.1002/per.2157}{10.1002/per.2157} +#' +#' @examples +#' data("open.clean") +NULL +#---- \ No newline at end of file diff --git a/R/textcleaner.R b/R/textcleaner.R index 99a3ab5..ffe6fe5 100644 --- a/R/textcleaner.R +++ b/R/textcleaner.R @@ -26,18 +26,18 @@ #' Use \code{dictionaries()} or \code{find.dictionaries()} for more options #' (See \code{\link{SemNetDictionaries}} for more details) #' +#' @param add.path Character. +#' Path to additional dictionaries to be found. +#' DOES NOT search recursively (through all folders in path) +#' to avoid time intensive search. +#' Set to \code{"choose"} to open an interactive directory explorer +#' #' @param continue List. #' A result previously unfinished that still needs to be completed. #' Allows you to continue to manually spell-check their data #' after you've closed or errored out. #' Defaults to \code{NULL} #' -#' @param walkthrough Boolean. -#' Whether a walkthrough should be provided (recommended for first time users). -#' Defaults to \code{NULL}, which will ask whether you would like a walkthrough. -#' Set to \code{TRUE} to do the walkthrough. -#' Set to \code{FALSE} to skip the walkthrough -#' #' @return This function returns a list containing the following objects: #' #' \item{binary}{A matrix of responses where each row represents a participant @@ -48,11 +48,11 @@ #' #' \itemize{ #' -#' \item{clean} +#' \item{\code{clean}} #' {A response matrix that has been spell-checked and de-pluralized with duplicates removed. #' This can be used as a final dataset for analyses (e.g., fluency of responses)} #' -#' \item{original} +#' \item{\code{original}} #' {The original response matrix that has had white spaces before and #' after words response. Also converts all upper-case letters to lower case} #' @@ -116,13 +116,13 @@ #' #' @export # Text Cleaner---- -# Updated 21.08.2020 +# Updated 08.09.2020 # Major update: 19.04.2020 textcleaner <- function(data = NULL, miss = 99, partBY = c("row","col"), - dictionary = NULL, - continue = NULL, - walkthrough = NULL) + dictionary = NULL, add.path = NULL, + continue = NULL#, walkthrough = NULL + ) { # Check if user is continuing from a previous point if(is.null(continue)) @@ -182,7 +182,9 @@ textcleaner <- function(data = NULL, miss = 99, spell.check <- try( spellcheck.dictionary(uniq.resp = uniq.resp, dictionary = dictionary, - data = data, walkthrough = walkthrough), + add.path = add.path, + data = data#, walkthrough = walkthrough + ), silent <- TRUE ) @@ -251,7 +253,6 @@ textcleaner <- function(data = NULL, miss = 99, ## Make sure to replace faux "NA" with real NA corrected$corrected[which(corrected$corrected == "NA")] <- NA - res$responses$checked <- as.data.frame(corrected$corrected, stringsAsFactors = FALSE) ## Cleaned responses (no instrusions or perseverations) cleaned.list <- apply(corrected$corrected, 1, function(x){unique(na.omit(x))}) @@ -270,7 +271,6 @@ textcleaner <- function(data = NULL, miss = 99, res$responses$clean <- cleaned.matrix - # Convert to binary response matrix (error catch) res$responses$binary <- try( resp2bin(corrected$corrected), @@ -292,12 +292,52 @@ textcleaner <- function(data = NULL, miss = 99, class(res) <- "textcleaner" # Correct auto-corrections - res <- correct.changes(res) + res <- try(correct.changes(res), silent = TRUE) + + if(any(class(res) == "try-error")) + { + error.fun(res, "correct.changes", "textcleaner") + + return(res) + } # Let user know spell-check is complete Sys.sleep(1) message("\nPreprocessing complete.\n") - Sys.sleep(1) + Sys.sleep(2) + + # Let user know where to send their dictionaries and monikers + dictionary.output <- paste( + textsymbol("bullet"), + "Dictionary output: `OBJECT_NAME$dictionary`", + sep = " " + ) + + moniker.output <- paste( + textsymbol("bullet"), + "Moniker output: `OBJECT_NAME$spellcheck$manual`", + sep = " " + ) + + cat( + + colortext( + + paste( + "Consider submitting your dictionary and spelling corrections (i.e., monikers) to:\n\n", + "https://github.com/AlexChristensen/SemNetDictionaries/issues/new/choose\n\n", + dictionary.output, "\n\n", + moniker.output, "\n\n" + ), + + defaults = "message" + + ) + + ) + + Sys.sleep(2) + return(res) } diff --git a/R/utils-SemNetCleaner.R b/R/utils-SemNetCleaner.R index 45bbf50..8c886ed 100644 --- a/R/utils-SemNetCleaner.R +++ b/R/utils-SemNetCleaner.R @@ -897,8 +897,8 @@ appropriate.answer <- function (answer, choices, default, dictionary = FALSE) #' @noRd #' # Custom Menu---- -# Updated 12.04.2020 -customMenu <- function (choices, title = NULL, default, dictionary = FALSE) +# Updated 07.09.2020 +customMenu <- function (choices, title = NULL, default, dictionary = FALSE, help = FALSE) { if (!interactive()) {stop("menu() cannot be used non-interactively")} @@ -928,7 +928,7 @@ customMenu <- function (choices, title = NULL, default, dictionary = FALSE) { word <- fop[1:5] word <- paste0(word, c(rep.int(" ", min(nc, ncol) - - 1L), "\n"), collapse = "") + 1L), "\n"), collapse = "") # Check number of characters nw <- nchar(word) @@ -938,7 +938,7 @@ customMenu <- function (choices, title = NULL, default, dictionary = FALSE) string <- fop[6:10] string <- paste0(string, c(rep.int(" ", min(nc, ncol) - - 1L), "\n"), collapse = "") + 1L), "\n"), collapse = "") # Check number of characters ns <- nchar(string) @@ -957,41 +957,43 @@ customMenu <- function (choices, title = NULL, default, dictionary = FALSE) if(substr(def, n-1, n) != "\n") {def <- paste(substr(def, 1, n-2), "\n")} } + + # Set up responses + resp <- fop[(default + 1):length(fop)] + resp[1] <- paste0("\n", resp[1], collapse = "") + resp.len <- length(resp) + + # Check if length less than ncol + if(resp.len > ncol) + { + resp <- paste0(resp, c(rep.int(" ", min(nc, ncol) - 1L), "\n"), collapse = "") - # Set up responses - resp <- fop[(default + 1):length(fop)] - resp[1] <- paste0("\n", resp[1], collapse = "") - resp.len <- length(resp) + if((resp.len / ncol) %% 1 != 0) + {resp <- paste0(paste0(resp, collapse = ""), "\n")} - # Check if length less than ncol - if(resp.len > ncol) - { - resp <- paste0(resp, c(rep.int(" ", min(nc, ncol) - 1L), "\n"), collapse = "") - - if((resp.len / ncol) %% 1 != 0) - {resp <- paste0(paste0(resp, collapse = ""), "\n")} - - }else{resp <- paste0(paste0(resp, collapse = ""), "\n")} + }else{resp <- paste0(paste0(resp, collapse = ""), "\n")} + + # Set up options + if(default == 10) + { + op <- paste0(styletext("Word options\n", defaults = "underline"), word, + styletext("\nString options\n", defaults = "underline"), string, + styletext("\nResponse options", defaults = "underline"), resp, + collapse = "") - # Set up options - if(default == 10) - { - op <- paste0(styletext("Word options\n", defaults = "underline"), word, - styletext("\nString options\n", defaults = "underline"), string, - styletext("\nResponse options", defaults = "underline"), resp, - collapse = "") - - }else if(default == 5) - { - op <- paste0(styletext("Word options\n", defaults = "underline"), def, - styletext("\nResponse options", defaults = "underline"), resp, - collapse = "") - - }else{stop("Error in customMenu")} + }else if(default == 5) + { + op <- paste0(styletext("Word options\n", defaults = "underline"), def, + styletext("\nResponse options", defaults = "underline"), resp, + collapse = "") + }else{stop("Error in customMenu")} + }else{op <- c(op, "")} - cat("", op, sep = "\n") + if(!help) + {cat("", op, sep = "\n") + }else{paste0("", resp, sep = "")} } #' Interactive Manual Spell-check @@ -1041,7 +1043,7 @@ customMenu <- function (choices, title = NULL, default, dictionary = FALSE) #' @noRd #' # Menu for Manual Spell-check---- -# Updated 28.08.2020 +# Updated 07.09.2020 spellcheck.menu <- function (check, context = NULL, possible, original, current.index, changes, full.dictionary, category) { @@ -1081,7 +1083,7 @@ spellcheck.menu <- function (check, context = NULL, possible, original, ans <- readline(prompt = "Selection (accepts lowercase): ") # Check for user stoppage - if(tolower(ans) == "x") + if(tolower(ans) == "x" || ans == "") {return("STOP")} # Check for appropriate answer @@ -1332,7 +1334,7 @@ spellcheck.menu <- function (check, context = NULL, possible, original, }else if(ans == length(choices) + 2) # HELP { # Get `textcleaner` documentation - textcleaner_help() + textcleaner_help(check, context, original, possible) # Renew prompt ans <- 30 @@ -1384,13 +1386,13 @@ spellcheck.menu <- function (check, context = NULL, possible, original, customMenu(choices = choices, title = title, default = 5) # Message user - message("Press 'B' to GO BACK or 'esc' to STOP.\n") + message("Press 'B' to GO BACK, 'H' for HELP, or 'X' to EXIT.\n") # Present prompt - ans <- readline(prompt = "Select option (accepts lowercase): ") + ans <- readline(prompt = "Selection (accepts lowercase): ") # Check for user stoppage - if(ans == "") + if(tolower(ans) == "x" || ans == "") {return("STOP")} # Check for appropriate answer @@ -1501,7 +1503,7 @@ spellcheck.menu <- function (check, context = NULL, possible, original, }else if(ans == length(choices) + 2) # HELP { # Get `textcleaner` documentation - textcleaner_help() + textcleaner_help(check, context, original, possible) # Renew prompt ans <- 30 @@ -1565,7 +1567,7 @@ spellcheck.menu <- function (check, context = NULL, possible, original, error.fun <- function(result, SUB_FUN, FUN) { # Let user know that an error has occurred - message(paste("\nAn error has occured in the '", SUB_FUN, "' function of '", FUN, "':\n", sep ="")) + message(paste("\nAn error has occurred in the '", SUB_FUN, "' function of '", FUN, "':\n", sep ="")) # Give them the error to send to you cat(paste(result)) @@ -1585,7 +1587,7 @@ error.fun <- function(result, SUB_FUN, FUN) # To reproduce message(styletext("To Reproduce:", defaults = "bold")) - message(paste(" ", textsymbol("bullet"), " Function error occured in: ", SUB_FUN, " function of ", FUN, sep = "")) + message(paste(" ", textsymbol("bullet"), " Function error occurred in: ", SUB_FUN, " function of ", FUN, sep = "")) # R, SemNetCleaner, and SemNetDictionaries message(styletext("\nR, SemNetCleaner, and SemNetDictionaries versions:", defaults = "bold")) @@ -1610,6 +1612,11 @@ error.fun <- function(result, SUB_FUN, FUN) #' @param dictionary Character vector. #' See \code{\link{SemNetDictionaries}} #' +#' @param add.path Character. +#' Path to additional dictionaries to be found. +#' DOES NOT search recursively (through all folders in path) +#' to avoid time intensive search +#' #' @param data Matrix or data frame. #' A dataset of text data. #' Participant IDs will be automatically identified if they are included. @@ -1654,11 +1661,14 @@ error.fun <- function(result, SUB_FUN, FUN) #' #' @noRd # Manual spell-check---- -# Updated 21.08.2020 -spellcheck.dictionary <- function (uniq.resp = NULL, dictionary = NULL, - data = NULL, continue = NULL, - walkthrough = NULL) +# Updated 07.09.2020 +spellcheck.dictionary <- function (uniq.resp = NULL, dictionary = NULL, add.path = NULL, + data = NULL, continue = NULL#, walkthrough = NULL + ) { + # Line break function + linebreak <- function(){cat("\n", colortext(paste(rep("-", getOption("width")), collapse = ""), defaults = "message"), "\n")} + # Continuation check if(is.null(continue)) { @@ -1691,7 +1701,7 @@ spellcheck.dictionary <- function (uniq.resp = NULL, dictionary = NULL, # Load dictionaries ## Full dictionary - full.dictionary <- SemNetDictionaries::load.dictionaries(dictionary) + full.dictionary <- SemNetDictionaries::load.dictionaries(dictionary, add.path = add.path) ## Save original dictionary (to comparse against later) orig.dictionary <- full.dictionary @@ -1759,11 +1769,11 @@ spellcheck.dictionary <- function (uniq.resp = NULL, dictionary = NULL, data <- continue$data # Do not run through walkthrough - walkthrough <- FALSE + #walkthrough <- FALSE } # Check for walkthrough - walk_through(walkthrough) + walk_through(FALSE) # Set up progress bar (Windows only) if(Sys.info()["sysname"] == "Windows") @@ -1773,6 +1783,8 @@ spellcheck.dictionary <- function (uniq.resp = NULL, dictionary = NULL, invisible(tcltk::getTkProgressBar(pb)) }else{pb <- txtProgressBar(min = 0, max = length(ind), style = 3)} + linebreak() + # Loop through for manual spell-check while(main.count != (length(ind) + 1)) { @@ -1809,9 +1821,14 @@ spellcheck.dictionary <- function (uniq.resp = NULL, dictionary = NULL, silent = TRUE ) + linebreak() + ## Check for user stoppage or error if("STOP" %in% result) { + # Let user know their data is being saved + message("\nUser stopped. Saving progress...\n") + # Return the results res <- list() @@ -1834,6 +1851,11 @@ spellcheck.dictionary <- function (uniq.resp = NULL, dictionary = NULL, class(res) <- "textcleaner" + # Close progress bar + close(pb) + + Sys.sleep(2) + return(res) }else if(any(class(result) == "try-error")) @@ -1863,6 +1885,14 @@ spellcheck.dictionary <- function (uniq.resp = NULL, dictionary = NULL, class(res) <- "textcleaner" + # Close progress bar + close(pb) + + # Let user know their data is being saved + message("\nSaving progress...\n") + + Sys.sleep(2) + return(res) } @@ -1967,9 +1997,14 @@ spellcheck.dictionary <- function (uniq.resp = NULL, dictionary = NULL, ) + linebreak() + ## Check for user stoppage or error if("STOP" %in% result) { + # Let user know their data is being saved + message("\nUser stopped. Saving progress...\n") + # Return the results res <- list() @@ -1992,6 +2027,11 @@ spellcheck.dictionary <- function (uniq.resp = NULL, dictionary = NULL, class(res) <- "textcleaner" + # Close progress bar + close(pb) + + Sys.sleep(2) + return(res) }else if(any(class(result) == "try-error")) @@ -2022,6 +2062,14 @@ spellcheck.dictionary <- function (uniq.resp = NULL, dictionary = NULL, class(res) <- "textcleaner" + # Close progress bar + close(pb) + + # Let user know their data is being saved + message("\nSaving progress...\n") + + Sys.sleep(2) + return(res) } @@ -2397,34 +2445,56 @@ update.monikers <- function (word, monikers, monk.list) #' @author Alexander Christensen #' #' @noRd +#' # Color text---- -# Updated 24.04.2020 +# Updated 08.09.2020 colortext <- function(text, number = NULL, defaults = NULL) { - # Defaults for number (white text) - if(is.null(number) || number < 0 || number > 231) - {number <- 15} + # Check system + sys.check <- system.check() - - # Check for default color - if(!is.null(defaults)) + if(sys.check$TEXT) { - number <- switch(defaults, - message = 204, - highlight = 226, - red = 9, - orange = 208, - yellow = 11, - "light green" = 10, - green = 34, - cyan = 14, - blue = 12, - magenta = 13, - pink = 211, - ) - } - - return(paste("\033[38;5;", number, "m", text, "\033[0m", sep = "")) + # Defaults for number (white text) + if(is.null(number) || number < 0 || number > 231) + {number <- 15} + + # Check for default color + if(!is.null(defaults)) + { + # Adjust highlight color based on background color + if(defaults == "highlight") + { + if(sys.check$RSTUDIO) + { + + if(rstudioapi::getThemeInfo()$dark) + {number <- 226 + }else{number <- 208} + + }else{number <- 208} + }else{ + + number <- switch(defaults, + message = 204, + red = 9, + orange = 208, + yellow = 11, + "light green" = 10, + green = 34, + cyan = 14, + blue = 12, + magenta = 13, + pink = 211, + ) + + } + + } + + return(paste("\033[38;5;", number, "m", text, "\033[0m", sep = "")) + + }else{return(text)} } #' Stylizes Text @@ -2440,26 +2510,32 @@ colortext <- function(text, number = NULL, defaults = NULL) #' #' @noRd # Style text---- -# Updated 24.04.2020 +# Updated 08.09.2020 styletext <- function(text, defaults = c("bold", "italics", "highlight", "underline", "strikethrough")) { - if(missing(defaults)) - {number <- 0 - }else{ - - # Get number code - number <- switch(defaults, - bold = 1, - italics = 3, - underline = 4, - highlight = 7, - strikethrough = 9 - ) - - } + # Check system + sys.check <- system.check() - return(paste("\033[", number, ";m", text, "\033[0m", sep = "")) + if(sys.check$TEXT) + { + if(missing(defaults)) + {number <- 0 + }else{ + + # Get number code + number <- switch(defaults, + bold = 1, + italics = 3, + underline = 4, + highlight = 7, + strikethrough = 9 + ) + + } + + return(paste("\033[", number, ";m", text, "\033[0m", sep = "")) + }else{return(text)} } #' Text Symbols @@ -2904,8 +2980,6 @@ walk_through <- function(walkthrough) #' #' Provides a help for the options you can use to spell-check responses #' -#' @param ... Additional arguments -#' #' @return NULL #' #' @author Alexander Christensen @@ -2913,26 +2987,62 @@ walk_through <- function(walkthrough) #' @noRd #' # Help---- -# Updated 24.04.2020 -textcleaner_help <- function(...) +# Updated 07.09.2020 +textcleaner_help <- function(check, context, original, possible) { linebreak <- function(){cat("\n\n", colortext(paste(rep("-", getOption("width")), collapse = ""), defaults = "message"), "\n")} linebreak() - cat(paste("\n", "Original response:\n", - colortext(paste(" ", textsymbol("bullet"), " Refers to the original response that the participant typed", sep = ""), defaults = "message"), - "\n", - sep = "") - ) + help_art <- c(" _ _ _ _ _ ", + "| |_ _____ _| |_ ___| | ___ __ _ _ __ ___ _ __ | |__ ___| |_ __ ", + "| __/ _ \\ \\/ / __/ __| |/ _ \\/ _` | '_ \\ / _ \\ '__| | '_ \\ / _ \\ | '_ \\ ", + "| || __/> <| || (__| | __/ (_| | | | | __/ | | | | | __/ | |_) | ", + " \\__\\___/_/\\_\\\\__\\___|_|\\___|\\__,_|_| |_|\\___|_| |_| |_|\\___|_| .__/ ", + " |_| ") - cat(paste("\n", "Auto-corrected response:\n", - colortext(paste(" ", textsymbol("bullet"), " Refers to the response that the automated spell-check derived", sep = ""), defaults = "message"), - "\n", - sep = "") - ) + cat(help_art, sep = "\n") + + linebreak <- function(){cat("", colortext(paste(rep("-", getOption("width")), collapse = ""), defaults = "message"), "\n")} - cat(paste("\n", "Response to manually spell-check: '", colortext("catdog", defaults = "highlight"), "'\n", + linebreak() + + linebreak <- function(){cat("\n\n", colortext(paste(rep("-", getOption("width")), collapse = ""), defaults = "message"), "\n")} + + Sys.sleep(2) + + if(!is.null(context)) + { + cat(paste("\n", "Original response:\n\n", + paste("'", original, "'", sep = ""), "\n\n", + colortext(paste(" ", textsymbol("bullet"), " Refers to the original response that the participant typed", sep = ""), defaults = "message"), + "\n", + sep = "") + ) + + cat(paste("\n", "Auto-corrected response:\n\n", + paste("'", context, "'", sep = "", collapse = " "), "\n\n", + colortext(paste(" ", textsymbol("bullet"), " Refers to the response that the automated spell-check derived", sep = ""), defaults = "message"), + "\n", + sep = "") + ) + + # Choices for spell-check + word <- c("SKIP WORD", "ADD WORD TO DICTIONARY", "TYPE MY OWN WORD", "GOOGLE WORD", "BAD WORD") + string <- c("KEEP ORIGINAL", "KEEP AUTO-CORRECT", "TYPE MY OWN STRING", "GOOGLE STRING", "BAD STRING") + + choices <- c(word, string, possible) + + check <- context[check] + + }else{ + + # Choices for spell-check + choices <- c("SKIP", "ADD TO DICTIONARY", "TYPE MY OWN", "GOOGLE IT", "BAD WORD", possible) + + } + + cat(paste("\n", "Response to manually spell-check: '", colortext(check, defaults = "highlight"), "'\n", paste( colortext(paste(" ", textsymbol("bullet"), " Refers to the ", sep = ""), defaults = "message"), styletext(colortext("target", defaults = "message"), defaults = "italics"), @@ -2945,81 +3055,95 @@ textcleaner_help <- function(...) linebreak() cat(paste("\n", "1: SKIP WORD\n", - colortext(paste(" ", textsymbol("bullet"), " Keeps word 'as is' and moves on to next word to be spell-checked", sep = ""), defaults = "message"), + colortext(paste(" ", textsymbol("bullet"), " Keeps the target response 'as is' and moves on to next word to be spell-checked", sep = ""), defaults = "message"), "\n", sep = "") ) cat(paste("\n", "2: ADD WORD TO DICTIONARY\n", - colortext(paste(" ", textsymbol("bullet"), " Adds word to dictionary for future spell-checking", sep = ""), defaults = "message"), + colortext(paste(" ", textsymbol("bullet"), " Adds the target response to dictionary for future spell-checking", sep = ""), defaults = "message"), "\n", sep = "") ) cat(paste("\n", "3: TYPE MY OWN WORD\n", - colortext(paste(" ", textsymbol("bullet"), " Allows you to type your own correction for the word", sep = ""), defaults = "message"), + colortext(paste(" ", textsymbol("bullet"), " Allows you to type your own correction for the target response", sep = ""), defaults = "message"), "\n", sep = "") ) cat(paste("\n", "4: GOOGLE WORD\n", - colortext(paste(" ", textsymbol("bullet"), " Opens your default browser and 'Googles' the word", sep = ""), defaults = "message"), + colortext(paste(" ", textsymbol("bullet"), " Opens your default browser and 'Googles' the target response", sep = ""), defaults = "message"), "\n", sep = "") ) cat(paste("\n", "5: BAD WORD\n", - colortext(paste(" ", textsymbol("bullet"), " Marks the word as an inappropriate response (NA)", sep = ""), defaults = "message"), + colortext(paste(" ", textsymbol("bullet"), " Marks the target response as an inappropriate response (NA)", sep = ""), defaults = "message"), sep = "") ) linebreak() - cat(paste("\n", "6: KEEP ORIGINAL\n", - paste(colortext(paste(" ", textsymbol("bullet"), " Reverts the string back to the", sep = ""), defaults = "message"), - "Original response:", - colortext("the participant provided.", defaults = "message")), - "\n", sep = "" - ) - ) - - cat(paste("\n", "7: KEEP AUTO-CORRECT\n", - paste(colortext(paste(" ", textsymbol("bullet"), " Keeps the string 'as is' with the", sep = ""), defaults = "message"), - "Auto-correct response:", - colortext("provided by the automated spell-check.", defaults = "message")), - "\n", sep = "" - ) - ) - - cat(paste("\n", "8: TYPE MY OWN STRING\n", - paste(colortext(paste(" ", textsymbol("bullet"), " Allows you to type your own correction for the", sep = ""), defaults = "message"), - "Original response:", - colortext("the participant provided.", defaults = "message")), - "\n", sep = "" - ) - ) - - cat(paste("\n", "9: GOOGLE STRING\n", - paste(colortext(paste(" ", textsymbol("bullet"), " Opens your default browser and 'Googles' the", sep = ""), defaults = "message"), - "Original response:", - colortext("the participant provided.", defaults = "message")), - "\n", sep = "" - ) - ) - - cat(paste("\n", "10: BAD STRING\n", - colortext(paste(" ", textsymbol("bullet"), " Marks the entire string as an inappropriate response (NA)", sep = ""), defaults = "message"), - sep = "" - ) - ) - - linebreak() - - cat(paste("\n", styletext("Response options\n", defaults = "underline"), - paste(colortext(paste(" ", textsymbol("bullet"), " Potential options based on `textcleaner`'s best guess (letters correspond to the response)", sep = ""), defaults = "message")), - "\n", sep = "" - ) - ) + if(!is.null(context)) + { + cat(paste("\n", "6: KEEP ORIGINAL\n", + paste(colortext(paste(" ", textsymbol("bullet"), " Reverts the string back to the", sep = ""), defaults = "message"), + "Original response:", + colortext("the participant provided", defaults = "message")), + "\n", sep = "" + ) + ) + + cat(paste("\n", "7: KEEP AUTO-CORRECT\n", + paste(colortext(paste(" ", textsymbol("bullet"), " Keeps the string 'as is' with the", sep = ""), defaults = "message"), + "Auto-correct response:", + colortext("provided by the automated spell-check", defaults = "message")), + "\n", sep = "" + ) + ) + + cat(paste("\n", "8: TYPE MY OWN STRING\n", + paste(colortext(paste(" ", textsymbol("bullet"), " Allows you to type your own correction for the", sep = ""), defaults = "message"), + "Original response:", + colortext("the participant provided", defaults = "message")), + "\n", sep = "" + ) + ) + + cat(paste("\n", "9: GOOGLE STRING\n", + paste(colortext(paste(" ", textsymbol("bullet"), " Opens your default browser and 'Googles' the", sep = ""), defaults = "message"), + "Original response:", + colortext("the participant provided", defaults = "message")), + "\n", sep = "" + ) + ) + + cat(paste("\n", "10: BAD STRING\n", + colortext(paste(" ", textsymbol("bullet"), " Marks the entire string as an inappropriate response (NA)", sep = ""), defaults = "message"), + sep = "" + ) + ) + + linebreak() + + cat(paste("\n", styletext("Response options\n", defaults = "underline"), + customMenu(choices = choices, title = NULL, default = 10, help = TRUE), "\n", + paste(colortext(paste(" ", textsymbol("bullet"), " Potential options based on `textcleaner`'s best guess (letters correspond to the response)", sep = ""), defaults = "message")), + "\n", sep = "" + ) + ) + + }else{ + + cat(paste("\n", styletext("Response options\n", defaults = "underline"), + customMenu(choices = choices, title = NULL, default = 5, help = TRUE), "\n", + paste(colortext(paste(" ", textsymbol("bullet"), " Potential options based on `textcleaner`'s best guess (letters correspond to the response)", sep = ""), defaults = "message")), + "\n", sep = "" + ) + ) + + } cat(paste("\n'B'\n", paste(colortext(paste(" ", textsymbol("bullet"), " Takes you back to the previous response (use if you make a mistake or just want to go back)", sep = ""), defaults = "message")), @@ -3033,7 +3157,7 @@ textcleaner_help <- function(...) ) ) - cat(paste("\n'esc'\n", + cat(paste("\n'X'\n", paste(colortext(paste(" ", textsymbol("bullet"), " Exits textcleaner completely but saves your output", sep = ""), defaults = "message")), "\n", sep = "" ) @@ -3229,4 +3353,36 @@ permn<- function(x, fun = NULL, ...) ip[m] <- tmp } out -} \ No newline at end of file +} + +#' System check for OS and RSTUDIO +#' +#' @description Checks for whether text options are available +#' +#' @param ... Additional arguments +#' +#' @return \code{TRUE} if text options are available and \code{FALSE} if not +#' +#' @author Alexander Christensen +#' +#' @noRd +# System Check---- +# Updated 08.09.2020 +system.check <- function (...) +{ + OS <- unname(tolower(Sys.info()["sysname"])) + + RSTUDIO <- ifelse(Sys.getenv("RSTUDIO") == "1", TRUE, FALSE) + + TEXT <- TRUE + + if(!RSTUDIO){if(OS != "linux"){TEXT <- FALSE}} + + res <- list() + + res$OS <- OS + res$RSTUDIO <- RSTUDIO + res$TEXT <- TEXT + + return(res) +} diff --git a/R/zzz.R b/R/zzz.R index 736dd15..7d97b25 100644 --- a/R/zzz.R +++ b/R/zzz.R @@ -3,8 +3,8 @@ .onAttach <- function(libname, pkgname) { - msg <- paste('For help getting started, type `browseVignettes("SemNetCleaner")` \n') + msg <- paste('\nFor help getting started, see \n') msg <- paste(msg,"For bugs and errors, submit an issue to \n\n") - msg <- paste(msg, "WARNING: There have been major updates to the SemNetCleaner package.\n Please see 'Package NEWS' for a detailed list of updates", sep = "") + msg <- paste(msg, "WARNING: There have been major updates to the SemNetCleaner package.\n Please see 'Package NEWS' for a detailed list of updates\n", sep = "") packageStartupMessage(msg) } \ No newline at end of file diff --git a/data/open.clean.RData b/data/open.clean.RData new file mode 100644 index 0000000000000000000000000000000000000000..37609be475621ac2da60ad08a4f3243464bdf572 GIT binary patch literal 22479 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%0AT_bQufxJ1DrJ89CWt&w==`u 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.{hR_M4G$@+qZa!5Ytcr9rnU^!K1K_D=Og--JZ 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 literal 0 HcmV?d00001 diff --git a/man/convert2snafu.Rd b/man/convert2snafu.Rd new file mode 100644 index 0000000..f2769ae --- /dev/null +++ b/man/convert2snafu.Rd @@ -0,0 +1,59 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/convert2snafu.R +\name{convert2snafu} +\alias{convert2snafu} +\title{Pathfinder Network} +\usage{ +convert2snafu(..., category) +} +\arguments{ +\item{...}{Matrix or data frame. +A clean response matrices} + +\item{category}{Character. +Category of verbal fluency data} +} +\value{ +A .csv file formatted for SNAFU +} +\description{ +Estimates a pathfinder network using the MST-Pathfinder +Network method from Quirin et al. (2008; see also Schvaneveldt, 1990) +} +\details{ +The format of the file has 7 columns: +\itemize{ +\item{id}{Defaults to the row names of the inputted \code{data}} + +\item{listnum}{The list number for the fluency category. Defaults to 0. +Future implementations will allow more lists} + +\item{category}{The verbal fluency category that is input into the +\code{category} argument} + +\item{item}{The verbal fluency responses for every participant} + +\item{RT}{Response time. Currently not implemented. Defaults to 0} + +\item{RTstart}{Start of response time. Currently not implemented. Defaults to 0} + +\item{group}{Names of groups. Defaults to the names of the objects input into +the function (\code{...})} +} +} +\examples{ +# Convert data to SNAFU +if(interactive()) +{convert2snafu(open.clean, category = "animals")} + +} +\references{ +# For SNAFU, see: +Zemla, J. C., Cao, K., Mueller, K. D., & Austerweil, J. L. (2020). +SNAFU: The Semantic Network and Fluency Utility. +\emph{Behavior Research Methods}, 1-19. +https://doi.org/10.3758/s13428-019-01343-w +} +\author{ +Alexander Christensen +} diff --git a/man/open.clean.Rd b/man/open.clean.Rd new file mode 100644 index 0000000..2a48a97 --- /dev/null +++ b/man/open.clean.Rd @@ -0,0 +1,26 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/open.clean.R +\docType{data} +\name{open.clean} +\alias{open.clean} +\title{Cleaned response Matrices (Openness and Verbal Fluency)} +\format{ +open.clean (matrix, 516 x 35) +} +\usage{ +data(open.clean) +} +\description{ +Cleaned response matrices for the Animals verbal fluency data (\emph{n} = 516) +from Christensen et al. (2018). +} +\examples{ +data("open.clean") +} +\references{ +Christensen, A. P., Kenett, Y. N., Cotter, K. N., Beaty, R. E., & Silvia, P. J. (2018). +Remotely close associations: Openness to experience and semantic memory structure. +\emph{European Journal of Personality}, \emph{32}, 480-492. +doi:\href{https://doi.org/10.1002/per.2157}{10.1002/per.2157} +} +\keyword{datasets} diff --git a/man/textcleaner.Rd b/man/textcleaner.Rd index f0077d3..d77e8ed 100644 --- a/man/textcleaner.Rd +++ b/man/textcleaner.Rd @@ -9,8 +9,8 @@ textcleaner( miss = 99, partBY = c("row", "col"), dictionary = NULL, - continue = NULL, - walkthrough = NULL + add.path = NULL, + continue = NULL ) } \arguments{ @@ -37,17 +37,17 @@ Defaults to \code{NULL}, which will use \code{\link[SemNetDictionaries]{general. Use \code{dictionaries()} or \code{find.dictionaries()} for more options (See \code{\link{SemNetDictionaries}} for more details)} +\item{add.path}{Character. +Path to additional dictionaries to be found. +DOES NOT search recursively (through all folders in path) +to avoid time intensive search. +Set to \code{"choose"} to open an interactive directory explorer} + \item{continue}{List. A result previously unfinished that still needs to be completed. Allows you to continue to manually spell-check their data after you've closed or errored out. Defaults to \code{NULL}} - -\item{walkthrough}{Boolean. -Whether a walkthrough should be provided (recommended for first time users). -Defaults to \code{NULL}, which will ask whether you would like a walkthrough. -Set to \code{TRUE} to do the walkthrough. -Set to \code{FALSE} to skip the walkthrough} } \value{ This function returns a list containing the following objects: @@ -60,11 +60,11 @@ and a response that a participant has not provided is a '\code{0}'} \itemize{ -\item{clean} +\item{\code{clean}} {A response matrix that has been spell-checked and de-pluralized with duplicates removed. This can be used as a final dataset for analyses (e.g., fluency of responses)} -\item{original} +\item{\code{original}} {The original response matrix that has had white spaces before and after words response. Also converts all upper-case letters to lower case}