compileprofile-spacetests 0.2.1 → 0.4.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/CLAUDE.md +115 -0
- package/README.md +152 -15
- package/dist/cjs/common-interfaces.d.ts +92 -0
- package/dist/cjs/common-interfaces.js +2 -0
- package/dist/cjs/emotions.d.ts +2 -7
- package/dist/cjs/emotions.js +56 -22
- package/dist/cjs/gonogo.d.ts +1 -6
- package/dist/cjs/gonogo.js +125 -46
- package/dist/cjs/index.d.ts +2 -5
- package/dist/cjs/nback.d.ts +6 -12
- package/dist/cjs/nback.js +159 -15
- package/dist/cjs/spatial-cognition.d.ts +1 -6
- package/dist/cjs/spatial-cognition.js +67 -14
- package/dist/esm/common-interfaces.d.ts +92 -0
- package/dist/esm/common-interfaces.js +1 -0
- package/dist/esm/emotions.d.ts +2 -7
- package/dist/esm/emotions.js +55 -21
- package/dist/esm/gonogo.d.ts +1 -6
- package/dist/esm/gonogo.js +125 -46
- package/dist/esm/index.d.ts +2 -5
- package/dist/esm/nback.d.ts +6 -12
- package/dist/esm/nback.js +155 -15
- package/dist/esm/spatial-cognition.d.ts +1 -6
- package/dist/esm/spatial-cognition.js +67 -14
- package/package.json +2 -2
- package/src/__tests__/integration/emotions.test.ts +122 -14
- package/src/__tests__/integration/gonogo.test.ts +240 -27
- package/src/__tests__/integration/nback-versions.test.ts +182 -0
- package/src/__tests__/integration/nback.test.ts +113 -20
- package/src/__tests__/integration/spatial-cognition.test.ts +106 -1
- package/src/common-interfaces.ts +125 -0
- package/src/emotions.ts +68 -29
- package/src/gonogo.ts +128 -55
- package/src/index.ts +22 -6
- package/src/nback.ts +160 -31
- package/src/spatial-cognition.ts +77 -21
package/dist/cjs/gonogo.js
CHANGED
|
@@ -1,71 +1,150 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __assign = (this && this.__assign) || function () {
|
|
3
|
+
__assign = Object.assign || function(t) {
|
|
4
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
5
|
+
s = arguments[i];
|
|
6
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
7
|
+
t[p] = s[p];
|
|
8
|
+
}
|
|
9
|
+
return t;
|
|
10
|
+
};
|
|
11
|
+
return __assign.apply(this, arguments);
|
|
12
|
+
};
|
|
2
13
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
14
|
exports.gonogo_results = exports.gonogo_extract_trials = exports.gonogo_calculate_results = void 0;
|
|
15
|
+
var BEST_SCORE = 300;
|
|
16
|
+
var WORST_SCORE = 5000;
|
|
4
17
|
var gonogo_calculate_results = function (data) {
|
|
5
18
|
var trials = gonogo_extract_trials(data);
|
|
6
19
|
var results = gonogo_results(trials);
|
|
7
20
|
return results;
|
|
8
21
|
};
|
|
9
22
|
exports.gonogo_calculate_results = gonogo_calculate_results;
|
|
23
|
+
// Which stimulus is "go" in each block of the runner:
|
|
24
|
+
// 1 astronaut, 2 alien, 3 rocket, 4 anything but the rocket (the UFOs).
|
|
25
|
+
var should_go_for = function (block_number, stimulus) {
|
|
26
|
+
switch (block_number) {
|
|
27
|
+
case 1: return stimulus == "astronaut_trans_1.png";
|
|
28
|
+
case 2: return stimulus == "alien_trans_1.png";
|
|
29
|
+
case 3: return stimulus == "rocket_trans_1.png";
|
|
30
|
+
case 4: return stimulus != "rocket_trans_1.png";
|
|
31
|
+
default: return false;
|
|
32
|
+
}
|
|
33
|
+
};
|
|
10
34
|
var gonogo_extract_trials = function (obj) {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
//
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
if (match) {
|
|
20
|
-
o.stimulus = match[0];
|
|
21
|
-
o.stimulustype = match[1];
|
|
22
|
-
o.image_number = match[2];
|
|
23
|
-
}
|
|
24
|
-
else {
|
|
35
|
+
var trials = [];
|
|
36
|
+
obj.filter(function (o) { return 'image' in o && o.image !== undefined && o.image !== null; }).forEach(function (o) {
|
|
37
|
+
// image is in format <stimulus>_trans_<number>.png, e.g.
|
|
38
|
+
// ".../test-stimuli/gonogo/aliens/astronaut_trans_1.png"
|
|
39
|
+
var match = String(o.image).match(/([^/]+)_(\d+)\.png$/);
|
|
40
|
+
if (!match) {
|
|
41
|
+
// Without a recognisable stimulus the trial cannot be scored, so leave it out
|
|
42
|
+
// instead of counting it as neither correct nor incorrect.
|
|
25
43
|
console.warn('Image format did not match expected pattern:', o.image);
|
|
26
44
|
return;
|
|
27
45
|
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
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;
|
|
46
|
+
// Copy, so the caller's data is not modified.
|
|
47
|
+
var trial = __assign({}, o);
|
|
48
|
+
trial.stimulus = match[0];
|
|
49
|
+
trial.stimulustype = match[1];
|
|
50
|
+
trial.image_number = match[2];
|
|
51
|
+
// Prefer a go/no-go flag recorded by the runner; otherwise derive it from block and image.
|
|
52
|
+
trial.should_go = typeof o.should_go === 'boolean' ? o.should_go : should_go_for(o.block_number, trial.stimulus);
|
|
53
|
+
trial.did_go = o.response !== null && o.response !== undefined;
|
|
54
|
+
trial.correct = trial.should_go == trial.did_go;
|
|
55
|
+
trials.push(trial);
|
|
49
56
|
});
|
|
50
57
|
return trials;
|
|
51
58
|
};
|
|
52
59
|
exports.gonogo_extract_trials = gonogo_extract_trials;
|
|
60
|
+
var has_rt = function (o) { return o.did_go === true && typeof o.rt === 'number' && !isNaN(o.rt); };
|
|
61
|
+
// Mean of the values; 0 for an empty list, so callers always get a number.
|
|
62
|
+
var mean = function (values) { return values.length > 0 ? values.reduce(function (a, b) { return a + b; }, 0) / values.length : 0; };
|
|
63
|
+
// Mean RT over the trials that have a response; trials without one have no RT and are not averaged in as 0.
|
|
64
|
+
var mean_rt = function (trials) { return mean(trials.filter(has_rt).map(function (o) { return o.rt; })); };
|
|
65
|
+
var proportion = function (trials, pred) {
|
|
66
|
+
return trials.length > 0 ? trials.filter(pred).length / trials.length : 0;
|
|
67
|
+
};
|
|
68
|
+
// Hit rate and correct-rejection rate weighted equally. When a set has no go (or no no-go)
|
|
69
|
+
// trials, the other rate is used alone.
|
|
70
|
+
var balanced_accuracy = function (go_trials, nogo_trials) {
|
|
71
|
+
var rates = [];
|
|
72
|
+
if (go_trials.length > 0)
|
|
73
|
+
rates.push(proportion(go_trials, function (o) { return o.correct === true; }));
|
|
74
|
+
if (nogo_trials.length > 0)
|
|
75
|
+
rates.push(proportion(nogo_trials, function (o) { return o.correct === true; }));
|
|
76
|
+
return mean(rates);
|
|
77
|
+
};
|
|
78
|
+
// Score 0-100 from the hit RT and the balanced accuracy: RT / (acc^5), clamped to 300-5000 ms.
|
|
79
|
+
// Without any hit there is no RT to score, so the score is 0. (Previously an RT of 0 was
|
|
80
|
+
// clamped to the best value, so a participant who never responded scored 100.)
|
|
81
|
+
var calculate_performance_score = function (hit_rt, acc) {
|
|
82
|
+
if (!(hit_rt > 0)) {
|
|
83
|
+
return 0;
|
|
84
|
+
}
|
|
85
|
+
var performance = hit_rt / (Math.pow(acc, 5) + 0.001);
|
|
86
|
+
performance = Math.min(Math.max(performance, BEST_SCORE), WORST_SCORE);
|
|
87
|
+
var performance_score = (1 - ((performance - BEST_SCORE) / (WORST_SCORE - BEST_SCORE))) * 100;
|
|
88
|
+
return performance_score;
|
|
89
|
+
};
|
|
53
90
|
var gonogo_results = function (data) {
|
|
54
91
|
// throw error if obj is empty
|
|
55
92
|
if (data.length === 0) {
|
|
56
93
|
throw new Error("No trials found");
|
|
57
94
|
}
|
|
58
|
-
var
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
95
|
+
var correct_trials = data.filter(function (o) { return o.correct === true; });
|
|
96
|
+
var incorrect_trials = data.filter(function (o) { return o.correct === false; });
|
|
97
|
+
var go_trials = data.filter(function (o) { return o.should_go === true; });
|
|
98
|
+
var nogo_trials = data.filter(function (o) { return o.should_go === false; });
|
|
99
|
+
// A response is correct on go trials (hit) and incorrect on no-go trials (false alarm).
|
|
100
|
+
// Correct no-go trials and missed go trials have no response, so no RT.
|
|
101
|
+
var hit_rt = mean_rt(go_trials);
|
|
102
|
+
var balanced_acc = balanced_accuracy(go_trials, nogo_trials);
|
|
103
|
+
var common = {
|
|
104
|
+
n_trials: data.length,
|
|
105
|
+
n_correct_trials: correct_trials.length,
|
|
106
|
+
n_incorrect_trials: incorrect_trials.length,
|
|
107
|
+
avg_rt_total: mean_rt(data),
|
|
108
|
+
avg_rt_correct: mean_rt(correct_trials),
|
|
109
|
+
avg_rt_incorrect: mean_rt(incorrect_trials),
|
|
110
|
+
performance_score: calculate_performance_score(hit_rt, balanced_acc)
|
|
111
|
+
};
|
|
112
|
+
// Group by block for special results
|
|
113
|
+
var by_block = Object.values(data.reduce(function (acc, trial) {
|
|
114
|
+
var key = trial.block_number || 'unknown';
|
|
115
|
+
if (!acc[key])
|
|
116
|
+
acc[key] = { block: key, trials: [] };
|
|
117
|
+
acc[key].trials.push(trial);
|
|
118
|
+
return acc;
|
|
119
|
+
}, {})).map(function (group) {
|
|
120
|
+
var block_go = group.trials.filter(function (o) { return o.should_go === true; });
|
|
121
|
+
var block_nogo = group.trials.filter(function (o) { return o.should_go === false; });
|
|
122
|
+
group.avg_rt = mean_rt(block_go);
|
|
123
|
+
group.avg_acc = proportion(group.trials, function (o) { return o.correct === true; });
|
|
124
|
+
group.hit_rate = proportion(block_go, function (o) { return o.correct === true; });
|
|
125
|
+
group.correct_rejection_rate = proportion(block_nogo, function (o) { return o.correct === true; });
|
|
126
|
+
group.balanced_acc = balanced_accuracy(block_go, block_nogo);
|
|
127
|
+
return group;
|
|
128
|
+
});
|
|
129
|
+
var special = {
|
|
130
|
+
balanced_acc: balanced_acc,
|
|
131
|
+
by_block: by_block,
|
|
132
|
+
go_trials: {
|
|
133
|
+
n: go_trials.length,
|
|
134
|
+
avg_rt: hit_rt,
|
|
135
|
+
avg_acc: proportion(go_trials, function (o) { return o.correct === true; }),
|
|
136
|
+
n_omissions: go_trials.filter(function (o) { return o.did_go === false; }).length,
|
|
137
|
+
},
|
|
138
|
+
nogo_trials: {
|
|
139
|
+
n: nogo_trials.length,
|
|
140
|
+
avg_rt: mean_rt(nogo_trials),
|
|
141
|
+
avg_acc: proportion(nogo_trials, function (o) { return o.correct === true; }),
|
|
142
|
+
n_commissions: nogo_trials.filter(function (o) { return o.did_go === true; }).length,
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
return {
|
|
146
|
+
common: common,
|
|
147
|
+
special: special
|
|
63
148
|
};
|
|
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;
|
|
70
149
|
};
|
|
71
150
|
exports.gonogo_results = gonogo_results;
|
package/dist/cjs/index.d.ts
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
|
-
import { NbackResultsStructure } from './
|
|
2
|
-
import { SpatialResultsStructure } from './spatial-cognition';
|
|
3
|
-
import { GonogoResultsStructure } from './gonogo';
|
|
4
|
-
import { EmotionResultsStructure } from './emotions';
|
|
1
|
+
import { NbackResultsStructure, SpatialResultsStructure, GonogoResultsStructure, EmotionResultsStructure, CommonResults } from './common-interfaces';
|
|
5
2
|
declare const NbackResults: (obj: any[]) => NbackResultsStructure;
|
|
6
3
|
declare const SpatialCognitionResults: (obj: any[]) => SpatialResultsStructure;
|
|
7
4
|
declare const GonogoResults: (obj: any[]) => GonogoResultsStructure;
|
|
8
5
|
declare const EmotionResults: (obj: any[]) => EmotionResultsStructure;
|
|
9
|
-
export { NbackResults, SpatialCognitionResults, EmotionResults, GonogoResults };
|
|
6
|
+
export { NbackResults, SpatialCognitionResults, EmotionResults, GonogoResults, NbackResultsStructure, SpatialResultsStructure, GonogoResultsStructure, EmotionResultsStructure, CommonResults };
|
package/dist/cjs/nback.d.ts
CHANGED
|
@@ -1,15 +1,9 @@
|
|
|
1
|
+
import { NbackResultsStructure, NbackGroupResults, NbackBlockResults, NbackLevelResults } from './common-interfaces';
|
|
1
2
|
declare const nback_calculate_results: (obj: any[]) => NbackResultsStructure;
|
|
2
3
|
declare const nback_extract_trials: (obj: any[]) => any[];
|
|
3
|
-
interface NbackTrialResultsStructure {
|
|
4
|
-
n: number;
|
|
5
|
-
avg_rt: number;
|
|
6
|
-
avg_acc: number;
|
|
7
|
-
}
|
|
8
|
-
interface NbackResultsStructure {
|
|
9
|
-
total_trials: NbackTrialResultsStructure;
|
|
10
|
-
target_trials: NbackTrialResultsStructure;
|
|
11
|
-
non_target_trials: NbackTrialResultsStructure;
|
|
12
|
-
performance: number;
|
|
13
|
-
}
|
|
14
4
|
declare const nback_results: (trials: any[]) => NbackResultsStructure;
|
|
15
|
-
|
|
5
|
+
declare const inverse_normal: (p: number) => number;
|
|
6
|
+
declare const nback_group_results: (trials: any[]) => NbackGroupResults;
|
|
7
|
+
declare const nback_results_by_block: (trials: any[]) => NbackBlockResults[];
|
|
8
|
+
declare const nback_results_by_nback: (trials: any[]) => NbackLevelResults[];
|
|
9
|
+
export { nback_extract_trials, nback_results, nback_calculate_results, nback_group_results, nback_results_by_block, nback_results_by_nback, inverse_normal, NbackResultsStructure };
|
package/dist/cjs/nback.js
CHANGED
|
@@ -1,12 +1,33 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __assign = (this && this.__assign) || function () {
|
|
3
|
+
__assign = Object.assign || function(t) {
|
|
4
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
5
|
+
s = arguments[i];
|
|
6
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
7
|
+
t[p] = s[p];
|
|
8
|
+
}
|
|
9
|
+
return t;
|
|
10
|
+
};
|
|
11
|
+
return __assign.apply(this, arguments);
|
|
12
|
+
};
|
|
2
13
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.nback_calculate_results = exports.nback_results = exports.nback_extract_trials = void 0;
|
|
14
|
+
exports.inverse_normal = exports.nback_results_by_nback = exports.nback_results_by_block = exports.nback_group_results = exports.nback_calculate_results = exports.nback_results = exports.nback_extract_trials = void 0;
|
|
4
15
|
// from the passed json extract those objects that have field is_target
|
|
16
|
+
// Version 1 trials have no n_back field and get exactly the original result. Version 2 trials
|
|
17
|
+
// (n_back, block, block_index on each trial) also get special.by_block and special.by_nback.
|
|
5
18
|
var nback_calculate_results = function (obj) {
|
|
6
19
|
var trials = nback_extract_trials(obj);
|
|
7
|
-
|
|
20
|
+
var results = nback_results(trials);
|
|
21
|
+
if (nback_is_versioned(trials)) {
|
|
22
|
+
results.special.by_block = nback_results_by_block(trials);
|
|
23
|
+
results.special.by_nback = nback_results_by_nback(trials);
|
|
24
|
+
}
|
|
25
|
+
return results;
|
|
8
26
|
};
|
|
9
27
|
exports.nback_calculate_results = nback_calculate_results;
|
|
28
|
+
var nback_is_versioned = function (trials) {
|
|
29
|
+
return trials.some(function (t) { return t.n_back !== undefined && t.n_back !== null; });
|
|
30
|
+
};
|
|
10
31
|
var nback_extract_trials = function (obj) {
|
|
11
32
|
var trials = obj.filter(function (o) { return 'is_target' in o; });
|
|
12
33
|
return trials;
|
|
@@ -15,26 +36,149 @@ exports.nback_extract_trials = nback_extract_trials;
|
|
|
15
36
|
var nback_results = function (trials) {
|
|
16
37
|
var target_trials = trials.filter(function (o) { return o.is_target; });
|
|
17
38
|
var non_target_trials = trials.filter(function (o) { return !o.is_target; });
|
|
18
|
-
var
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
39
|
+
var correct_trials = trials.filter(function (o) { return o.correct === true; });
|
|
40
|
+
var incorrect_trials = trials.filter(function (o) { return o.correct === false; });
|
|
41
|
+
var total_rt = trials.reduce(function (a, b) { return a + (b.rt || 0); }, 0);
|
|
42
|
+
var correct_rt = correct_trials.reduce(function (a, b) { return a + (b.rt || 0); }, 0);
|
|
43
|
+
var incorrect_rt = incorrect_trials.reduce(function (a, b) { return a + (b.rt || 0); }, 0);
|
|
44
|
+
var responded_trials = trials.filter(function (o) { return o.response !== null; });
|
|
45
|
+
var correct_responded_trials = responded_trials.filter(function (o) { return o.correct === true; });
|
|
46
|
+
var incorrect_responded_trials = responded_trials.filter(function (o) { return o.correct === false; });
|
|
47
|
+
var common = {
|
|
48
|
+
n_trials: trials.length,
|
|
49
|
+
n_correct_trials: correct_trials.length,
|
|
50
|
+
n_incorrect_trials: incorrect_trials.length,
|
|
51
|
+
avg_rt_total: trials.length > 0 ? total_rt / responded_trials.length : 0,
|
|
52
|
+
avg_rt_correct: correct_trials.length > 0 ? correct_rt / correct_responded_trials.length : 0,
|
|
53
|
+
avg_rt_incorrect: incorrect_trials.length > 0 ? incorrect_rt / incorrect_responded_trials.length : 0,
|
|
54
|
+
performance_score: trials.length > 0 ? correct_trials.length * 100 / trials.length : 0
|
|
55
|
+
};
|
|
56
|
+
var special = {
|
|
24
57
|
target_trials: {
|
|
25
58
|
n: target_trials.length,
|
|
26
|
-
avg_rt: target_trials.reduce(function (a, b) { return a + b.rt; }, 0) / target_trials.length,
|
|
27
|
-
avg_acc: target_trials.reduce(function (a, b) { return a + b.correct; }, 0) / target_trials.length,
|
|
59
|
+
avg_rt: target_trials.length > 0 ? target_trials.reduce(function (a, b) { return a + (b.rt || 0); }, 0) / target_trials.length : 0,
|
|
60
|
+
avg_acc: target_trials.length > 0 ? target_trials.reduce(function (a, b) { return a + (b.correct ? 1 : 0); }, 0) * 100 / target_trials.length : 0,
|
|
28
61
|
},
|
|
29
62
|
non_target_trials: {
|
|
30
63
|
n: non_target_trials.length,
|
|
31
|
-
avg_rt: non_target_trials.reduce(function (a, b) { return a + b.rt; }, 0) / non_target_trials.length,
|
|
32
|
-
avg_acc: non_target_trials.reduce(function (a, b) { return a + b.correct; }, 0) / non_target_trials.length,
|
|
33
|
-
}
|
|
34
|
-
|
|
64
|
+
avg_rt: non_target_trials.length > 0 ? non_target_trials.reduce(function (a, b) { return a + (b.rt || 0); }, 0) / non_target_trials.length : 0,
|
|
65
|
+
avg_acc: non_target_trials.length > 0 ? non_target_trials.reduce(function (a, b) { return a + (b.correct ? 1 : 0); }, 0) * 100 / non_target_trials.length : 0,
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
var results = {
|
|
69
|
+
common: common,
|
|
70
|
+
special: special
|
|
35
71
|
};
|
|
36
|
-
results.performance = results.total_trials.avg_acc;
|
|
37
72
|
console.log(results);
|
|
38
73
|
return results;
|
|
39
74
|
};
|
|
40
75
|
exports.nback_results = nback_results;
|
|
76
|
+
// Standard normal CDF (Marsaglia 2004, Taylor series; absolute error ~1e-15 for |x| < 8)
|
|
77
|
+
var normal_cdf = function (x) {
|
|
78
|
+
var sum = x, term = x, prev = 0;
|
|
79
|
+
var x2 = x * x;
|
|
80
|
+
for (var i = 3; sum !== prev; i += 2) {
|
|
81
|
+
prev = sum;
|
|
82
|
+
term *= x2 / i;
|
|
83
|
+
sum = prev + term;
|
|
84
|
+
}
|
|
85
|
+
return 0.5 + sum * Math.exp(-0.5 * x2 - 0.91893853320467274178);
|
|
86
|
+
};
|
|
87
|
+
// Inverse of the standard normal CDF: Acklam's rational approximation, polished with one
|
|
88
|
+
// Halley step against normal_cdf, as Acklam recommends. Accurate to ~1e-12 for 1e-10 < p < 1 - 1e-10.
|
|
89
|
+
var inverse_normal = function (p) {
|
|
90
|
+
if (p <= 0)
|
|
91
|
+
return -Infinity;
|
|
92
|
+
if (p >= 1)
|
|
93
|
+
return Infinity;
|
|
94
|
+
var x = acklam_inverse_normal(p);
|
|
95
|
+
var e = normal_cdf(x) - p;
|
|
96
|
+
var u = e * Math.sqrt(2 * Math.PI) * Math.exp(x * x / 2);
|
|
97
|
+
return x - u / (1 + x * u / 2);
|
|
98
|
+
};
|
|
99
|
+
exports.inverse_normal = inverse_normal;
|
|
100
|
+
var acklam_inverse_normal = function (p) {
|
|
101
|
+
var a = [-3.969683028665376e+01, 2.209460984245205e+02, -2.759285104469687e+02,
|
|
102
|
+
1.383577518672690e+02, -3.066479806614716e+01, 2.506628277459239e+00];
|
|
103
|
+
var b = [-5.447609879822406e+01, 1.615858368580409e+02, -1.556989798598866e+02,
|
|
104
|
+
6.680131188771972e+01, -1.328068155288572e+01];
|
|
105
|
+
var c = [-7.784894002430293e-03, -3.223964580411365e-01, -2.400758277161838e+00,
|
|
106
|
+
-2.549671010322563e+00, 4.374664141464968e+00, 2.938163982698783e+00];
|
|
107
|
+
var d = [7.784695709041462e-03, 3.224671290700398e-01, 2.445134137142996e+00,
|
|
108
|
+
3.754408661907416e+00];
|
|
109
|
+
var p_low = 0.02425;
|
|
110
|
+
if (p < p_low) {
|
|
111
|
+
var q_1 = Math.sqrt(-2 * Math.log(p));
|
|
112
|
+
return (((((c[0] * q_1 + c[1]) * q_1 + c[2]) * q_1 + c[3]) * q_1 + c[4]) * q_1 + c[5]) /
|
|
113
|
+
((((d[0] * q_1 + d[1]) * q_1 + d[2]) * q_1 + d[3]) * q_1 + 1);
|
|
114
|
+
}
|
|
115
|
+
if (p > 1 - p_low)
|
|
116
|
+
return -acklam_inverse_normal(1 - p);
|
|
117
|
+
var q = p - 0.5;
|
|
118
|
+
var r = q * q;
|
|
119
|
+
return (((((a[0] * r + a[1]) * r + a[2]) * r + a[3]) * r + a[4]) * r + a[5]) * q /
|
|
120
|
+
(((((b[0] * r + b[1]) * r + b[2]) * r + b[3]) * r + b[4]) * r + 1);
|
|
121
|
+
};
|
|
122
|
+
var mean_or_null = function (xs) {
|
|
123
|
+
return xs.length > 0 ? xs.reduce(function (s, x) { return s + x; }, 0) / xs.length : null;
|
|
124
|
+
};
|
|
125
|
+
var responded = function (t) { return t.response !== null && t.response !== undefined; };
|
|
126
|
+
// d' uses the log-linear correction (Hautus 1995), so it stays finite at 0 % or 100 % rates
|
|
127
|
+
var nback_group_results = function (trials) {
|
|
128
|
+
var targets = trials.filter(function (t) { return t.is_target; });
|
|
129
|
+
var non_targets = trials.filter(function (t) { return !t.is_target; });
|
|
130
|
+
var hits = targets.filter(responded);
|
|
131
|
+
var false_alarms = non_targets.filter(responded);
|
|
132
|
+
var lures = non_targets.filter(function (t) { return t.is_lure === true; });
|
|
133
|
+
var lure_false_alarms = lures.filter(responded).length;
|
|
134
|
+
var n_correct = trials.filter(function (t) { return t.correct === true; }).length;
|
|
135
|
+
var rts = function (ts) { return ts.map(function (t) { return t.rt; }).filter(function (rt) { return typeof rt === 'number'; }); };
|
|
136
|
+
return {
|
|
137
|
+
n_trials: trials.length,
|
|
138
|
+
n_correct_trials: n_correct,
|
|
139
|
+
performance_score: trials.length > 0 ? n_correct * 100 / trials.length : 0,
|
|
140
|
+
n_targets: targets.length,
|
|
141
|
+
n_non_targets: non_targets.length,
|
|
142
|
+
hits: hits.length,
|
|
143
|
+
misses: targets.length - hits.length,
|
|
144
|
+
false_alarms: false_alarms.length,
|
|
145
|
+
correct_rejections: non_targets.length - false_alarms.length,
|
|
146
|
+
hit_rate: targets.length > 0 ? hits.length / targets.length : null,
|
|
147
|
+
false_alarm_rate: non_targets.length > 0 ? false_alarms.length / non_targets.length : null,
|
|
148
|
+
d_prime: targets.length > 0 && non_targets.length > 0
|
|
149
|
+
? inverse_normal((hits.length + 0.5) / (targets.length + 1))
|
|
150
|
+
- inverse_normal((false_alarms.length + 0.5) / (non_targets.length + 1))
|
|
151
|
+
: null,
|
|
152
|
+
n_lures: lures.length,
|
|
153
|
+
lure_false_alarms: lure_false_alarms,
|
|
154
|
+
lure_false_alarm_rate: lures.length > 0 ? lure_false_alarms / lures.length : null,
|
|
155
|
+
avg_rt_hits: mean_or_null(rts(hits)),
|
|
156
|
+
avg_rt_false_alarms: mean_or_null(rts(false_alarms)),
|
|
157
|
+
};
|
|
158
|
+
};
|
|
159
|
+
exports.nback_group_results = nback_group_results;
|
|
160
|
+
var nback_results_by_block = function (trials) {
|
|
161
|
+
var blocks = new Map();
|
|
162
|
+
for (var _i = 0, trials_1 = trials; _i < trials_1.length; _i++) {
|
|
163
|
+
var t = trials_1[_i];
|
|
164
|
+
if (!blocks.has(t.block_index))
|
|
165
|
+
blocks.set(t.block_index, []);
|
|
166
|
+
blocks.get(t.block_index).push(t);
|
|
167
|
+
}
|
|
168
|
+
return Array.from(blocks.entries())
|
|
169
|
+
.sort(function (_a, _b) {
|
|
170
|
+
var a = _a[0];
|
|
171
|
+
var b = _b[0];
|
|
172
|
+
return a - b;
|
|
173
|
+
})
|
|
174
|
+
.map(function (_a) {
|
|
175
|
+
var block_index = _a[0], ts = _a[1];
|
|
176
|
+
return (__assign({ block: ts[0].block, block_index: block_index, n_back: ts[0].n_back }, nback_group_results(ts)));
|
|
177
|
+
});
|
|
178
|
+
};
|
|
179
|
+
exports.nback_results_by_block = nback_results_by_block;
|
|
180
|
+
var nback_results_by_nback = function (trials) {
|
|
181
|
+
var levels = Array.from(new Set(trials.map(function (t) { return t.n_back; }))).sort(function (a, b) { return a - b; });
|
|
182
|
+
return levels.map(function (n_back) { return (__assign({ n_back: n_back }, nback_group_results(trials.filter(function (t) { return t.n_back === n_back; })))); });
|
|
183
|
+
};
|
|
184
|
+
exports.nback_results_by_nback = nback_results_by_nback;
|
|
@@ -1,9 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
n: number;
|
|
3
|
-
avg_rt: number;
|
|
4
|
-
avg_acc: number;
|
|
5
|
-
performance: number;
|
|
6
|
-
}
|
|
1
|
+
import { SpatialResultsStructure } from './common-interfaces';
|
|
7
2
|
declare const spatial_calculate_results: (obj: any[]) => SpatialResultsStructure;
|
|
8
3
|
declare const spatial_extract_trials: (obj: any[]) => any[];
|
|
9
4
|
declare const spatial_results: (obj: any[]) => SpatialResultsStructure;
|
|
@@ -1,11 +1,19 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.spatial_calculate_results = exports.spatial_results = exports.spatial_extract_trials = exports.spatial_extract_image_info = void 0;
|
|
4
|
+
var BEST_SCORE = 1000;
|
|
5
|
+
var WORST_SCORE = 10000;
|
|
4
6
|
var spatial_calculate_results = function (obj) {
|
|
5
7
|
var trials = spatial_extract_trials(obj);
|
|
6
8
|
return spatial_results(trials);
|
|
7
9
|
};
|
|
8
10
|
exports.spatial_calculate_results = spatial_calculate_results;
|
|
11
|
+
var calculate_performance_score = function (avg_rt, avg_acc) {
|
|
12
|
+
var performance = avg_rt / (avg_acc + 0.001);
|
|
13
|
+
performance = Math.min(Math.max(performance, BEST_SCORE), WORST_SCORE);
|
|
14
|
+
var performance_score = (1 - ((performance - BEST_SCORE) / (WORST_SCORE - BEST_SCORE))) * 100;
|
|
15
|
+
return performance_score;
|
|
16
|
+
};
|
|
9
17
|
var spatial_extract_trials = function (obj) {
|
|
10
18
|
var trials = obj.filter(function (o) { return 'stimulus' in o &&
|
|
11
19
|
o.stimulus.startsWith("<img src="); });
|
|
@@ -14,21 +22,66 @@ var spatial_extract_trials = function (obj) {
|
|
|
14
22
|
};
|
|
15
23
|
exports.spatial_extract_trials = spatial_extract_trials;
|
|
16
24
|
var spatial_results = function (obj) {
|
|
17
|
-
var
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
25
|
+
var correct_trials = obj.filter(function (o) { return o.correct === 1 || o.correct === true; });
|
|
26
|
+
var incorrect_trials = obj.filter(function (o) { return o.correct === 0 || o.correct === false; });
|
|
27
|
+
var total_rt = obj.reduce(function (a, b) { return a + (b.rt || 0); }, 0);
|
|
28
|
+
var correct_rt = correct_trials.reduce(function (a, b) { return a + (b.rt || 0); }, 0);
|
|
29
|
+
var incorrect_rt = incorrect_trials.reduce(function (a, b) { return a + (b.rt || 0); }, 0);
|
|
30
|
+
var avg_rt = obj.length > 0 ? total_rt / obj.length : 0;
|
|
31
|
+
var avg_acc = obj.length > 0 ? correct_trials.length / obj.length : 0;
|
|
32
|
+
var performance_score = calculate_performance_score(avg_rt, avg_acc);
|
|
33
|
+
var common = {
|
|
34
|
+
n_trials: obj.length,
|
|
35
|
+
n_correct_trials: correct_trials.length,
|
|
36
|
+
n_incorrect_trials: incorrect_trials.length,
|
|
37
|
+
avg_rt_total: avg_rt,
|
|
38
|
+
avg_rt_correct: correct_trials.length > 0 ? correct_rt / correct_trials.length : 0,
|
|
39
|
+
avg_rt_incorrect: incorrect_trials.length > 0 ? incorrect_rt / incorrect_trials.length : 0,
|
|
40
|
+
performance_score: performance_score
|
|
41
|
+
};
|
|
42
|
+
// Group by distance, angle, and rotation for special results
|
|
43
|
+
var by_distance = Object.values(obj.reduce(function (acc, trial) {
|
|
44
|
+
var key = trial.distance || 'unknown';
|
|
45
|
+
if (!acc[key])
|
|
46
|
+
acc[key] = { distance: key, trials: [], avg_rt: 0, avg_acc: 0 };
|
|
47
|
+
acc[key].trials.push(trial);
|
|
48
|
+
return acc;
|
|
49
|
+
}, {})).map(function (group) {
|
|
50
|
+
group.avg_rt = group.trials.reduce(function (a, b) { return a + (b.rt || 0); }, 0) / group.trials.length;
|
|
51
|
+
group.avg_acc = group.trials.reduce(function (a, b) { return a + (b.correct ? 1 : 0); }, 0) / group.trials.length;
|
|
52
|
+
return group;
|
|
53
|
+
});
|
|
54
|
+
var by_angle = Object.values(obj.reduce(function (acc, trial) {
|
|
55
|
+
var key = trial.angle || 'unknown';
|
|
56
|
+
if (!acc[key])
|
|
57
|
+
acc[key] = { angle: key, trials: [], avg_rt: 0, avg_acc: 0 };
|
|
58
|
+
acc[key].trials.push(trial);
|
|
59
|
+
return acc;
|
|
60
|
+
}, {})).map(function (group) {
|
|
61
|
+
group.avg_rt = group.trials.reduce(function (a, b) { return a + (b.rt || 0); }, 0) / group.trials.length;
|
|
62
|
+
group.avg_acc = group.trials.reduce(function (a, b) { return a + (b.correct ? 1 : 0); }, 0) / group.trials.length;
|
|
63
|
+
return group;
|
|
64
|
+
});
|
|
65
|
+
var by_rotation = Object.values(obj.reduce(function (acc, trial) {
|
|
66
|
+
var key = trial.rotation || 'unknown';
|
|
67
|
+
if (!acc[key])
|
|
68
|
+
acc[key] = { rotation: key, trials: [], avg_rt: 0, avg_acc: 0 };
|
|
69
|
+
acc[key].trials.push(trial);
|
|
70
|
+
return acc;
|
|
71
|
+
}, {})).map(function (group) {
|
|
72
|
+
group.avg_rt = group.trials.reduce(function (a, b) { return a + (b.rt || 0); }, 0) / group.trials.length;
|
|
73
|
+
group.avg_acc = group.trials.reduce(function (a, b) { return a + (b.correct ? 1 : 0); }, 0) / group.trials.length;
|
|
74
|
+
return group;
|
|
75
|
+
});
|
|
76
|
+
var special = {
|
|
77
|
+
by_distance: by_distance,
|
|
78
|
+
by_angle: by_angle,
|
|
79
|
+
by_rotation: by_rotation
|
|
80
|
+
};
|
|
81
|
+
return {
|
|
82
|
+
common: common,
|
|
83
|
+
special: special
|
|
22
84
|
};
|
|
23
|
-
var best_score = 1000;
|
|
24
|
-
var worst_score = 10000;
|
|
25
|
-
// results.avg_acc to the power of 5
|
|
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);
|
|
29
|
-
// convert to 0-100 where 100 is the best (200)
|
|
30
|
-
results.performance = (1 - ((performance - best_score) / (worst_score - best_score))) * 100;
|
|
31
|
-
return results;
|
|
32
85
|
};
|
|
33
86
|
exports.spatial_results = spatial_results;
|
|
34
87
|
var spatial_extract_image_info = function (obj) {
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
interface CommonResults {
|
|
2
|
+
n_trials: number;
|
|
3
|
+
n_correct_trials: number;
|
|
4
|
+
n_incorrect_trials: number;
|
|
5
|
+
avg_rt_total: number;
|
|
6
|
+
avg_rt_correct: number;
|
|
7
|
+
avg_rt_incorrect: number;
|
|
8
|
+
performance_score: number;
|
|
9
|
+
}
|
|
10
|
+
interface NbackGroupResults {
|
|
11
|
+
n_trials: number;
|
|
12
|
+
n_correct_trials: number;
|
|
13
|
+
performance_score: number;
|
|
14
|
+
n_targets: number;
|
|
15
|
+
n_non_targets: number;
|
|
16
|
+
hits: number;
|
|
17
|
+
misses: number;
|
|
18
|
+
false_alarms: number;
|
|
19
|
+
correct_rejections: number;
|
|
20
|
+
hit_rate: number | null;
|
|
21
|
+
false_alarm_rate: number | null;
|
|
22
|
+
d_prime: number | null;
|
|
23
|
+
n_lures: number;
|
|
24
|
+
lure_false_alarms: number;
|
|
25
|
+
lure_false_alarm_rate: number | null;
|
|
26
|
+
avg_rt_hits: number | null;
|
|
27
|
+
avg_rt_false_alarms: number | null;
|
|
28
|
+
}
|
|
29
|
+
interface NbackBlockResults extends NbackGroupResults {
|
|
30
|
+
block: string;
|
|
31
|
+
block_index: number;
|
|
32
|
+
n_back: number;
|
|
33
|
+
}
|
|
34
|
+
interface NbackLevelResults extends NbackGroupResults {
|
|
35
|
+
n_back: number;
|
|
36
|
+
}
|
|
37
|
+
interface NbackSpecialResults {
|
|
38
|
+
target_trials: {
|
|
39
|
+
n: number;
|
|
40
|
+
avg_rt: number;
|
|
41
|
+
avg_acc: number;
|
|
42
|
+
};
|
|
43
|
+
non_target_trials: {
|
|
44
|
+
n: number;
|
|
45
|
+
avg_rt: number;
|
|
46
|
+
avg_acc: number;
|
|
47
|
+
};
|
|
48
|
+
by_block?: NbackBlockResults[];
|
|
49
|
+
by_nback?: NbackLevelResults[];
|
|
50
|
+
}
|
|
51
|
+
interface SpatialSpecialResults {
|
|
52
|
+
by_distance: any[];
|
|
53
|
+
by_angle: any[];
|
|
54
|
+
by_rotation: any[];
|
|
55
|
+
}
|
|
56
|
+
interface GonogoSpecialResults {
|
|
57
|
+
balanced_acc: number;
|
|
58
|
+
by_block: any[];
|
|
59
|
+
go_trials: {
|
|
60
|
+
n: number;
|
|
61
|
+
avg_rt: number;
|
|
62
|
+
avg_acc: number;
|
|
63
|
+
n_omissions: number;
|
|
64
|
+
};
|
|
65
|
+
nogo_trials: {
|
|
66
|
+
n: number;
|
|
67
|
+
avg_rt: number;
|
|
68
|
+
avg_acc: number;
|
|
69
|
+
n_commissions: number;
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
interface EmotionSpecialResults {
|
|
73
|
+
by_emotion: any[];
|
|
74
|
+
confusion_matrix: any;
|
|
75
|
+
}
|
|
76
|
+
interface NbackResultsStructure {
|
|
77
|
+
common: CommonResults;
|
|
78
|
+
special: NbackSpecialResults;
|
|
79
|
+
}
|
|
80
|
+
interface SpatialResultsStructure {
|
|
81
|
+
common: CommonResults;
|
|
82
|
+
special: SpatialSpecialResults;
|
|
83
|
+
}
|
|
84
|
+
interface GonogoResultsStructure {
|
|
85
|
+
common: CommonResults;
|
|
86
|
+
special: GonogoSpecialResults;
|
|
87
|
+
}
|
|
88
|
+
interface EmotionResultsStructure {
|
|
89
|
+
common: CommonResults;
|
|
90
|
+
special: EmotionSpecialResults;
|
|
91
|
+
}
|
|
92
|
+
export { CommonResults, NbackResultsStructure, SpatialResultsStructure, GonogoResultsStructure, EmotionResultsStructure, NbackSpecialResults, NbackGroupResults, NbackBlockResults, NbackLevelResults, SpatialSpecialResults, GonogoSpecialResults, EmotionSpecialResults };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/esm/emotions.d.ts
CHANGED
|
@@ -1,10 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
n: number;
|
|
3
|
-
avg_rt: number;
|
|
4
|
-
avg_acc: number;
|
|
5
|
-
performance: number;
|
|
6
|
-
}
|
|
1
|
+
import { EmotionResultsStructure } from './common-interfaces';
|
|
7
2
|
declare const emotion_calculate_results: (obj: any[]) => EmotionResultsStructure;
|
|
8
|
-
declare const emotion_results: (obj: any[]) => EmotionResultsStructure;
|
|
9
3
|
declare const emotion_extract_trials: (obj: any[]) => any[];
|
|
4
|
+
declare const emotion_results: (obj: any[]) => EmotionResultsStructure;
|
|
10
5
|
export { EmotionResultsStructure, emotion_calculate_results, emotion_extract_trials, emotion_results };
|