Skip to content

Commit d024426

Browse files
authored
[FIX] align F tests specification with BIDS stats model (#1276)
* fix F tests * fix tests * update changelog
1 parent b30dcad commit d024426

File tree

14 files changed

+200
-131
lines changed

14 files changed

+200
-131
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
4141

4242
### Changed
4343

44+
* [ENH] align specification of F contrasts on the BIDS stats model: they should now be specified as a 2D matrix and not a 1D vector. #1276 @Remi-Gau
4445
* [DOC] change theme and structure of the documentation #1256 @Remi-Gau
4546
* [REF] Refactor and update CLI in #1096 @Remi-Gau
4647
* [ENH] {func}`getData` only loads anat data when requested #1257 @Remi-Gau
@@ -55,7 +56,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
5556

5657
* [FIX] update {func}`createDefaultStatsModel` to use proper `GroupBy` at the dataset level #1248 by @d-ni374
5758
* [FIX] make {func}`getAcquisitionTime` less brittle #1248 by @d-ni374
58-
* [FIX] fix regular expression in {func}`bidsResults` to identify contrasts #1248 by @d-ni374
59+
* [FIX] fix regular expression in {func}`bidsResults` to identify contrasts #1248 by @d-ni374 and #1275 by @Remi-Gau
5960
* [FIX] pass analysis level to stats actions when using python CLI #1258 @Remi-Gau
6061
* [FIX] remove goodness of fit from dataset level analysis as it is not supported by the MACS toolbox #1265 by @Remi-Gau
6162
* [FIX] add java and zip to container recipes to allow using nidm results with octave #1265 by @Remi-Gau

demos/face_repetition/models/model-faceRepetition_smdl.json

Lines changed: 48 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -161,12 +161,54 @@
161161
"rot_z"
162162
],
163163
"Weights": [
164-
1,
165-
1,
166-
1,
167-
1,
168-
1,
169-
1
164+
[
165+
1,
166+
0,
167+
0,
168+
0,
169+
0,
170+
0
171+
],
172+
[
173+
0,
174+
1,
175+
0,
176+
0,
177+
0,
178+
0
179+
],
180+
[
181+
0,
182+
0,
183+
1,
184+
0,
185+
0,
186+
0
187+
],
188+
[
189+
0,
190+
0,
191+
0,
192+
1,
193+
0,
194+
0
195+
],
196+
[
197+
0,
198+
0,
199+
0,
200+
0,
201+
1,
202+
0
203+
],
204+
[
205+
0,
206+
0,
207+
0,
208+
0,
209+
0,
210+
1
211+
]
170212
],
171213
"Test": "F"
172214
}

lib/bids-matlab

src/bids_model/checkContrast.m

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,19 @@
1-
function contrast = checkContrast(node, iCon)
1+
function contrast = checkContrast(model, node, iCon)
22
%
33
% Validates contrast specification
44
%
5-
% put some of that in bids.Model
65
%
76
% USAGE::
87
%
9-
% contrast = checkContrast(node, iCon)
8+
% contrast = checkContrast(model, node, iCon)
109
%
1110
%
1211

12+
% TODO put some of that in bids.Model
13+
1314
% (C) Copyright 2022 bidspm developers
1415

15-
BidsModel.validate_constrasts(node);
16+
model.validate_constrasts(node);
1617

1718
if ~ismember(lower(node.Level), {'run', 'session', 'subject'}) && ...
1819
~isTtest(node.Contrasts(iCon))

src/bids_model/getContrastsFromParentNode.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
if isfield(sourceNode, 'Contrasts') && ~isempty(sourceNode.Contrasts)
2323
for i = 1:numel(sourceNode.Contrasts)
2424
if isTtest(sourceNode.Contrasts{i}) % only contrast can be forwarded
25-
contrastsList{end + 1} = checkContrast(sourceNode, i);
25+
contrastsList{end + 1} = checkContrast(model, sourceNode, i);
2626
end
2727
end
2828

src/bids_model/getContrastsList.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
if isfield(node, 'Contrasts')
3232

3333
for i = 1:numel(node.Contrasts)
34-
contrastsList{end + 1} = checkContrast(node, i); %#ok<*AGROW>
34+
contrastsList{end + 1} = checkContrast(model, node, i); %#ok<*AGROW>
3535
end
3636

3737
% check previous Nodes recursively

src/stats/subject_level/specifyContrasts.m

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -180,13 +180,13 @@
180180

181181
for iCon = 1:length(node.Contrasts)
182182

183-
this_contrast = checkContrast(node, iCon);
183+
thisContrast = checkContrast(model, node, iCon);
184184

