compileprofile-spacetests 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/emotions.d.ts +10 -0
- package/dist/cjs/emotions.js +54 -0
- package/dist/cjs/gonogo.d.ts +10 -3
- package/dist/cjs/gonogo.js +64 -23
- package/dist/cjs/spatial-cognition.js +3 -7
- package/dist/esm/emotions.d.ts +10 -0
- package/dist/esm/emotions.js +49 -0
- package/dist/esm/gonogo.d.ts +10 -3
- package/dist/esm/gonogo.js +60 -24
- package/dist/esm/spatial-cognition.js +3 -7
- package/example-data/spatial-cognition.json +1 -1
- package/package.json +2 -2
- package/src/__tests__/integration/emotions.test.ts +65 -0
- package/src/__tests__/integration/gonogo.test.ts +81 -0
- package/src/__tests__/integration/spatial-cognition.test.ts +8 -1
- package/src/emotions.ts +59 -0
- package/src/gonogo.ts +69 -30
- package/src/spatial-cognition.ts +3 -7
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
interface EmotionResults {
|
|
2
|
+
n: number;
|
|
3
|
+
avg_rt: number;
|
|
4
|
+
avg_acc: number;
|
|
5
|
+
performance: number;
|
|
6
|
+
}
|
|
7
|
+
declare const emotion_calculate_results: (obj: any[]) => EmotionResults;
|
|
8
|
+
declare const emotion_results: (obj: any[]) => EmotionResults;
|
|
9
|
+
declare const emotion_extract_trials: (obj: any[]) => any[];
|
|
10
|
+
export { emotion_calculate_results, emotion_extract_trials, emotion_results };
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.emotion_results = exports.emotion_extract_trials = exports.emotion_calculate_results = void 0;
|
|
4
|
+
var emotion_calculate_results = function (obj) {
|
|
5
|
+
var trials = emotion_extract_trials(obj);
|
|
6
|
+
// throw if trials is empty
|
|
7
|
+
if (trials.length === 0) {
|
|
8
|
+
throw new Error("No trials found");
|
|
9
|
+
}
|
|
10
|
+
return emotion_results(trials);
|
|
11
|
+
};
|
|
12
|
+
exports.emotion_calculate_results = emotion_calculate_results;
|
|
13
|
+
var emotion_results = function (obj) {
|
|
14
|
+
// throw error if obj is empty
|
|
15
|
+
if (obj.length === 0) {
|
|
16
|
+
throw new Error("No trials found");
|
|
17
|
+
}
|
|
18
|
+
var results = {
|
|
19
|
+
n: obj.length,
|
|
20
|
+
avg_rt: obj.reduce(function (a, b) { return a + b.rt; }, 0) / obj.length,
|
|
21
|
+
avg_acc: obj.reduce(function (a, b) { return a + b.correct; }, 0) / obj.length,
|
|
22
|
+
performance: NaN
|
|
23
|
+
};
|
|
24
|
+
var best_score = 1000;
|
|
25
|
+
var worst_score = 10000;
|
|
26
|
+
var performance = results.avg_rt / (Math.pow(results.avg_acc, 5) + 0.001);
|
|
27
|
+
performance = Math.min(Math.max(performance, best_score), worst_score);
|
|
28
|
+
results.performance = (1 - ((performance - best_score) / (worst_score - best_score))) * 100;
|
|
29
|
+
return results;
|
|
30
|
+
};
|
|
31
|
+
exports.emotion_results = emotion_results;
|
|
32
|
+
var emotion_extract_trials = function (obj) {
|
|
33
|
+
var emotionMap = ["neutral", "sad", "happy", "surprised", "angry"];
|
|
34
|
+
// filter trials where response and rt are defined and not null
|
|
35
|
+
var trials = obj.filter(function (o) { return 'response' in o && 'rt' in o && 'emotion' in o; });
|
|
36
|
+
trials = trials.filter(function (o) { return o.response !== null && o.rt !== null; });
|
|
37
|
+
trials.forEach(function (o) {
|
|
38
|
+
var match = o.emotion.match(/\/([^/]+)_([0-9]+)\.png/);
|
|
39
|
+
if (match) {
|
|
40
|
+
o.stimulus = match[0];
|
|
41
|
+
o.emotion = match[1];
|
|
42
|
+
o.image_number = match[2];
|
|
43
|
+
//this is <emotion>_<number>.png
|
|
44
|
+
o.image = "".concat(match[1], "_").concat(match[2], ".png");
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
trials.forEach(function (o) {
|
|
48
|
+
o.emotion_response = emotionMap[o.response] || "unknown";
|
|
49
|
+
o.correct = o.emotion === o.emotion_response;
|
|
50
|
+
// in the older ones there were 15 trials per rotation
|
|
51
|
+
});
|
|
52
|
+
return trials;
|
|
53
|
+
};
|
|
54
|
+
exports.emotion_extract_trials = emotion_extract_trials;
|
package/dist/cjs/gonogo.d.ts
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
interface GonogoResults {
|
|
2
|
+
n: number;
|
|
3
|
+
avg_rt: number;
|
|
4
|
+
avg_acc: number;
|
|
5
|
+
performance: number;
|
|
6
|
+
}
|
|
7
|
+
declare const gonogo_calculate_results: (data: any[]) => GonogoResults;
|
|
8
|
+
declare const gonogo_extract_trials: (obj: any[]) => any[];
|
|
9
|
+
declare const gonogo_results: (data: any[]) => GonogoResults;
|
|
10
|
+
export { gonogo_calculate_results, gonogo_extract_trials, gonogo_results };
|
package/dist/cjs/gonogo.js
CHANGED
|
@@ -1,30 +1,71 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
// df <- as.data.frame(fromJSON(arr[[1]]))
|
|
5
|
-
// GONOGO_IMAGE_PATH <- "https://unyavwofnmwihnpvkjji.supabase.co/storage/v1/object/public/test-stimuli/gonogo/"
|
|
6
|
-
// df <- filter(df, !is.na(image))
|
|
7
|
-
// df <- select(df, trial_index, time_elapsed, rt,
|
|
8
|
-
// response, block_number, image)
|
|
9
|
-
// df$image <- gsub(GONOGO_IMAGE_PATH, "", df$image)
|
|
10
|
-
// df$image <- gsub(".png", "", df$image)
|
|
11
|
-
// df <- df %>%
|
|
12
|
-
// mutate(
|
|
13
|
-
// should_go = case_when(
|
|
14
|
-
// block_number == 1 & grepl("astronaut_trans_1", image) ~ TRUE,
|
|
15
|
-
// block_number == 2 & grepl("alien_trans_1", image) ~ TRUE,
|
|
16
|
-
// block_number == 3 & grepl("rocket_trans_1", image) ~ TRUE,
|
|
17
|
-
// block_number == 4 & !grepl("rocket_trans_1", image) ~ TRUE,
|
|
18
|
-
// TRUE ~ FALSE),
|
|
19
|
-
// did_go = !is.na(response),
|
|
20
|
-
// correct = should_go == did_go
|
|
21
|
-
// )
|
|
22
|
-
// return(df)
|
|
23
|
-
// }
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.gonogo_results = exports.gonogo_extract_trials = exports.gonogo_calculate_results = void 0;
|
|
24
4
|
var gonogo_calculate_results = function (data) {
|
|
5
|
+
var trials = gonogo_extract_trials(data);
|
|
6
|
+
var results = gonogo_results(trials);
|
|
7
|
+
return results;
|
|
25
8
|
};
|
|
26
|
-
|
|
9
|
+
exports.gonogo_calculate_results = gonogo_calculate_results;
|
|
10
|
+
var gonogo_extract_trials = function (obj) {
|
|
27
11
|
// GONOGO_IMAGE_PATH <- "https://unyavwofnmwihnpvkjji.supabase.co/storage/v1/object/public/test-stimuli/gonogo/"
|
|
12
|
+
var trials = obj.filter(function (o) { return 'image' in o && o.image !== undefined; });
|
|
13
|
+
trials.forEach(function (o) {
|
|
14
|
+
// image is in format <stimulus>_trans_<number>.png
|
|
15
|
+
// extract the stimulus and number
|
|
16
|
+
// "image": "https://unyavwofnmwihnpvkjji.supabase.co/storage/v1/object/public/test-stimuli/gonogo/aliens/astronaut_trans_1.png",
|
|
17
|
+
// i need to extract the iamge name from the url
|
|
18
|
+
var match = o.image.match(/([^/]+)_(\d+)\.png$/);
|
|
19
|
+
if (match) {
|
|
20
|
+
o.stimulus = match[0];
|
|
21
|
+
o.stimulustype = match[1];
|
|
22
|
+
o.image_number = match[2];
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
console.warn('Image format did not match expected pattern:', o.image);
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
o.should_go = false;
|
|
29
|
+
o.did_go = o.response !== null;
|
|
30
|
+
switch (o.block_number) {
|
|
31
|
+
case 1:
|
|
32
|
+
o.should_go = o.stimulus == "astronaut_trans_1.png";
|
|
33
|
+
break;
|
|
34
|
+
case 2:
|
|
35
|
+
o.should_go = o.stimulus == "alien_trans_1.png";
|
|
36
|
+
break;
|
|
37
|
+
case 3:
|
|
38
|
+
o.should_go = o.stimulus == "rocket_trans_1.png";
|
|
39
|
+
break;
|
|
40
|
+
case 4:
|
|
41
|
+
// should go in all cases where the goal is NOT the rocket
|
|
42
|
+
o.should_go = !(o.stimulus == "rocket_trans_1.png");
|
|
43
|
+
break;
|
|
44
|
+
default:
|
|
45
|
+
o.should_go = false;
|
|
46
|
+
break;
|
|
47
|
+
}
|
|
48
|
+
o.correct = o.should_go == o.did_go;
|
|
49
|
+
});
|
|
50
|
+
return trials;
|
|
28
51
|
};
|
|
52
|
+
exports.gonogo_extract_trials = gonogo_extract_trials;
|
|
29
53
|
var gonogo_results = function (data) {
|
|
54
|
+
// throw error if obj is empty
|
|
55
|
+
if (data.length === 0) {
|
|
56
|
+
throw new Error("No trials found");
|
|
57
|
+
}
|
|
58
|
+
var results = {
|
|
59
|
+
n: data.length,
|
|
60
|
+
avg_rt: data.reduce(function (a, b) { return a + b.rt; }, 0) / data.length,
|
|
61
|
+
avg_acc: data.reduce(function (a, b) { return a + b.correct; }, 0) / data.length,
|
|
62
|
+
performance: NaN
|
|
63
|
+
};
|
|
64
|
+
var best_score = 300;
|
|
65
|
+
var worst_score = 5000;
|
|
66
|
+
var performance = results.avg_rt / (Math.pow(results.avg_acc, 5) + 0.001);
|
|
67
|
+
performance = Math.min(Math.max(performance, best_score), worst_score);
|
|
68
|
+
results.performance = (1 - ((performance - best_score) / (worst_score - best_score))) * 100;
|
|
69
|
+
return results;
|
|
30
70
|
};
|
|
71
|
+
exports.gonogo_results = gonogo_results;
|
|
@@ -23,13 +23,9 @@ var spatial_results = function (obj) {
|
|
|
23
23
|
var best_score = 1000;
|
|
24
24
|
var worst_score = 10000;
|
|
25
25
|
// results.avg_acc to the power of 5
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
}
|
|
30
|
-
if (performance > worst_score) {
|
|
31
|
-
performance = worst_score;
|
|
32
|
-
}
|
|
26
|
+
//let performance = results.avg_rt / (Math.pow(results.avg_acc, 5) + 0.001);
|
|
27
|
+
var performance = results.avg_rt / (results.avg_acc + 0.001);
|
|
28
|
+
performance = Math.min(Math.max(performance, best_score), worst_score);
|
|
33
29
|
// convert to 0-100 where 100 is the best (200)
|
|
34
30
|
results.performance = (1 - ((performance - best_score) / (worst_score - best_score))) * 100;
|
|
35
31
|
return results;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
interface EmotionResults {
|
|
2
|
+
n: number;
|
|
3
|
+
avg_rt: number;
|
|
4
|
+
avg_acc: number;
|
|
5
|
+
performance: number;
|
|
6
|
+
}
|
|
7
|
+
declare const emotion_calculate_results: (obj: any[]) => EmotionResults;
|
|
8
|
+
declare const emotion_results: (obj: any[]) => EmotionResults;
|
|
9
|
+
declare const emotion_extract_trials: (obj: any[]) => any[];
|
|
10
|
+
export { emotion_calculate_results, emotion_extract_trials, emotion_results };
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
var emotion_calculate_results = function (obj) {
|
|
2
|
+
var trials = emotion_extract_trials(obj);
|
|
3
|
+
// throw if trials is empty
|
|
4
|
+
if (trials.length === 0) {
|
|
5
|
+
throw new Error("No trials found");
|
|
6
|
+
}
|
|
7
|
+
return emotion_results(trials);
|
|
8
|
+
};
|
|
9
|
+
var emotion_results = function (obj) {
|
|
10
|
+
// throw error if obj is empty
|
|
11
|
+
if (obj.length === 0) {
|
|
12
|
+
throw new Error("No trials found");
|
|
13
|
+
}
|
|
14
|
+
var results = {
|
|
15
|
+
n: obj.length,
|
|
16
|
+
avg_rt: obj.reduce(function (a, b) { return a + b.rt; }, 0) / obj.length,
|
|
17
|
+
avg_acc: obj.reduce(function (a, b) { return a + b.correct; }, 0) / obj.length,
|
|
18
|
+
performance: NaN
|
|
19
|
+
};
|
|
20
|
+
var best_score = 1000;
|
|
21
|
+
var worst_score = 10000;
|
|
22
|
+
var performance = results.avg_rt / (Math.pow(results.avg_acc, 5) + 0.001);
|
|
23
|
+
performance = Math.min(Math.max(performance, best_score), worst_score);
|
|
24
|
+
results.performance = (1 - ((performance - best_score) / (worst_score - best_score))) * 100;
|
|
25
|
+
return results;
|
|
26
|
+
};
|
|
27
|
+
var emotion_extract_trials = function (obj) {
|
|
28
|
+
var emotionMap = ["neutral", "sad", "happy", "surprised", "angry"];
|
|
29
|
+
// filter trials where response and rt are defined and not null
|
|
30
|
+
var trials = obj.filter(function (o) { return 'response' in o && 'rt' in o && 'emotion' in o; });
|
|
31
|
+
trials = trials.filter(function (o) { return o.response !== null && o.rt !== null; });
|
|
32
|
+
trials.forEach(function (o) {
|
|
33
|
+
var match = o.emotion.match(/\/([^/]+)_([0-9]+)\.png/);
|
|
34
|
+
if (match) {
|
|
35
|
+
o.stimulus = match[0];
|
|
36
|
+
o.emotion = match[1];
|
|
37
|
+
o.image_number = match[2];
|
|
38
|
+
//this is <emotion>_<number>.png
|
|
39
|
+
o.image = "".concat(match[1], "_").concat(match[2], ".png");
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
trials.forEach(function (o) {
|
|
43
|
+
o.emotion_response = emotionMap[o.response] || "unknown";
|
|
44
|
+
o.correct = o.emotion === o.emotion_response;
|
|
45
|
+
// in the older ones there were 15 trials per rotation
|
|
46
|
+
});
|
|
47
|
+
return trials;
|
|
48
|
+
};
|
|
49
|
+
export { emotion_calculate_results, emotion_extract_trials, emotion_results };
|
package/dist/esm/gonogo.d.ts
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
interface GonogoResults {
|
|
2
|
+
n: number;
|
|
3
|
+
avg_rt: number;
|
|
4
|
+
avg_acc: number;
|
|
5
|
+
performance: number;
|
|
6
|
+
}
|
|
7
|
+
declare const gonogo_calculate_results: (data: any[]) => GonogoResults;
|
|
8
|
+
declare const gonogo_extract_trials: (obj: any[]) => any[];
|
|
9
|
+
declare const gonogo_results: (data: any[]) => GonogoResults;
|
|
10
|
+
export { gonogo_calculate_results, gonogo_extract_trials, gonogo_results };
|
package/dist/esm/gonogo.js
CHANGED
|
@@ -1,30 +1,66 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
// gonogo_create_trial_table <- function(txt) {
|
|
3
|
-
// arr <- fromJSON(txt)
|
|
4
|
-
// df <- as.data.frame(fromJSON(arr[[1]]))
|
|
5
|
-
// GONOGO_IMAGE_PATH <- "https://unyavwofnmwihnpvkjji.supabase.co/storage/v1/object/public/test-stimuli/gonogo/"
|
|
6
|
-
// df <- filter(df, !is.na(image))
|
|
7
|
-
// df <- select(df, trial_index, time_elapsed, rt,
|
|
8
|
-
// response, block_number, image)
|
|
9
|
-
// df$image <- gsub(GONOGO_IMAGE_PATH, "", df$image)
|
|
10
|
-
// df$image <- gsub(".png", "", df$image)
|
|
11
|
-
// df <- df %>%
|
|
12
|
-
// mutate(
|
|
13
|
-
// should_go = case_when(
|
|
14
|
-
// block_number == 1 & grepl("astronaut_trans_1", image) ~ TRUE,
|
|
15
|
-
// block_number == 2 & grepl("alien_trans_1", image) ~ TRUE,
|
|
16
|
-
// block_number == 3 & grepl("rocket_trans_1", image) ~ TRUE,
|
|
17
|
-
// block_number == 4 & !grepl("rocket_trans_1", image) ~ TRUE,
|
|
18
|
-
// TRUE ~ FALSE),
|
|
19
|
-
// did_go = !is.na(response),
|
|
20
|
-
// correct = should_go == did_go
|
|
21
|
-
// )
|
|
22
|
-
// return(df)
|
|
23
|
-
// }
|
|
24
1
|
var gonogo_calculate_results = function (data) {
|
|
2
|
+
var trials = gonogo_extract_trials(data);
|
|
3
|
+
var results = gonogo_results(trials);
|
|
4
|
+
return results;
|
|
25
5
|
};
|
|
26
|
-
var gonogo_extract_trials = function (
|
|
6
|
+
var gonogo_extract_trials = function (obj) {
|
|
27
7
|
// GONOGO_IMAGE_PATH <- "https://unyavwofnmwihnpvkjji.supabase.co/storage/v1/object/public/test-stimuli/gonogo/"
|
|
8
|
+
var trials = obj.filter(function (o) { return 'image' in o && o.image !== undefined; });
|
|
9
|
+
trials.forEach(function (o) {
|
|
10
|
+
// image is in format <stimulus>_trans_<number>.png
|
|
11
|
+
// extract the stimulus and number
|
|
12
|
+
// "image": "https://unyavwofnmwihnpvkjji.supabase.co/storage/v1/object/public/test-stimuli/gonogo/aliens/astronaut_trans_1.png",
|
|
13
|
+
// i need to extract the iamge name from the url
|
|
14
|
+
var match = o.image.match(/([^/]+)_(\d+)\.png$/);
|
|
15
|
+
if (match) {
|
|
16
|
+
o.stimulus = match[0];
|
|
17
|
+
o.stimulustype = match[1];
|
|
18
|
+
o.image_number = match[2];
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
console.warn('Image format did not match expected pattern:', o.image);
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
o.should_go = false;
|
|
25
|
+
o.did_go = o.response !== null;
|
|
26
|
+
switch (o.block_number) {
|
|
27
|
+
case 1:
|
|
28
|
+
o.should_go = o.stimulus == "astronaut_trans_1.png";
|
|
29
|
+
break;
|
|
30
|
+
case 2:
|
|
31
|
+
o.should_go = o.stimulus == "alien_trans_1.png";
|
|
32
|
+
break;
|
|
33
|
+
case 3:
|
|
34
|
+
o.should_go = o.stimulus == "rocket_trans_1.png";
|
|
35
|
+
break;
|
|
36
|
+
case 4:
|
|
37
|
+
// should go in all cases where the goal is NOT the rocket
|
|
38
|
+
o.should_go = !(o.stimulus == "rocket_trans_1.png");
|
|
39
|
+
break;
|
|
40
|
+
default:
|
|
41
|
+
o.should_go = false;
|
|
42
|
+
break;
|
|
43
|
+
}
|
|
44
|
+
o.correct = o.should_go == o.did_go;
|
|
45
|
+
});
|
|
46
|
+
return trials;
|
|
28
47
|
};
|
|
29
48
|
var gonogo_results = function (data) {
|
|
49
|
+
// throw error if obj is empty
|
|
50
|
+
if (data.length === 0) {
|
|
51
|
+
throw new Error("No trials found");
|
|
52
|
+
}
|
|
53
|
+
var results = {
|
|
54
|
+
n: data.length,
|
|
55
|
+
avg_rt: data.reduce(function (a, b) { return a + b.rt; }, 0) / data.length,
|
|
56
|
+
avg_acc: data.reduce(function (a, b) { return a + b.correct; }, 0) / data.length,
|
|
57
|
+
performance: NaN
|
|
58
|
+
};
|
|
59
|
+
var best_score = 300;
|
|
60
|
+
var worst_score = 5000;
|
|
61
|
+
var performance = results.avg_rt / (Math.pow(results.avg_acc, 5) + 0.001);
|
|
62
|
+
performance = Math.min(Math.max(performance, best_score), worst_score);
|
|
63
|
+
results.performance = (1 - ((performance - best_score) / (worst_score - best_score))) * 100;
|
|
64
|
+
return results;
|
|
30
65
|
};
|
|
66
|
+
export { gonogo_calculate_results, gonogo_extract_trials, gonogo_results };
|
|
@@ -18,13 +18,9 @@ var spatial_results = function (obj) {
|
|
|
18
18
|
var best_score = 1000;
|
|
19
19
|
var worst_score = 10000;
|
|
20
20
|
// results.avg_acc to the power of 5
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}
|
|
25
|
-
if (performance > worst_score) {
|
|
26
|
-
performance = worst_score;
|
|
27
|
-
}
|
|
21
|
+
//let performance = results.avg_rt / (Math.pow(results.avg_acc, 5) + 0.001);
|
|
22
|
+
var performance = results.avg_rt / (results.avg_acc + 0.001);
|
|
23
|
+
performance = Math.min(Math.max(performance, best_score), worst_score);
|
|
28
24
|
// convert to 0-100 where 100 is the best (200)
|
|
29
25
|
results.performance = (1 - ((performance - best_score) / (worst_score - best_score))) * 100;
|
|
30
26
|
return results;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "compileprofile-spacetests",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "A package for evaluating cognitive test results",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "A package for evaluating cognitive test results from Vzhuru do vesmiru",
|
|
5
5
|
"main": "dist/cjs/index.js",
|
|
6
6
|
"module": "dist/esm/index.js",
|
|
7
7
|
"types": "dist/cjs/index.d.ts",
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { emotion_extract_trials, emotion_results,
|
|
2
|
+
emotion_calculate_results } from '../../emotions';
|
|
3
|
+
import { loadTestData } from '../test-utils/testData';
|
|
4
|
+
|
|
5
|
+
describe('Emotions test module', () => {
|
|
6
|
+
const emotionsData = loadTestData('emotions').emotions;
|
|
7
|
+
|
|
8
|
+
describe('emotion_extract_trials', () => {
|
|
9
|
+
it('should extract trials from raw data', () => {
|
|
10
|
+
const trials = emotion_extract_trials(emotionsData);
|
|
11
|
+
expect(trials.length).toBeLessThan(emotionsData.length);
|
|
12
|
+
trials.forEach(trial => {
|
|
13
|
+
expect(trial).toHaveProperty('rt');
|
|
14
|
+
expect(trial).toHaveProperty('emotion');
|
|
15
|
+
expect(trial).toHaveProperty('emotion_response');
|
|
16
|
+
expect(trial).toHaveProperty('correct');
|
|
17
|
+
expect(trial).toHaveProperty('image_number');
|
|
18
|
+
expect(typeof trial.emotion).toBe('string');
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('should handle empty data array', () => {
|
|
23
|
+
const trials = emotion_extract_trials([]);
|
|
24
|
+
expect(trials).toEqual([]);
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
describe('emotion_results', () => {
|
|
29
|
+
it('should calculate correct averages', () => {
|
|
30
|
+
// Create sample trial data
|
|
31
|
+
const sampleTrials = [
|
|
32
|
+
{ rt: 600, correct: true, emotion: 'happy', emotion_response: 'happy' },
|
|
33
|
+
{ rt: 1000, correct: true, emotion: 'sad', emotion_response: 'sad' },
|
|
34
|
+
{ rt: 800, correct: false, emotion: 'angry', emotion_response: 'happy' },
|
|
35
|
+
];
|
|
36
|
+
|
|
37
|
+
const results = emotion_results(sampleTrials);
|
|
38
|
+
|
|
39
|
+
expect(results.n).toBe(3);
|
|
40
|
+
expect(results.avg_rt).toBe(800); // (1000 + 1500 + 2000) / 3
|
|
41
|
+
expect(results.avg_acc).toBe(2/3); // (1 + 1 + 0) / 3
|
|
42
|
+
expect(results.performance).toBeGreaterThan(0);
|
|
43
|
+
expect(results.performance).toBeLessThanOrEqual(100);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('should handle empty trials array', () => {
|
|
47
|
+
// When given an empty array, it should handle it gracefully
|
|
48
|
+
expect(() => emotion_results([])).toThrow();
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
describe('emotion_calculate_results', () => {
|
|
53
|
+
it('should process raw data and return valid results', () => {
|
|
54
|
+
const results = emotion_calculate_results(emotionsData);
|
|
55
|
+
console.log(results);
|
|
56
|
+
expect(results).toHaveProperty('n');
|
|
57
|
+
expect(results).toHaveProperty('avg_rt');
|
|
58
|
+
expect(results).toHaveProperty('avg_acc');
|
|
59
|
+
expect(results).toHaveProperty('performance');
|
|
60
|
+
|
|
61
|
+
expect(results.performance).toBeGreaterThan(0);
|
|
62
|
+
expect(results.performance).toBeLessThanOrEqual(100);
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
});
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { gonogo_extract_trials, gonogo_results, gonogo_calculate_results } from '../../gonogo';
|
|
2
|
+
import { loadTestData } from '../test-utils/testData';
|
|
3
|
+
|
|
4
|
+
describe('Gonogo test module', () => {
|
|
5
|
+
// If gonogo data is available in your test data, load it
|
|
6
|
+
// const gonogoData = loadTestData('gonogo').gonogo;
|
|
7
|
+
|
|
8
|
+
const gonogoData = loadTestData('gonogo').gonogo;
|
|
9
|
+
|
|
10
|
+
const mockTrials = [
|
|
11
|
+
{
|
|
12
|
+
image: "https://unyavwofnmwihnpvkjji.supabase.co/storage/v1/object/public/test-stimuli/gonogo/aliens/astronaut_trans_1.png",
|
|
13
|
+
rt: 846,
|
|
14
|
+
response: 0,
|
|
15
|
+
block_number:1
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
image: "https://unyavwofnmwihnpvkjji.supabase.co/storage/v1/object/public/test-stimuli/gonogo/aliens/alien_trans_1.png",
|
|
19
|
+
rt: null,
|
|
20
|
+
response: null,
|
|
21
|
+
block_number: 1
|
|
22
|
+
},
|
|
23
|
+
];
|
|
24
|
+
|
|
25
|
+
describe('gonogo_extract_trials', () => {
|
|
26
|
+
it('should extract trials from raw data', () => {
|
|
27
|
+
const trials = gonogo_extract_trials(gonogoData);
|
|
28
|
+
// consolo log trials which have block number 3
|
|
29
|
+
expect(trials.length).toBeLessThan(gonogoData.length);
|
|
30
|
+
|
|
31
|
+
trials.forEach(trial => {
|
|
32
|
+
expect(trial).toHaveProperty('stimulus');
|
|
33
|
+
expect(trial).toHaveProperty('stimulustype');
|
|
34
|
+
expect(trial).toHaveProperty('should_go');
|
|
35
|
+
expect(trial).toHaveProperty('did_go');
|
|
36
|
+
expect(trial).toHaveProperty('correct');
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('should handle empty data array', () => {
|
|
41
|
+
const trials = gonogo_extract_trials([]);
|
|
42
|
+
expect(trials).toEqual([]);
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
describe('gonogo_results', () => {
|
|
47
|
+
it('should calculate correct averages', () => {
|
|
48
|
+
const sampleTrials = [
|
|
49
|
+
{ rt: 500, correct: true, should_go: true, did_go: true },
|
|
50
|
+
{ rt: 600, correct: true, should_go: false, did_go: false },
|
|
51
|
+
{ rt: 700, correct: false, should_go: true, did_go: false },
|
|
52
|
+
];
|
|
53
|
+
|
|
54
|
+
const results = gonogo_results(sampleTrials);
|
|
55
|
+
console.log(results)
|
|
56
|
+
expect(results.n).toBe(3);
|
|
57
|
+
expect(results.avg_rt).toBe(600); // (500 + 600 + 700) / 3
|
|
58
|
+
expect(results.avg_acc).toBe(2/3); // (1 + 1 + 0) / 3
|
|
59
|
+
expect(results.performance).toBeGreaterThan(0);
|
|
60
|
+
expect(results.performance).toBeLessThanOrEqual(100);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it('should handle empty trials array', () => {
|
|
64
|
+
expect(() => gonogo_results([])).toThrow();
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
describe('gonogo_calculate_results', () => {
|
|
69
|
+
it('should process raw data and return valid results', () => {
|
|
70
|
+
const results = gonogo_calculate_results(gonogoData);
|
|
71
|
+
console.log(results);
|
|
72
|
+
expect(results).toHaveProperty('n');
|
|
73
|
+
expect(results).toHaveProperty('avg_rt');
|
|
74
|
+
expect(results).toHaveProperty('avg_acc');
|
|
75
|
+
expect(results).toHaveProperty('performance');
|
|
76
|
+
|
|
77
|
+
expect(results.performance).toBeGreaterThan(0);
|
|
78
|
+
expect(results.performance).toBeLessThanOrEqual(100);
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
});
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// test out the spatial_extract_image_info function
|
|
2
|
-
import { spatial_extract_image_info,
|
|
2
|
+
import { spatial_extract_image_info, spatial_calculate_results,
|
|
3
|
+
spatial_results } from '../../spatial-cognition';
|
|
3
4
|
import { loadTestData } from '../test-utils/testData';
|
|
4
5
|
|
|
5
6
|
const ImageInfoTestData = [
|
|
@@ -55,5 +56,11 @@ describe('spatial_results test data', () => {
|
|
|
55
56
|
console.log(resultsTestData);
|
|
56
57
|
expect(resultsTestData).toBeDefined();
|
|
57
58
|
});
|
|
59
|
+
test('processes real data correctly', () => {
|
|
60
|
+
const testData = loadTestData('spatialCognition').spatialCognition;
|
|
61
|
+
const resultData = spatial_calculate_results(testData);
|
|
62
|
+
console.log(resultData);
|
|
63
|
+
expect(resultData).toBeDefined();
|
|
64
|
+
});
|
|
58
65
|
});
|
|
59
66
|
|
package/src/emotions.ts
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
interface EmotionResults {
|
|
2
|
+
n: number;
|
|
3
|
+
avg_rt: number;
|
|
4
|
+
avg_acc: number;
|
|
5
|
+
performance: number;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const emotion_calculate_results = (obj: any[]): EmotionResults => {
|
|
9
|
+
const trials = emotion_extract_trials(obj);
|
|
10
|
+
// throw if trials is empty
|
|
11
|
+
if (trials.length === 0) {
|
|
12
|
+
throw new Error("No trials found");
|
|
13
|
+
}
|
|
14
|
+
return emotion_results(trials);
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const emotion_results = (obj: any[]): EmotionResults => {
|
|
18
|
+
// throw error if obj is empty
|
|
19
|
+
if (obj.length === 0) {
|
|
20
|
+
throw new Error("No trials found");
|
|
21
|
+
}
|
|
22
|
+
let results = {
|
|
23
|
+
n: obj.length,
|
|
24
|
+
avg_rt: obj.reduce((a, b) => a + b.rt, 0) / obj.length,
|
|
25
|
+
avg_acc: obj.reduce((a, b) => a + b.correct, 0) / obj.length,
|
|
26
|
+
performance: NaN
|
|
27
|
+
};
|
|
28
|
+
const best_score = 1000;
|
|
29
|
+
const worst_score = 10000;
|
|
30
|
+
let performance = results.avg_rt / (Math.pow(results.avg_acc, 5) + 0.001);
|
|
31
|
+
performance = Math.min(Math.max(performance, best_score), worst_score);
|
|
32
|
+
results.performance = (1 - ((performance - best_score) / (worst_score - best_score))) * 100;
|
|
33
|
+
return results;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const emotion_extract_trials = (obj: any[]) => {
|
|
37
|
+
const emotionMap = ["neutral", "sad", "happy", "surprised", "angry"];
|
|
38
|
+
// filter trials where response and rt are defined and not null
|
|
39
|
+
let trials = obj.filter((o: any) => 'response' in o && 'rt' in o && 'emotion' in o);
|
|
40
|
+
trials = trials.filter((o: any) => o.response !== null && o.rt !== null);
|
|
41
|
+
trials.forEach((o: any) => {
|
|
42
|
+
const match = o.emotion.match(/\/([^/]+)_([0-9]+)\.png/);
|
|
43
|
+
if (match) {
|
|
44
|
+
o.stimulus = match[0];
|
|
45
|
+
o.emotion = match[1];
|
|
46
|
+
o.image_number = match[2];
|
|
47
|
+
//this is <emotion>_<number>.png
|
|
48
|
+
o.image = `${match[1]}_${match[2]}.png`;
|
|
49
|
+
}
|
|
50
|
+
})
|
|
51
|
+
trials.forEach((o: any) => {
|
|
52
|
+
o.emotion_response = emotionMap[o.response] || "unknown";
|
|
53
|
+
o.correct = o.emotion === o.emotion_response;
|
|
54
|
+
// in the older ones there were 15 trials per rotation
|
|
55
|
+
});
|
|
56
|
+
return trials;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export { emotion_calculate_results, emotion_extract_trials, emotion_results };
|
package/src/gonogo.ts
CHANGED
|
@@ -1,37 +1,76 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
// df <- select(df, trial_index, time_elapsed, rt,
|
|
7
|
-
// response, block_number, image)
|
|
8
|
-
// df$image <- gsub(GONOGO_IMAGE_PATH, "", df$image)
|
|
9
|
-
// df$image <- gsub(".png", "", df$image)
|
|
10
|
-
// df <- df %>%
|
|
11
|
-
// mutate(
|
|
12
|
-
// should_go = case_when(
|
|
13
|
-
// block_number == 1 & grepl("astronaut_trans_1", image) ~ TRUE,
|
|
14
|
-
// block_number == 2 & grepl("alien_trans_1", image) ~ TRUE,
|
|
15
|
-
// block_number == 3 & grepl("rocket_trans_1", image) ~ TRUE,
|
|
16
|
-
// block_number == 4 & !grepl("rocket_trans_1", image) ~ TRUE,
|
|
17
|
-
// TRUE ~ FALSE),
|
|
18
|
-
// did_go = !is.na(response),
|
|
19
|
-
// correct = should_go == did_go
|
|
20
|
-
// )
|
|
21
|
-
// return(df)
|
|
22
|
-
// }
|
|
23
|
-
|
|
24
|
-
const gonogo_calculate_results = (data: any) => {
|
|
25
|
-
|
|
1
|
+
interface GonogoResults {
|
|
2
|
+
n: number;
|
|
3
|
+
avg_rt: number;
|
|
4
|
+
avg_acc: number;
|
|
5
|
+
performance: number;
|
|
26
6
|
}
|
|
27
7
|
|
|
28
|
-
const
|
|
8
|
+
const gonogo_calculate_results = (data: any[]): GonogoResults => {
|
|
9
|
+
const trials = gonogo_extract_trials(data);
|
|
10
|
+
const results = gonogo_results(trials);
|
|
11
|
+
return results;
|
|
12
|
+
}
|
|
29
13
|
|
|
30
|
-
|
|
14
|
+
const gonogo_extract_trials = (obj: any[]): any[] => {
|
|
15
|
+
// GONOGO_IMAGE_PATH <- "https://unyavwofnmwihnpvkjji.supabase.co/storage/v1/object/public/test-stimuli/gonogo/"
|
|
16
|
+
let trials = obj.filter((o: any) => 'image' in o && o.image !== undefined);
|
|
17
|
+
trials.forEach((o: any) => {
|
|
18
|
+
// image is in format <stimulus>_trans_<number>.png
|
|
19
|
+
// extract the stimulus and number
|
|
31
20
|
|
|
21
|
+
// "image": "https://unyavwofnmwihnpvkjji.supabase.co/storage/v1/object/public/test-stimuli/gonogo/aliens/astronaut_trans_1.png",
|
|
22
|
+
// i need to extract the iamge name from the url
|
|
23
|
+
const match = o.image.match(/([^/]+)_(\d+)\.png$/);
|
|
24
|
+
if (match) {
|
|
25
|
+
o.stimulus = match[0];
|
|
26
|
+
o.stimulustype = match[1];
|
|
27
|
+
o.image_number = match[2];
|
|
28
|
+
} else {
|
|
29
|
+
console.warn('Image format did not match expected pattern:', o.image);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
o.should_go = false;
|
|
33
|
+
o.did_go = o.response !== null;
|
|
34
|
+
switch (o.block_number) {
|
|
35
|
+
case 1:
|
|
36
|
+
o.should_go = o.stimulus == "astronaut_trans_1.png";
|
|
37
|
+
break;
|
|
38
|
+
case 2:
|
|
39
|
+
o.should_go = o.stimulus == "alien_trans_1.png";
|
|
40
|
+
break;
|
|
41
|
+
case 3:
|
|
42
|
+
o.should_go = o.stimulus == "rocket_trans_1.png";
|
|
43
|
+
break;
|
|
44
|
+
case 4:
|
|
45
|
+
// should go in all cases where the goal is NOT the rocket
|
|
46
|
+
o.should_go = !(o.stimulus == "rocket_trans_1.png");
|
|
47
|
+
break;
|
|
48
|
+
default:
|
|
49
|
+
o.should_go = false;
|
|
50
|
+
break;
|
|
51
|
+
}
|
|
52
|
+
o.correct = o.should_go == o.did_go;
|
|
53
|
+
})
|
|
54
|
+
return trials;
|
|
32
55
|
}
|
|
33
56
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
57
|
+
const gonogo_results = (data: any[]): GonogoResults => {
|
|
58
|
+
// throw error if obj is empty
|
|
59
|
+
if (data.length === 0) {
|
|
60
|
+
throw new Error("No trials found");
|
|
61
|
+
}
|
|
62
|
+
let results = {
|
|
63
|
+
n: data.length,
|
|
64
|
+
avg_rt: data.reduce((a, b) => a + b.rt, 0) / data.length,
|
|
65
|
+
avg_acc: data.reduce((a, b) => a + b.correct, 0) / data.length,
|
|
66
|
+
performance: NaN
|
|
67
|
+
};
|
|
68
|
+
const best_score = 300;
|
|
69
|
+
const worst_score = 5000;
|
|
70
|
+
let performance = results.avg_rt / (Math.pow(results.avg_acc, 5) + 0.001);
|
|
71
|
+
performance = Math.min(Math.max(performance, best_score), worst_score);
|
|
72
|
+
results.performance = (1 - ((performance - best_score) / (worst_score - best_score))) * 100;
|
|
73
|
+
return results;
|
|
37
74
|
}
|
|
75
|
+
|
|
76
|
+
export { gonogo_calculate_results, gonogo_extract_trials, gonogo_results };
|
package/src/spatial-cognition.ts
CHANGED
|
@@ -27,13 +27,9 @@ const spatial_results = (obj: any[]): SpatialResults => {
|
|
|
27
27
|
const best_score = 1000;
|
|
28
28
|
const worst_score = 10000;
|
|
29
29
|
// results.avg_acc to the power of 5
|
|
30
|
-
let performance = results.avg_rt / (Math.pow(results.avg_acc, 5) + 0.001);
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
}
|
|
34
|
-
if (performance > worst_score) {
|
|
35
|
-
performance = worst_score;
|
|
36
|
-
}
|
|
30
|
+
//let performance = results.avg_rt / (Math.pow(results.avg_acc, 5) + 0.001);
|
|
31
|
+
let performance = results.avg_rt / (results.avg_acc + 0.001);
|
|
32
|
+
performance = Math.min(Math.max(performance, best_score), worst_score);
|
|
37
33
|
// convert to 0-100 where 100 is the best (200)
|
|
38
34
|
results.performance = (1 - ((performance - best_score) / (worst_score - best_score))) * 100;
|
|
39
35
|
return results;
|