-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Condecon
committed
May 16, 2023
0 parents
commit 38d6cfd
Showing
27 changed files
with
1,693 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
source("renv/activate.R") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
.Rproj.user | ||
.Rhistory | ||
.RData | ||
.Ruserdata | ||
.Rbuildignore | ||
.DS_Store | ||
src/*.o | ||
src/*.so | ||
src/*.dll | ||
src/*.pdb | ||
.vscode/ | ||
renv.lock | ||
psy_data/ | ||
inst/python/__pycache__/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
Package: psytoolkittools | ||
Type: Package | ||
Title: psytoolkittools | ||
Version: 0.1.0 | ||
Date: 2023-05-11 | ||
Author: Jonas Engicht | ||
Maintainer: Jonas Engicht <dev@condecon.de> | ||
Description: Working with PsyToolkit experiments and surveys | ||
License: GPL (>= 2) | ||
RoxygenNote: 7.2.3 | ||
Suggests: | ||
testthat (>= 3.0.0) | ||
Imports: | ||
cli, glue, reticulate, stringr | ||
LinkingTo: cpp11 | ||
SystemRequirements: C++11 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
# Generated by roxygen2: do not edit by hand | ||
|
||
export(load.experiment) | ||
export(load.survey) | ||
export(recode.keys) | ||
export(recode.status) | ||
import("glue") | ||
import("reticulate") | ||
import("stringr") | ||
importFrom("stats","setNames") | ||
importFrom("utils","read.csv") | ||
useDynLib(psytoolkittools, .registration = TRUE) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
# Generated by cpp11: do not edit by hand | ||
|
||
recode_keys_c <- function(vector, keys) { | ||
.Call(`_psytoolkittools_recode_keys_c`, vector, keys) | ||
} | ||
|
||
recode_status_c <- function(status_vector, correct, error, timeout) { | ||
.Call(`_psytoolkittools_recode_status_c`, status_vector, correct, error, timeout) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
#' Load Experiment | ||
#' @description This function loads experiment data from a PsyToolkit experiment | ||
#' Therefore, a vector of file names and a vector of labels which represents the | ||
#' structure of the experiment file have to be provided. | ||
#' The experiment data has to be located in the `psy_data/experiment_data` directory. | ||
#' Otherwise, loading the experiment will fail. | ||
#' @param experiment.file.names A vector of experiment file names | ||
#' @param label.structur A vector of labels that represents the structure of the saved experiment value | ||
#' @param merge.dataframe The result of this function can be directly added to a existing data frame (e.g. survey data). | ||
#' The default value is NA. | ||
#' | ||
#' @return data.frame | ||
#' @export | ||
#' @importFrom "stats" "setNames" | ||
#' @importFrom "utils" "read.csv" | ||
#' @examples | ||
load.experiment = function(experiment.file.names,label.structure, merge.dataframe = NA){ | ||
|
||
#add path to experiment.file.names | ||
experiment.file.names = glue::glue("psy_data\\experiment_data\\{experiment.file.names}") | ||
|
||
|
||
|
||
d = data.frame() | ||
|
||
for(i in c(1:length(experiment.file.names))){ | ||
data.list = .read.experiment.file(experiment.file.names[i]) | ||
|
||
d = rbind(d, data.list) | ||
} | ||
|
||
d = setNames(d, label.structure) | ||
|
||
|
||
|
||
### add to existing dataframe? | ||
if(missing(merge.dataframe)){ | ||
return(d) | ||
} | ||
else{ | ||
return(cbind(merge.dataframe, d)) | ||
} | ||
|
||
} | ||
|
||
.read.experiment.file = function(filename){ | ||
experiment.data = read.csv(filename, sep =" ", header = FALSE) | ||
|
||
|
||
data.vector = c() | ||
|
||
for(row in c(1:nrow(experiment.data))){ | ||
for(entry in c(1:length(experiment.data[row, ]))){ | ||
|
||
e = experiment.data[row, entry] | ||
if(!is.na(e)){ | ||
data.vector = append(data.vector, as.integer(e)) | ||
} | ||
} | ||
} | ||
|
||
return(data.vector) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
#======Basic Load====== | ||
|
||
#UNZIP-Survey-Data | ||
unzip_tool = function(file_path){ | ||
unzip(file_path, exdir = "psy_data") | ||
} | ||
|
||
#load survey | ||
load_survey_awnsers = function(){ | ||
awnsers = read.csv(glue::glue("psy_data\\data.csv")) | ||
return(awnsers) | ||
} | ||
|
||
#========================Survey Parser=============================== | ||
#' Parse Survey (Hidden) | ||
#' | ||
#' @import "reticulate" | ||
#' @import "stringr" | ||
#' @import "glue" | ||
|
||
parse_survey = function(awnsers){ | ||
#get package path | ||
package_path = path.package("psytoolkittools") | ||
#replace / with \\ | ||
package_path = gsub("/", "\\\\", package_path) | ||
module_path = glue::glue("{package_path}\\python\\") | ||
|
||
#import module | ||
parse_module = reticulate::import_from_path("survey_parser", path = module_path) | ||
#parse document | ||
document = parse_module$parse(".") | ||
|
||
list_of_question_labels = c() | ||
|
||
for(i in c(1:length(document))){ | ||
list_of_question_labels = append(list_of_question_labels, document[[i]]$label) | ||
} | ||
|
||
list_of_question_types = c() | ||
|
||
for(i in c(1:length(document))){ | ||
list_of_question_types = append(list_of_question_types, document[[i]]$type) | ||
} | ||
|
||
#remove newline of question_labels | ||
list_of_question_labels = gsub("\n", "", list_of_question_labels) | ||
list_of_question_types = gsub("\n", "", list_of_question_types) | ||
|
||
|
||
|
||
#get index of all radio questions | ||
index_of_radio_questions = which(list_of_question_types == "radio") | ||
#get names of radio questions# | ||
names_of_radio_questions = list_of_question_labels[index_of_radio_questions] | ||
|
||
|
||
#get survey awnser index of radio questions | ||
survey_radio_index = c() | ||
for(i in c(1:length(names_of_radio_questions))){ | ||
res = stringr::str_which(colnames(awnsers), names_of_radio_questions[i]) | ||
|
||
survey_radio_index = append(res, survey_radio_index) | ||
} | ||
|
||
|
||
#convert columns which are "radio" questions to factors | ||
for(i in c(1:length(survey_radio_index))){ | ||
awnsers[,survey_radio_index[i]] = as.factor(awnsers[,survey_radio_index[i]]) | ||
} | ||
|
||
|
||
return(awnsers) | ||
} | ||
|
||
|
||
#============Load Survey============ | ||
#'Load Survey | ||
#'@description This functions loads the answers of a PsyToolkit survey from the specified .ZIP file. | ||
#'This file will be unzipped in the folder `psy_data`. Do not remove this folder for further use such as reading experiment data. | ||
#'@param filename File name of the .ZIP file that has been downloaded from PsyToolkit | ||
#'@export | ||
#'@return data.frame | ||
load.survey = function(filename){ | ||
unzip_tool(filename) | ||
|
||
awnsers = load_survey_awnsers() | ||
awnsers = parse_survey(awnsers) | ||
|
||
return(awnsers) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
#' @useDynLib psytoolkittools, .registration = TRUE | ||
load = function(){ | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
#' Recode Keys | ||
#' | ||
#' @param vector A vector of key values | ||
#' @param keys A vector of keys. Those keys have to be in the same order than | ||
#' in your experiment code. | ||
#' | ||
#' @return numeric | ||
#' | ||
#' @export | ||
#' @examples | ||
recode.keys = function(vector, keys){ | ||
v = as.character(vector) | ||
k = as.character(keys) | ||
result = psytoolkittools:::recode_keys_c(v, k) | ||
|
||
return(result) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
|
||
#' Recode Status | ||
#' @description This function recodes the status variable to custom values. | ||
#' @param status_vector Numeric vector of statuses. This vector will be recoded. | ||
#' @param correct Numeric value which indicates a correct response. | ||
#' @param error Numeric value which indicates an error. | ||
#' @param timeout Numeric value which indicates a timeout. | ||
#' | ||
#' @return numeric | ||
#' @export | ||
#' | ||
#' @examples | ||
recode.status = function(status_vector, correct = 1, error = 0, timeout = NA){ | ||
return(psytoolkittools:::recode_status_c(as.character(status_vector), | ||
as.character(correct), | ||
as.character(error), | ||
as.character(timeout))) | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
# PSYTOOLKITTOOLS | ||
|
||
## Installing | ||
|
||
Because the package is currently not avaible on CRAN, you have to download it from GitHub and compile it yourself. | ||
Both can be be easily done by using the following R code. | ||
```r | ||
#if devtools are not installed | ||
install.packages("devtools") | ||
|
||
library(devtools) | ||
devtools::install_github("condecon/psytoolkittools") | ||
``` | ||
|
||
**Dependecies** | ||
- reticulate | ||
- cpp11 | ||
- cli | ||
- glue | ||
- devtools | ||
|
||
Also, RTools are required for compiling the source code. | ||
|
||
## Loading Data | ||
|
||
At first, download your survey and experiment results from the | ||
PsyToolkit website. You will receive a .ZIP file. Move this file to your | ||
current R working directory. | ||
|
||
In R, load the `psytoolkittools` package and run the `load.survey(filename)` function. | ||
For example: | ||
```r | ||
library(psytoolkittools) | ||
data <- load.survey("data.zip") | ||
``` | ||
The function returns a data frame with the survey awnsers. | ||
A folder called "psy_data" is created. Do not delete this folder as it is nessecary for loading experiment data. | ||
|
||
### Loading Experiment Data | ||
To easily load the experiment data, the package provides the `load.experiment.data()` function. | ||
This functions requires two arguments: | ||
- Column with the experiment data filenames | ||
- Vector of strings which correspond to the structure of the saved experiment data | ||
|
||
The function returns a data frame which can be combined with the survey data frame by passing it to the function. | ||
```r | ||
load.experiment.data(experiment.file.names, label.structure, merge.dataframe = surveydata) | ||
``` | ||
|
||
# Utilities | ||
|
||
## `recode.keys` | ||
In PsyToolkit, when saving keys, the pressed key itself is not saved instead the position in which the key was definied is saved. | ||
For further analysis, it can be helpful to reverse the saved value to the name of the original key that has been pressed by the participant. | ||
In this case `recode.keys()` can be used. | ||
The function takes to parameters. The first is the vector or column that shall be recoded. The second parameter is a vector of characters in which the characters are in the same line up than in the experiment code. | ||
For example: | ||
``` | ||
#experiment code | ||
... | ||
keys 1 2 3 4 space | ||
... | ||
``` | ||
|
||
```r | ||
#R code | ||
recode.keys(data, c("1", "2", "3", "4", "space")) | ||
``` | ||
## `recode.status` | ||
|
||
In PsyToolkit experiments, a status of 1 represents a correct and 2 an incorrect answer. 3 represents a time out.\ | ||
With `recode.status()`, status codes can be recoded to custom values. | ||
|
||
*Example:* | ||
|
||
```r | ||
recode.status(vector, correct = 1, error = 0, timeout = -99) | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
class Question: | ||
label:str = "" | ||
type:str = "" | ||
question:str = "" | ||
awnsers:list[str] = [] | ||
|
||
|
||
|
||
def parse(tempdir:str) -> list[Question]: | ||
document:list[Question] = [] | ||
|
||
file = open(f"psy_data\\survey.txt") | ||
survey_string_list = file.readlines() | ||
|
||
|
||
#remove all empty lines | ||
survey_string_list = [x for x in survey_string_list if x != "\n"] | ||
|
||
question = Question() | ||
#loop document | ||
line_index = 0 | ||
for line in survey_string_list: | ||
if line.startswith("l:"): | ||
question_label = line.replace("l: ", "") | ||
#question_label = line.replace("\n", "") | ||
question.label = question_label | ||
|
||
if line.startswith("t:"): | ||
question_type = line.replace("t: ", "") | ||
question.type = question_type | ||
|
||
if line.startswith("q:"): | ||
question.question = line.replace("q: ", "") | ||
|
||
if line.startswith("-"): | ||
question.awnsers.append(line.replace("- ", "")) | ||
|
||
#check for question end | ||
#question ended when the beginning of the next line is "l: " | ||
try: | ||
if survey_string_list[line_index + 1].startswith("l:"): | ||
#save question | ||
document.append(question) | ||
#create new question variable | ||
question = Question() | ||
question.awnsers = [] | ||
except IndexError: | ||
document.append(question) | ||
|
||
|
||
line_index = line_index + 1 | ||
|
||
|
||
|
||
#return | ||
return document |
Oops, something went wrong.