Skip to content

Commit

Permalink
deal with results
Browse files Browse the repository at this point in the history
  • Loading branch information
Remi-Gau committed Jul 28, 2024
1 parent 8efb9ad commit 2d23f73
Show file tree
Hide file tree
Showing 8 changed files with 161 additions and 43 deletions.
2 changes: 1 addition & 1 deletion demos/openneuro/ds003397_run.m
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@

bidspm(bids_dir, output_dir, 'dataset', ...
'participant_label', participant_label, ...
'action', 'stats', ...
'action', 'results', ...
'preproc_dir', preproc_dir, ...
'model_file', model_file, ...
'roi_atlas', 'hcpex', ...
Expand Down
2 changes: 1 addition & 1 deletion demos/openneuro/models/model-ds003397_smdl.json
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@
"B > I",
"average across groups"
],
"p": 0.05,
"p": 0.001,
"MC": "none",
"png": true,
"binary": false,
Expand Down
2 changes: 1 addition & 1 deletion src/batches/stats/setBatchFactorialDesign.m
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@

label = '1WayANOVA';

rfxDir = getRFXdir(opt, nodeName, contrasts{1}, '1WayANOVA');
rfxDir = getRFXdir(opt, nodeName, contrasts{1}, label);
overwriteDir(rfxDir, opt);

assert(exist(fullfile(rfxDir, 'SPM.mat'), 'file') == 0);
Expand Down
2 changes: 2 additions & 0 deletions src/stats/utils/getContrastNb.m
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@
id = 'noMatchingContrastName';
logger('WARNING', msg, 'id', id, 'filename', mfilename());

contrastNb = [];

return

end
Expand Down
22 changes: 21 additions & 1 deletion src/workflows/stats/bidsResults.m
Original file line number Diff line number Diff line change
Expand Up @@ -479,7 +479,6 @@
elseif all(ismember(lower(groupBy), {'contrast', 'group'}))

% TODO make more general than just with group

groupColumnHdr = groupBy{ismember(lower(groupBy), {'group'})};
availableGroups = unique(participants.(groupColumnHdr));

Expand Down Expand Up @@ -508,6 +507,27 @@
matlabbatch = appendToBatch(matlabbatch, opt, result);
end

case 'one_way_anova'

contrastsList = getContrastsListForFactorialDesign(opt, result.nodeName);

for iCon = 1:numel(contrastsList)

label = '1WayANOVA';
result.dir = getRFXdir(opt, result.nodeName, contrastsList{iCon}, label);

load(fullfile(result.dir, 'SPM.mat'), 'SPM');

result.name = name;
contrastNb = getContrastNb(result, opt, SPM);
result.contrastNb = contrastNb;

result.name = [bids.internal.camel_case(contrastsList{iCon}) ' - ' name];

matlabbatch = appendToBatch(matlabbatch, opt, result);

end

