Skip to content

Commit 2589123

Browse files
authored
2T6S pipeline reproduction (#75)
* Dummy change to test 2T6S pipeline on CI with rectified results data * [REFAC] 2T6S pipeline * [BUG] cleaning connections * [BUG] cleaning connections * [TEST] init a test for conftest.py * [BUG] inside unit_tests workflow * [TEST] testing the conftest module * Issue with parameters dir creation * Bug with makedirs import * Workaround to change hypotheses 5&8 files * Change correlation threshold values
1 parent 29b7c3d commit 2589123

File tree

2 files changed

+77
-59
lines changed

2 files changed

+77
-59
lines changed

narps_open/pipelines/team_2T6S.py

Lines changed: 76 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#!/usr/bin/python
22
# coding: utf-8
33

4-
""" Write the work of NARPS' team 2T6S using Nipype """
4+
""" Write the work of NARPS team 2T6S using Nipype """
55

66
from os.path import join
77
from itertools import product
@@ -78,8 +78,10 @@ def get_subject_infos(event_files, runs):
7878
duration[val].append(float(info[4])) # durations for trial (rpz by RT)
7979
else: # trial with no response : duration of 4 s
8080
duration[val].append(float(4))
81-
weights_gain[val_gain].append(float(info[2])) # weights gain for trial_run1
82-
weights_loss[val_loss].append(-1.0 * float(info[3])) # weights loss for trial_run1
81+
# weights gain for trial_run1
82+
weights_gain[val_gain].append(float(info[2]))
83+
# weights loss for trial_run1
84+
weights_loss[val_loss].append(-1.0 * float(info[3]))
8385

8486
# Bunching is done per run, i.e. trial_run1, trial_run2, etc.
8587
# But names must not have '_run1' etc because we concatenate runs
@@ -141,11 +143,11 @@ def get_parameters_file(filepaths, subject_id, working_dir):
141143
Return :
142144
- parameters_file : paths to new files containing only desired parameters.
143145
"""
144-
from os import mkdir
146+
from os import makedirs
145147
from os.path import join, isdir
146148

147-
import pandas as pd
148-
import numpy as np
149+
from pandas import read_csv, DataFrame
150+
from numpy import array, transpose
149151

150152
# Handle the case where filepaths is a single path (str)
151153
if not isinstance(filepaths, list):
@@ -154,21 +156,20 @@ def get_parameters_file(filepaths, subject_id, working_dir):
154156
# Create the parameters files
155157
parameters_file = []
156158
for file_id, file in enumerate(filepaths):
157-
data_frame = pd.read_csv(file, sep = '\t', header=0)
159+
data_frame = read_csv(file, sep = '\t', header=0)
158160

159161
# Extract parameters we want to use for the model
160-
temp_list = np.array([
162+
temp_list = array([
161163
data_frame['X'], data_frame['Y'], data_frame['Z'],
162164
data_frame['RotX'], data_frame['RotY'], data_frame['RotZ']])
163-
retained_parameters = pd.DataFrame(np.transpose(temp_list))
165+
retained_parameters = DataFrame(transpose(temp_list))
164166

165167
# Write parameters to a parameters file
166168
# TODO : warning !!! filepaths must be ordered (1,2,3,4) for the following code to work
167-
new_path =join(working_dir, 'parameters_file',
169+
new_path = join(working_dir, 'parameters_file',
168170
f'parameters_file_sub-{subject_id}_run-{str(file_id + 1).zfill(2)}.tsv')
169171

170-
if not isdir(join(working_dir, 'parameters_file')):
171-
mkdir(join(working_dir, 'parameters_file'))
172+
makedirs(join(working_dir, 'parameters_file'), exist_ok = True)
172173

173174
with open(new_path, 'w') as writer:
174175
writer.write(retained_parameters.to_csv(
@@ -187,11 +188,11 @@ def remove_gunzip_files(_, subject_id, working_dir):
187188
188189
Parameters:
189190
- _: Node input only used for triggering the Node
190-
- subject_id: str, TODO
191-
- working_id: str, TODO
191+
- subject_id: str, subject id from which to remove the unzipped file
192+
- working_dir: str, path to the working directory
192193
"""
193-
from shutil import rmtree
194194
from os.path import join
195+
from shutil import rmtree
195196

196197
try:
197198
rmtree(join(working_dir, 'l1_analysis', f'_subject_id_{subject_id}', 'gunzip_func'))
@@ -209,11 +210,11 @@ def remove_smoothed_files(_, subject_id, working_dir):
209210
210211
Parameters:
211212
- _: Node input only used for triggering the Node
212-
- subject_id: str, TODO
213-
- working_id: str, TODO
213+
- subject_id: str, subject id from which to remove the smoothed file
214+
- working_dir: str, path to the working directory
214215
"""
215-
from shutil import rmtree
216216
from os.path import join
217+
from shutil import rmtree
217218

218219
try:
219220
rmtree(join(working_dir, 'l1_analysis', f'_subject_id_{subject_id}', 'smooth'))
@@ -231,11 +232,7 @@ def get_subject_level_analysis(self):
231232
"""
232233
# Infosource Node - To iterate on subjects
233234
infosource = Node(IdentityInterface(
234-
fields = ['subject_id', 'dataset_dir', 'results_dir', 'working_dir', 'run_list'],
235-
dataset_dir = self.directories.dataset_dir,
236-
results_dir = self.directories.results_dir,
237-
working_dir = self.directories.working_dir,
238-
run_list = self.run_list),
235+
fields = ['subject_id']),
239236
name = 'infosource')
240237
infosource.iterables = [('subject_id', self.subject_list)]
241238