185-
if isempty(this_contrast) || strcmp(this_contrast.Test, 'pass')
185+
if isempty(thisContrast) || strcmp(thisContrast.Test, 'pass')
186186
continue
187187
end
188188

189-
conditionList = this_contrast.ConditionList;
189+
conditionList = thisContrast.ConditionList;
190190

191191
for iCdt = 1:length(conditionList)
192192
cdtName = conditionList{iCdt};
@@ -201,7 +201,7 @@
201201

202202
if length(nbRuns) > 1
203203
msg = sprintf('Skipping contrast %s: runs are missing condition %s', ...
204-
this_contrast.Name, cdtName);
204+
thisContrast.Name, cdtName);
205205
id = 'runMissingCondition';
206206
logger('WARNING', msg, 'id', id, 'filename', mfilename());
207207

@@ -213,22 +213,24 @@
213213
% Use the SPM Sess index for the contrast name
214214
iSess = getSessionForRegressorNb(regIdx{1}(iRun), model.SPM);
215215

216-
contrastName = constructContrastNameFromBidsEntity(this_contrast.Name, model.SPM, iSess);
217-
C = newContrast(model.SPM, contrastName, this_contrast.Test, conditionList);
216+
contrastName = constructContrastNameFromBidsEntity(thisContrast.Name, model.SPM, iSess);
217+
C = newContrast(model.SPM, contrastName, thisContrast.Test, conditionList);
218218

219219
for iCdt = 1:length(conditionList)
220220

221-
if strcmp(this_contrast.Test, 't')
222-
C.C(end, regIdx{iCdt}(iRun)) = this_contrast.Weights(iCdt);
221+
if strcmp(thisContrast.Test, 't')
222+
C.C(end, regIdx{iCdt}(iRun)) = thisContrast.Weights(iCdt);
223223

224-
elseif strcmp(this_contrast.Test, 'F')
225-
C.C(iCdt, regIdx{iCdt}(iRun)) = this_contrast.Weights(iCdt);
224+
elseif strcmp(thisContrast.Test, 'F')
225+
for i = 1:size(thisContrast.Weights, 1)
226+
C.C(i, regIdx{iCdt}(iRun)) = thisContrast.Weights(i, iCdt);
227+
end
226228

227229
end
228230

229231
end
230232

231-
[contrasts, counter] = appendContrast(contrasts, C, counter, this_contrast.Test);
233+
[contrasts, counter] = appendContrast(contrasts, C, counter, thisContrast.Test);
232234

233235
end
234236

src/stats/subject_level/specifySessionLvlContrasts.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
% amongst themselves or inferior to baseline
3333
for iCon = 1:length(node.Contrasts)
3434

35-
this_contrast = checkContrast(node, iCon);
35+
this_contrast = checkContrast(model, node, iCon);
3636

3737
if isempty(this_contrast) || strcmp(this_contrast.Test, 'pass')
3838
continue

src/stats/subject_level/specifySubLvlContrasts.m

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
% amongst themselves or inferior to baseline
3737
for iCon = 1:length(node.Contrasts)
3838

39-
thisContrast = checkContrast(node, iCon);
39+
thisContrast = checkContrast(model, node, iCon);
4040

4141
if isempty(thisContrast) || strcmp(thisContrast.Test, 'pass')
4242
continue
@@ -123,9 +123,12 @@
123123
C.C(end, regIdx) = thisContrast.Weights(iCdt);
124124

125125
elseif strcmp(thisContrast.Test, 'F')
126+
126127
for i = 1:numel(regIdx)
127-
C.C(row, regIdx(i)) = thisContrast.Weights(iCdt);
128-
row = row + 1;
128+
for i_w = 1:size(thisContrast.Weights, 1)
129+
C.C(row, regIdx(i)) = thisContrast.Weights(i_w, iCdt);
130+
row = row + 1;
131+
end
129132
end
130133

131134
end
@@ -134,6 +137,9 @@
134137

135138
end
136139

140+
rows_to_rm = all(C.C == 0, 2);
141+
C.C(rows_to_rm, :) = [];
142+
137143
% do not create this contrast if a condition is missing
138144
if exist('status', 'var')
139145
if ~status

tests/data/models/model-vismotionFtest_smdl.json

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,14 @@
7070
"VisStat"
7171
],
7272
"Weights": [
73-
1,
74-
1
73+
[
74+
1,
75+
0
76+
],
77+
[
78+
0,
79+
1
80+
]
7581
],
7682
"Test": "F"
7783
}

0 commit comments

Comments
 (0)