otherwise
msg = sprintf('Node %s has has model type I cannot handle.\n', result.nodeName);
notImplemented(mfilename(), msg);
Expand Down
26 changes: 23 additions & 3 deletions tests/data/models/model-vismotionOneWayANOVA_smdl.json
Original file line number Diff line number Diff line change
Expand Up @@ -107,11 +107,31 @@
"X": [
1,
"diagnostic"
]
],
"Software": {
"bidspm": {
"Results": [
{
"name": [
"relative_gt_ctrl",
"blind_gt_relative"
],
"p": 0.05,
"MC": "none",
"png": true,
"binary": false,
"nidm": false,
"montage": {
"do": false
}
}
]
}
}
},
"Contrasts": [
{
"Name": "VisMot_gt_VisStat",
"Name": "relative_gt_ctrl",
"Description": "3 groups but not sorted alphabetically whereas the groups are entered alphabetically in the design matrix.",
"ConditionList": [
"diagnostic.relative",
Expand All @@ -126,7 +146,7 @@
"Test": "t"
},
{
"Name": "VisMot_gt_VisStat",
"Name": "blind_gt_relative",
"Description": "Only 2 groups should be OK but needs to be handled properly: should give a vector [-1, 0, 1]",
"ConditionList": [
"diagnostic.blind",
Expand Down
44 changes: 8 additions & 36 deletions tests/tests_slow/tests_workflows/stats/test_bidsRFX_3_groups.m
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
% (C) Copyright 2021 bidspm developers
% (C) Copyright 2024 bidspm developers

function test_suite = test_bidsRFX_3_groups %#ok<*STOUT>
try % assignment of 'localfunctions' is necessary in Matlab >= 2016
Expand All @@ -10,52 +10,24 @@

function test_bidsRFX_one_way_anova()

% markTestAs('slow');
%
% opt = setOptions('3_groups', '', 'pipelineType', 'stats');
%
% opt.model.bm = BidsModel('file', opt.model.file);
% opt.verbosity = 3;
%
% matlabbatch = bidsRFX('RFX', opt, 'nodeName', 'between_groups');
%
% assertEqual(matlabbatch{1}.spm.stats.factorial_design.dir{1}, ...
% fileparts(matlabbatch{2}.spm.stats.fmri_est.spmmat{1}));
% assertEqual(matlabbatch{1}.spm.stats.factorial_design.dir{1}, ...
% matlabbatch{3}.spm.tools.MACS.MA_model_space.dir{1});
%
% assertEqual(batchSummary(matlabbatch), expectedBatchOrder());

end

function test_bidsRFX_one_way_anova_contrast()

markTestAs('slow');

opt = setOptions('3_groups', '', 'pipelineType', 'stats');

opt.model.bm = BidsModel('file', opt.model.file);
opt.verbosity = 3;
opt.verbosity = 0;

nodeName = 'between_groups';

matlabbatch = bidsRFX('contrasts', opt, 'nodeName', nodeName);
matlabbatch = bidsRFX('RFX', opt, 'nodeName', 'between_groups');

nodeName = 'between_groups';
contrastName = 'VisMot_gt_VisStat';
rfxDir = getRFXdir(opt, nodeName, contrastName, '1WayANOVA');
assertEqual(fileparts(matlabbatch{1}.spm.stats.con.spmmat{1}), rfxDir);

assertEqual(numel(matlabbatch{1}.spm.stats.con.consess), 2);
assertEqual(matlabbatch{1}.spm.stats.con.consess{1}.tcon.convec, [0; -1; 1]);
assertEqual(matlabbatch{1}.spm.stats.con.consess{2}.tcon.convec, [-1; 0; 1]);

contrastName = 'VisStat_gt_VisMot';
rfxDir = getRFXdir(opt, nodeName, contrastName, '1WayANOVA');
assertEqual(fileparts(matlabbatch{2}.spm.stats.con.spmmat{1}), rfxDir);
assertEqual(matlabbatch{1}.spm.stats.factorial_design.dir{1}, rfxDir);
assertEqual(matlabbatch{3}.spm.tools.MACS.MA_model_space.dir{1}, rfxDir);
assertEqual(fileparts(matlabbatch{2}.spm.stats.fmri_est.spmmat{1}), rfxDir);

assertEqual(numel(matlabbatch{2}.spm.stats.con.consess), 2);
assertEqual(matlabbatch{2}.spm.stats.con.consess{1}.tcon.convec, [0; -1; 1]);
assertEqual(matlabbatch{2}.spm.stats.con.consess{2}.tcon.convec, [-1; 0; 1]);
assertEqual(batchSummary(matlabbatch), expectedBatchOrder());

end

Expand Down
104 changes: 104 additions & 0 deletions tests/tests_workflows/stats/test_bidsRFX_3_groups.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
% (C) Copyright 2024 bidspm developers

function test_suite = test_bidsRFX_3_groups %#ok<*STOUT>
try % assignment of 'localfunctions' is necessary in Matlab >= 2016
test_functions = localfunctions(); %#ok<*NASGU>
catch % no problem; early Matlab versions can use initTestSuite fine
end
initTestSuite;
end

function test_bidsRFX_one_way_anova_contrast()

opt = setOptions('3_groups', '', 'pipelineType', 'stats');

opt.model.bm = BidsModel('file', opt.model.file);
opt.verbosity = 0;

nodeName = 'between_groups';

matlabbatch = bidsRFX('contrasts', opt, 'nodeName', nodeName);

contrastName = 'VisMot_gt_VisStat';
rfxDir = getRFXdir(opt, nodeName, contrastName, '1WayANOVA');
assertEqual(fileparts(matlabbatch{1}.spm.stats.con.spmmat{1}), rfxDir);

assertEqual(numel(matlabbatch{1}.spm.stats.con.consess), 2);
assertEqual(matlabbatch{1}.spm.stats.con.consess{1}.tcon.name, 'relative_gt_ctrl');
assertEqual(matlabbatch{1}.spm.stats.con.consess{1}.tcon.convec, [0; -1; 1]);
assertEqual(matlabbatch{1}.spm.stats.con.consess{2}.tcon.name, 'blind_gt_relative');
assertEqual(matlabbatch{1}.spm.stats.con.consess{2}.tcon.convec, [-1; 0; 1]);

contrastName = 'VisStat_gt_VisMot';
rfxDir = getRFXdir(opt, nodeName, contrastName, '1WayANOVA');
assertEqual(fileparts(matlabbatch{2}.spm.stats.con.spmmat{1}), rfxDir);

assertEqual(numel(matlabbatch{2}.spm.stats.con.consess), 2);
assertEqual(matlabbatch{1}.spm.stats.con.consess{1}.tcon.name, 'relative_gt_ctrl');
assertEqual(matlabbatch{2}.spm.stats.con.consess{1}.tcon.convec, [0; -1; 1]);
assertEqual(matlabbatch{1}.spm.stats.con.consess{2}.tcon.name, 'blind_gt_relative');
assertEqual(matlabbatch{2}.spm.stats.con.consess{2}.tcon.convec, [-1; 0; 1]);

end

function test_bidsRFX_one_way_anova_results()

opt = setOptions('3_groups', '', 'pipelineType', 'stats');

opt.model.bm = BidsModel('file', opt.model.file);
opt.verbosity = 3;

nodeName = 'between_groups';

contrastName = 'VisMot_gt_VisStat';
rfxDir = getRFXdir(opt, nodeName, contrastName, '1WayANOVA');
spm_mkdir(rfxDir);
xCon(1) = struct('name', 'relative_gt_ctrl');
xCon(2) = struct('name', 'blind_gt_relative');
SPM = struct('nscan', 10, 'xCon', xCon);
save(fullfile(rfxDir, 'SPM.mat'), 'SPM');

contrastName = 'VisStat_gt_VisMot';
rfxDir = getRFXdir(opt, nodeName, contrastName, '1WayANOVA');
spm_mkdir(rfxDir);
% here we switch the order of the contrast in the SPM.mat
% to make sure the batch setting picks up the correct ones.
xCon(2) = struct('name', 'relative_gt_ctrl');
xCon(1) = struct('name', 'blind_gt_relative');
SPM = struct('nscan', 10, 'xCon', xCon);
save(fullfile(rfxDir, 'SPM.mat'), 'SPM');

matlabbatch = bidsResults(opt, 'nodeName', nodeName);

assertEqual(length(matlabbatch), 4);
assertEqual(matlabbatch{1}.result.name, 'VisMotGtVisStat - relative_gt_ctrl');
assertEqual(matlabbatch{1}.spm.stats.results.conspec.contrasts, 1);
assertEqual(matlabbatch{2}.result.name, 'VisStatGtVisMot - relative_gt_ctrl');
assertEqual(matlabbatch{2}.spm.stats.results.conspec.contrasts, 2);
assertEqual(matlabbatch{3}.result.name, 'VisMotGtVisStat - blind_gt_relative');
assertEqual(matlabbatch{3}.spm.stats.results.conspec.contrasts, 2);
assertEqual(matlabbatch{4}.result.name, 'VisStatGtVisMot - blind_gt_relative');
assertEqual(matlabbatch{4}.spm.stats.results.conspec.contrasts, 1);

end

function value = batchSummary(matlabbatch)
value = {};
for i = 1:numel(matlabbatch)
field = fieldnames(matlabbatch{i}.spm);
value{i, 1} = field{1}; %#ok<*AGROW>
field = fieldnames(matlabbatch{i}.spm.(value{i, 1}));
value{i, 2} = field{1};
end
end

function value = expectedBatchOrder()

value = {'stats', 'factorial_design'; ...
'stats', 'fmri_est'; ...
'tools', 'MACS'; ...
'tools', 'MACS'; ...
'stats', 'review'; ...
'util', 'print'};

end

0 comments on commit 2d23f73

Please sign in to comment.