@@ -275,6 +272,7 @@ def get_subject_level_analysis(self):
275272
input_names = ['event_files', 'runs'],
276273
output_names = ['subject_info']),
277274
name = 'subject_infos')
275+
subject_infos.inputs.runs = self.run_list
278276

279277
# SpecifyModel - generates SPM-specific Model
280278
specify_model = Node(SpecifySPMModel(
@@ -332,16 +330,13 @@ def get_subject_level_analysis(self):
332330
l1_analysis = Workflow(base_dir = self.directories.working_dir, name = 'l1_analysis')
333331
l1_analysis.connect([
334332
(infosource, selectfiles, [('subject_id', 'subject_id')]),
335-
(infosource, subject_infos, [('run_list', 'runs')]),
336333
(infosource, remove_gunzip_files, [('subject_id', 'subject_id')]),
337334
(infosource, remove_smoothed_files, [('subject_id', 'subject_id')]),
335+
(infosource, parameters, [('subject_id', 'subject_id')]),
338336
(subject_infos, specify_model, [('subject_info', 'subject_info')]),
339337
(contrasts, contrast_estimate, [('contrasts', 'contrasts')]),
340338
(selectfiles, parameters, [('param', 'filepaths')]),
341339
(selectfiles, subject_infos, [('event', 'event_files')]),
342-
(infosource, parameters, [
343-
('subject_id', 'subject_id'),
344-
('working_dir', 'working_dir')]),
345340
(selectfiles, gunzip_func, [('func', 'in_file')]),
346341
(gunzip_func, smooth, [('out_file', 'in_files')]),
347342
(smooth, specify_model, [('smoothed_files', 'functional_runs')]),
@@ -401,8 +396,10 @@ def get_subset_contrasts(file_list, subject_list, participants_file):
401396
Returns :
402397
- equal_indifference_id : a list of subject ids in the equalIndifference group
403398
- equal_range_id : a list of subject ids in the equalRange group
404-
- equal_indifference_files : a subset of file_list corresponding to subjects in the equalIndifference group
405-
- equal_range_files : a subset of file_list corresponding to subjects in the equalRange group
399+
- equal_indifference_files : a subset of file_list corresponding to
400+
subjects in the equalIndifference group
401+
- equal_range_files : a subset of file_list corresponding to
402+
subjects in the equalRange group
406403
"""
407404
equal_indifference_id = []
408405
equal_range_id = []
@@ -454,8 +451,7 @@ def get_group_level_analysis_sub_workflow(self, method):
454451
# Infosource - iterate over the list of contrasts
455452
infosource_groupanalysis = Node(
456453
IdentityInterface(
457-
fields = ['contrast_id', 'subjects'],
458-
subjects = self.subject_list),
454+
fields = ['contrast_id', 'subjects']),
459455
name = 'infosource_groupanalysis')
460456
infosource_groupanalysis.iterables = [('contrast_id', self.contrast_list)]
461457

@@ -469,7 +465,7 @@ def get_group_level_analysis_sub_workflow(self, method):
469465
}
470466

471467
selectfiles_groupanalysis = Node(SelectFiles(
472-
templates, base_directory=self.directories.results_dir, force_list= True),
468+
templates, base_directory = self.directories.results_dir, force_list = True),
473469
name = 'selectfiles_groupanalysis')
474470

475471
# Datasink - save important files
@@ -481,14 +477,14 @@ def get_group_level_analysis_sub_workflow(self, method):
481477
# Function node get_subset_contrasts - select subset of contrasts
482478
sub_contrasts = Node(Function(
483479
function = self.get_subset_contrasts,
484-
input_names = ['file_list', 'method', 'subject_list', 'participants_file'],
480+
input_names = ['file_list', 'subject_list', 'participants_file'],
485481
output_names = [
486482
'equalIndifference_id',
487483
'equalRange_id',
488484
'equalIndifference_files',
489485
'equalRange_files']),
490486
name = 'sub_contrasts')
491-
sub_contrasts.inputs.method = method
487+
sub_contrasts.inputs.subject_list = self.subject_list
492488

493489
# Estimate model
494490
estimate_model = Node(EstimateModel(
@@ -513,8 +509,6 @@ def get_group_level_analysis_sub_workflow(self, method):
513509
l2_analysis.connect([
514510
(infosource_groupanalysis, selectfiles_groupanalysis, [
515511
('contrast_id', 'contrast_id')]),
516-
(infosource_groupanalysis, sub_contrasts, [
517-
('subjects', 'subject_list')]),
518512
(selectfiles_groupanalysis, sub_contrasts, [
519513
('contrast', 'file_list'),
520514
('participants', 'participants_file')]),
@@ -618,29 +612,53 @@ def get_group_level_outputs(self):
618612
return return_list
619613

620614
def get_hypotheses_outputs(self):
621-
""" Return all hypotheses output file names.
622-
Note that hypotheses 5 to 8 correspond to the maps given by the team in their results ;
623-
but they are not fully consistent with the hypotheses definitions as expected by NARPS.
624-
"""
615+
""" Return all hypotheses output file names. """
625616
nb_sub = len(self.subject_list)
626617
files = [
627-
join(f'l2_analysis_equalIndifference_nsub_{nb_sub}', '_contrast_id_0002', '_threshold0', 'spmT_0001_thr.nii'),
628-
join(f'l2_analysis_equalIndifference_nsub_{nb_sub}', '_contrast_id_0002', 'spmT_0001.nii'),
629-
join(f'l2_analysis_equalRange_nsub_{nb_sub}', '_contrast_id_0002', '_threshold0', 'spmT_0001_thr.nii'),
630-
join(f'l2_analysis_equalRange_nsub_{nb_sub}', '_contrast_id_0002', 'spmT_0001.nii'),
631-
join(f'l2_analysis_equalIndifference_nsub_{nb_sub}', '_contrast_id_0002', '_threshold0', 'spmT_0001_thr.nii'),
632-
join(f'l2_analysis_equalIndifference_nsub_{nb_sub}', '_contrast_id_0002', 'spmT_0001.nii'),
633-
join(f'l2_analysis_equalRange_nsub_{nb_sub}', '_contrast_id_0002', '_threshold0', 'spmT_0001_thr.nii'),
634-
join(f'l2_analysis_equalRange_nsub_{nb_sub}', '_contrast_id_0002', 'spmT_0001.nii'),
635-
join(f'l2_analysis_equalIndifference_nsub_{nb_sub}', '_contrast_id_0003', '_threshold1', 'spmT_0002_thr.nii'),
636-
join(f'l2_analysis_equalIndifference_nsub_{nb_sub}', '_contrast_id_0003', 'spmT_0002.nii'),
637-
join(f'l2_analysis_equalRange_nsub_{nb_sub}', '_contrast_id_0003', '_threshold1', 'spmT_0001_thr.nii'),
638-
join(f'l2_analysis_equalRange_nsub_{nb_sub}', '_contrast_id_0003', 'spmT_0001.nii'),
639-
join(f'l2_analysis_equalIndifference_nsub_{nb_sub}', '_contrast_id_0003', '_threshold0', 'spmT_0001_thr.nii'),
640-
join(f'l2_analysis_equalIndifference_nsub_{nb_sub}', '_contrast_id_0003', 'spmT_0001.nii'),
641-
join(f'l2_analysis_equalRange_nsub_{nb_sub}', '_contrast_id_0003', '_threshold0', 'spmT_0002_thr.nii'),
642-
join(f'l2_analysis_equalRange_nsub_{nb_sub}', '_contrast_id_0003', 'spmT_0002.nii'),
643-
join(f'l2_analysis_groupComp_nsub_{nb_sub}', '_contrast_id_0003', '_threshold0', 'spmT_0001_thr.nii'),
644-
join(f'l2_analysis_groupComp_nsub_{nb_sub}', '_contrast_id_0003', 'spmT_0001.nii')
618+
# Hypothesis 1
619+
join(f'l2_analysis_equalIndifference_nsub_{nb_sub}',
620+
'_contrast_id_0002', '_threshold0', 'spmT_0001_thr.nii'),
621+
join(f'l2_analysis_equalIndifference_nsub_{nb_sub}',
622+
'_contrast_id_0002', 'spmT_0001.nii'),
623+
# Hypothesis 2
624+
join(f'l2_analysis_equalRange_nsub_{nb_sub}',
625+
'_contrast_id_0002', '_threshold0', 'spmT_0001_thr.nii'),
626+
join(f'l2_analysis_equalRange_nsub_{nb_sub}',
627+
'_contrast_id_0002', 'spmT_0001.nii'),
628+
# Hypothesis 3
629+
join(f'l2_analysis_equalIndifference_nsub_{nb_sub}',
630+
'_contrast_id_0002', '_threshold0', 'spmT_0001_thr.nii'),
631+
join(f'l2_analysis_equalIndifference_nsub_{nb_sub}',
632+
'_contrast_id_0002', 'spmT_0001.nii'),
633+
# Hypothesis 4
634+
join(f'l2_analysis_equalRange_nsub_{nb_sub}',
635+
'_contrast_id_0002', '_threshold0', 'spmT_0001_thr.nii'),
636+
join(f'l2_analysis_equalRange_nsub_{nb_sub}',
637+
'_contrast_id_0002', 'spmT_0001.nii'),
638+
# Hypothesis 5
639+
join(f'l2_analysis_equalIndifference_nsub_{nb_sub}',
640+
'_contrast_id_0003', '_threshold0', 'spmT_0001_thr.nii'),
641+
join(f'l2_analysis_equalIndifference_nsub_{nb_sub}',
642+
'_contrast_id_0003', 'spmT_0001.nii'),
643+
# Hypothesis 6
644+
join(f'l2_analysis_equalRange_nsub_{nb_sub}',
645+
'_contrast_id_0003', '_threshold1', 'spmT_0002_thr.nii'),
646+
join(f'l2_analysis_equalRange_nsub_{nb_sub}',
647+
'_contrast_id_0003', 'spmT_0002.nii'),
648+
# Hypothesis 7
649+
join(f'l2_analysis_equalIndifference_nsub_{nb_sub}',
650+
'_contrast_id_0003', '_threshold0', 'spmT_0001_thr.nii'),
651+
join(f'l2_analysis_equalIndifference_nsub_{nb_sub}',
652+
'_contrast_id_0003', 'spmT_0001.nii'),
653+
# Hypothesis 8
654+
join(f'l2_analysis_equalRange_nsub_{nb_sub}',
655+
'_contrast_id_0003', '_threshold1', 'spmT_0002_thr.nii'),
656+
join(f'l2_analysis_equalRange_nsub_{nb_sub}',
657+
'_contrast_id_0003', 'spmT_0002.nii'),
658+
# Hypothesis 9
659+
join(f'l2_analysis_groupComp_nsub_{nb_sub}',
660+
'_contrast_id_0003', '_threshold0', 'spmT_0001_thr.nii'),
661+
join(f'l2_analysis_groupComp_nsub_{nb_sub}',
662+
'_contrast_id_0003', 'spmT_0001.nii')
645663
]
646664
return [join(self.directories.output_dir, f) for f in files]

narps_open/utils/configuration/testing_config.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,4 @@ neurovault_naming = true # true if results files are saved using the neurovault
1919
[testing]
2020

2121
[testing.pipelines]
22-
correlation_thresholds = [0.30, 0.70, 0.80, 0.85, 0.93] # Correlation between reproduced hypotheses files and results, respectively for [20, 40, 60, 80, 108] subjects.
22+
correlation_thresholds = [0.30, 0.70, 0.79, 0.85, 0.93] # Correlation between reproduced hypotheses files and results, respectively for [20, 40, 60, 80, 108] subjects.

0 commit comments

Comments
 (0)