Run this notebook
Subject and Group Level Analysis Workflows¶
Author: Monika Doerig
Date: 13 June 2024
License:
Note: If this notebook uses neuroimaging tools from Neurocontainers, those tools retain their original licenses. Please see Neurodesk citation guidelines for details.
Citation and Resources:¶
Tools included in this workflow¶
Nipype:
Esteban, O., Markiewicz, C. J., Burns, C., Goncalves, M., Jarecka, D., Ziegler, E., Berleant, S., Ellis, D. G., Pinsard, B., Madison, C., Waskom, M., Notter, M. P., Clark, D., Manhães-Savio, A., Clark, D., Jordan, K., Dayan, M., Halchenko, Y. O., Loney, F., … Ghosh, S. (2025). nipy/nipype: 1.8.6 (1.8.6). Zenodo. Esteban et al. (2025)
SPM12:
Friston, K. J. (2007). Statistical parametric mapping: The analysis of functional brain images (1st ed). Elsevier / Academic Press.
Dataset¶
Wakeman, DG and Henson, RN (2021). Multisubject, multimodal face processing. OpenNeuro. [Dataset] doi: 10
.18112 /openneuro .ds000117 .v1 .0.5 Wakeman, D.G. & Henson, R.N. (2015). A multi-subject, multi-modal human neuroimaging dataset. Sci. Data 2:150001 doi: 10
.1038 /sdata .2015.1
Educational resources:¶
Introduction¶
The fMRI dataset used for this example is part of a multi-subject, multi-modal (sMRI, fMRI, MEG, EEG) neuroimaging dataset on face processing. It contains data in BIDS format on sixteen healthy volunteers. The data was recoreded while the volunteers performed multiple runs of hundreds of trials of a simple perceptual task on pictures of familiar, unfamiliar and scrambled faces during two visits to the laboratory.
The facial stimuli consisted of two groups of 300 greyscale photos, half of which were of famous people and half of which were of non-famous people (unknown to the participants). Each scrambled face was created either from the famous face or the non-famous face of the same stimulus number. Additionally, each image was presented twice to the participants. The second presentation occurred either immediately after the first presentation (Immediate Repeats) or after 5–15 intervening stimuli (Delayed Repeats), with 50% of each type of repeat. To ensure that each stimulus received equal attention, participants were instructed to use their left or right index finger to press one of two keys (assignment counter-balanced across participants). They determined the symmetry of each image by pressing a key based on whether they perceived it to be ‘more’ or ‘less symmetric’ than average.
In the original paper (Wakeman & Henson, 2015), the repetition manipulation was not distinguished, meaning that initial and repeated presentations were treated identically without considering the timing of the repeats.
To illustrate the setup of a 3x2 factorial design analysis (familiar vs. unfamiliar vs. scrambled faces) x (1st vs. 2nd presentation) in an SPM Nipype workflow, the event files will be adapted accordingly. Each stimulus type will be labeled as either the first or second presentation. However, for simplicity, no distinction is made between immediate and delayed repetitions, resulting in 6 stimulus types (conditions): Familiar-Rep1 (F1), Familiar-Rep2 (F2), Unfamiliar-Rep1 (U1), Unfamiliar-Rep2 (U2), Scrambled-Rep1 (S1), and Scrambled-Rep2 (S2).
Examples of a familiar, unfamiliar and scrambled face:
PATTERN_STIMULI = "stimuli/func/*001.bmp"
!datalad install https://github.com/OpenNeuroDatasets/ds000117.git
!cd ds000117 && git checkout 1.0.5 && datalad get $PATTERN_STIMULICloning: 0%| | 0.00/2.00 [00:00<?, ? candidates/s]
Enumerating: 0.00 Objects [00:00, ? Objects/s]
Counting: 0%| | 0.00/39.9k [00:00<?, ? Objects/s]
Compressing: 0%| | 0.00/22.2k [00:00<?, ? Objects/s]
Receiving: 0%| | 0.00/61.8k [00:00<?, ? Objects/s]
Receiving: 51%|██████████▋ | 31.5k/61.8k [00:00<00:00, 314k Objects/s]
Resolving: 0%| | 0.00/16.5k [00:00<?, ? Deltas/s]
Resolving: 62%|█████████████▋ | 10.2k/16.5k [00:00<00:00, 102k Deltas/s]
[INFO ] Remote origin not usable by git-annex; setting annex-ignore
[INFO ] https://github.com/OpenNeuroDatasets/ds000117.git/config download failed: Not Found
[INFO ] Remote origin not usable by git-annex; setting annex-ignore
[INFO ] https://github.com/OpenNeuroDatasets/ds000117.git/config download failed: Not Found
install(ok): /home/jovyan/workspace/books/examples/functional_imaging/ds000117 (dataset)
Note: switching to '1.0.5'.
You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by switching back to a branch.
If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -c with the switch command. Example:
git switch -c <new-branch-name>
Or undo this operation with:
git switch -
Turn off this advice by setting config variable advice.detachedHead to false
HEAD is now at 12470d39 [OpenNeuro] Recorded changes
Total: 0%| | 0.00/131k [00:00<?, ? Bytes/s]
Total: 7%|██▎ | 8.52k/131k [00:01<?, ? Bytes/s]
Get stimuli/ .. nc/ps001.bmp: 100%|███████████| 21.8k/21.8k [00:00<?, ? Bytes/s]
Total: 17%|████▌ | 21.8k/131k [00:01<00:10, 10.9k Bytes/s]
Get stimuli/ .. nc/pf001.bmp: 39%|████▎ | 8.52k/21.8k [00:00<?, ? Bytes/s]
Get stimuli/ .. nc/pf001.bmp: 100%|███████████| 21.8k/21.8k [00:00<?, ? Bytes/s]
Total: 33%|█████████ | 43.6k/131k [00:01<00:04, 17.9k Bytes/s]
Get stimuli/func/u001.bmp: 39%|█████▍ | 8.52k/21.8k [00:00<?, ? Bytes/s]
Get stimuli/func/u001.bmp: 100%|██████████████| 21.8k/21.8k [00:00<?, ? Bytes/s]
Total: 50%|█████████████▌ | 65.4k/131k [00:01<00:02, 23.2k Bytes/s]
Get stimuli/ .. nc/pu001.bmp: 39%|████▎ | 8.52k/21.8k [00:00<?, ? Bytes/s]
Get stimuli/ .. nc/pu001.bmp: 100%|███████████| 21.8k/21.8k [00:00<?, ? Bytes/s]
Total: 67%|██████████████████ | 87.3k/131k [00:01<00:01, 26.9k Bytes/s]
Get stimuli/func/f001.bmp: 39%|█████▍ | 8.52k/21.8k [00:00<?, ? Bytes/s]
Get stimuli/func/f001.bmp: 100%|██████████████| 21.8k/21.8k [00:00<?, ? Bytes/s]
Total: 83%|███████████████████████▎ | 109k/131k [00:02<00:00, 29.9k Bytes/s]
Get stimuli/func/s001.bmp: 39%|█████▍ | 8.52k/21.8k [00:00<?, ? Bytes/s]
Get stimuli/func/s001.bmp: 100%|██████████████| 21.8k/21.8k [00:00<?, ? Bytes/s]
get(ok): stimuli/func/ps001.bmp (file) [from s3-PUBLIC...]
get(ok): stimuli/func/pf001.bmp (file) [from s3-PUBLIC...]
get(ok): stimuli/func/u001.bmp (file) [from s3-PUBLIC...]
get(ok): stimuli/func/pu001.bmp (file) [from s3-PUBLIC...]
get(ok): stimuli/func/f001.bmp (file) [from s3-PUBLIC...]
get(ok): stimuli/func/s001.bmp (file) [from s3-PUBLIC...]
action summary:
get (ok: 6)
import matplotlib.pyplot as plt
from matplotlib.image import imread
# Load the .bmp images
familiar = imread('ds000117/stimuli/func/f001.bmp')
unfamiliar = imread('ds000117/stimuli/func/u001.bmp')
scrambled = imread('ds000117/stimuli/func/s001.bmp')
# Create a Matplotlib figure with subplots
fig, axes = plt.subplots(1, 3, figsize=(12, 4))
# Plot each image on a subplot
axes[0].imshow(familiar, cmap='gray')
axes[0].set_title('Familiar face')
axes[0].axis('off')
axes[1].imshow(unfamiliar, cmap='gray')
axes[1].set_title('Unfamiliar face')
axes[1].axis('off')
axes[2].imshow(scrambled, cmap='gray')
axes[2].set_title('Scrambled face')
axes[2].axis('off')
plt.tight_layout()
plt.show()
Download Data and install Python modules¶
# Raw dataset: ONLY events.tsv + json sidecar
!cd ds000117 && git checkout 1.0.5 && \
datalad get sub-0[1-5]/ses-mri/func/*_events.tsv task-facerecognition_bold.jsonHEAD is now at 12470d39 [OpenNeuro] Recorded changes
action summary:
get (notneeded: 46)
# get preprocessed normalized func images of 5 individuals and 2 runs
PATTERN_PREP = "sub-0[1-5]/ses-mri/func/*run-[1-2]*space-MNI152NLin6Asym_desc-smoothAROMAnonaggr_bold.nii.gz"
!datalad install https://github.com/OpenNeuroDerivatives/ds000117-fmriprep.git
!cd ds000117-fmriprep && datalad get $PATTERN_PREP%%capture
!pip install nilearn==0.13.1 pandas==2.3.3 scipy==1.16.3Load SPM and import Python and Nipype modules¶
import module
await module.purge(force=True)
await module.load('spm12/r7771')
await module.list()['spm12/r7771']import pandas as pd
import numpy as np
from nilearn import plotting
import matplotlib.pyplot as plt
import json
import os
from os.path import join as opj
from scipy.io import loadmatimport nipype.algorithms.modelgen as model
from nipype.interfaces import spm
from nipype.interfaces.io import DataSink, DataGrabber
from nipype.interfaces.utility import IdentityInterface, Function
from nipype import Node, Workflow, MapNode
from nipype.algorithms.misc import Gunzipimport nipype
NIPYPE_VERSION = nipype.__version__
print(NIPYPE_VERSION)1.11.0
from packaging.version import Version
if Version(NIPYPE_VERSION) <= Version("1.8.6"):
print('Contrasts need to be defined manually and wont be computed automatically when they are defined in Level1Design using the factor_info parameter')
# starting in nipype version 1.8.7., when factor_info parameter is used in Level1design T and F contrasts (ess*, con*, spmF* and spmT* images)
# are created automatically by in EstimateModel by SPMAnalysis¶
1. First Level Analysis¶
Prepare Data Input¶
#base directories
data_base_dir = os.getcwd()
experiment_dir = opj(data_base_dir, 'spm_analysis/') #where to store the working and datasink directories
#list of subject identifiers and runs
sub_list = ['01', '02', '03', '04', '05']
#only take run 1 and 2 for computational reasons
run_id = [1,2]#TR of functional images
with open(opj(data_base_dir,'ds000117/task-facerecognition_bold.json'), 'rt') as fp:
task_info = json.load(fp)
TR = float(task_info['RepetitionTime'])
print('Repetition Time:', TR)Repetition Time: 2.0
Start the workflow¶
wf = Workflow(name='level1_spm', base_dir=experiment_dir)
wf.config["execution"]["crashfile_format"] = "txt"Input stream¶
infosource = Node(IdentityInterface(fields=["subject_id"]),
name="infosource")
infosource.iterables = [("subject_id", sub_list)]SPM12 can accept NIfTI files as input, but only if they are not compressed (‘unzipped’). Use Gunzip node to unzip the files, before feeding them it to the model specification node.¶
gunzip_func = MapNode(Gunzip(), name='gunzip_func', iterfield='in_file')datagrabber = Node(interface=DataGrabber(
infields=["subject_id","run_id"], outfields=["func", "events"]
), name="datagrabber"
)
# Specify task names and return a sorted filelist to ensure to match files to correct runs
datagrabber.inputs.run_id = run_id
datagrabber.inputs.sort_filelist = True
datagrabber.inputs.template = "*"
datagrabber.inputs.base_directory = data_base_dir
# Define arguments fill the wildcards in the below paths
datagrabber.inputs.template_args = dict(
func=[["subject_id","subject_id","run_id"]],
events=[["subject_id","subject_id", "run_id"]]
)
datagrabber.inputs.field_template = dict(
func= "ds000117-fmriprep/sub-%s/ses-mri/func/sub-%s_ses-mri_task-facerecognition_run-%d_space-MNI152NLin6Asym_desc-smoothAROMAnonaggr_bold.nii.gz",
events="ds000117/sub-%s/ses-mri/func/sub-%s_ses-mri_task-facerecognition_run-0%d_events.tsv",
)
wf.connect([
(infosource, datagrabber, [("subject_id", "subject_id")])])
wf.connect([(datagrabber, gunzip_func, [('func', 'in_file')])])First-level GLM¶
The subsequent task involves obtaining information such as stimuli type, onset, duration, and other regressors for integration into the GLM model. To accomplish this, a helper function needs to be created, which will be referred to as subjectinfo.
A TSV file for each run looks like this:
!cat ds000117/sub-01/ses-mri/func/sub-01_ses-mri_task-facerecognition_run-01_events.tsvonset duration circle_duration stim_type trigger button_pushed response_time stim_file
0 .908 .534 FAMOUS 5 4 2.158 func/f013.bmp
3.273 .962 .586 FAMOUS 6 4 1.233 func/f013.bmp
6.647 .825 .546 UNFAMILIAR 13 4 1.183 func/u014.bmp
9.838 .968 .597 UNFAMILIAR 14 4 .930 func/u014.bmp
12.978 .904 .415 UNFAMILIAR 13 7 1.068 func/u016.bmp
16.219 .859 .558 UNFAMILIAR 14 7 1.207 func/u016.bmp
19.443 .804 .585 UNFAMILIAR 13 4 1.286 func/u010.bmp
22.55 .879 .526 UNFAMILIAR 14 4 1.008 func/u010.bmp
25.606 .866 .416 SCRAMBLED 17 7 1.929 func/s002.bmp
28.697 .884 .461 SCRAMBLED 18 4 1.300 func/s002.bmp
31.319 20.000 20.000 n/a 999 20000 20.000 func/i999.bmp
51.898 .974 .543 FAMOUS 5 7 2.477 func/f004.bmp
55.173 .925 .534 SCRAMBLED 17 7 1.372 func/s008.bmp
58.313 .985 .439 UNFAMILIAR 13 4 1.431 func/u012.bmp
61.587 .862 .533 FAMOUS 5 4 1.086 func/f012.bmp
64.677 .869 .461 FAMOUS 6 4 1.018 func/f012.bmp
67.75 .804 .446 SCRAMBLED 17 7 1.267 func/s007.bmp
70.774 .873 .445 SCRAMBLED 17 7 1.211 func/s011.bmp
73.881 .983 .466 FAMOUS 7 7 1.203 func/f004.bmp
77.105 .998 .468 SCRAMBLED 17 7 1.240 func/s015.bmp
80.445 .833 .583 SCRAMBLED 19 7 1.379 func/s008.bmp
83.469 .940 .434 FAMOUS 5 7 1.637 func/f006.bmp
86.676 .813 .488 FAMOUS 6 7 1.209 func/f006.bmp
89.833 .994 .570 UNFAMILIAR 15 4 1.444 func/u012.bmp
93.19 .997 .594 FAMOUS 5 7 1.352 func/f009.bmp
96.448 .869 .491 FAMOUS 5 7 1.012 func/f005.bmp
99.655 .821 .571 SCRAMBLED 19 7 1.483 func/s007.bmp
102.695 .933 .437 FAMOUS 5 7 1.228 func/f002.bmp
105.869 .818 .481 FAMOUS 6 7 1.109 func/f002.bmp
108.942 .925 .487 SCRAMBLED 19 7 1.205 func/s011.bmp
111.615 20.000 20.000 n/a 999 20000 20.000 func/i999.bmp
132.144 .980 .498 FAMOUS 5 7 .898 func/f014.bmp
135.351 .833 .458 SCRAMBLED 19 n/a 0 func/s015.bmp
138.541 .999 .591 SCRAMBLED 17 4 1.940 func/s004.bmp
141.849 .868 .548 FAMOUS 5 4 1.366 func/f001.bmp
144.906 .832 .421 FAMOUS 6 4 1.433 func/f001.bmp
147.946 .897 .445 FAMOUS 7 7 .767 func/f009.bmp
151.186 .971 .575 UNFAMILIAR 13 7 1.604 func/u013.bmp
154.393 .978 .458 FAMOUS 7 7 1.137 func/f005.bmp
157.701 .984 .564 FAMOUS 5 7 1.248 func/f015.bmp
161.008 .900 .556 UNFAMILIAR 13 4 1.239 func/u011.bmp
164.265 .828 .594 UNFAMILIAR 14 4 1.269 func/u011.bmp
167.306 .830 .447 FAMOUS 7 7 1.116 func/f014.bmp
170.312 .992 .415 FAMOUS 5 7 1.806 func/f003.bmp
173.519 .942 .442 FAMOUS 6 7 1.361 func/f003.bmp
176.777 .874 .539 SCRAMBLED 19 4 1.363 func/s004.bmp
179.984 .845 .559 SCRAMBLED 17 4 1.131 func/s012.bmp
183.058 .981 .467 SCRAMBLED 17 7 .872 func/s001.bmp
186.365 .880 .559 SCRAMBLED 18 7 1.000 func/s001.bmp
189.422 .858 .414 UNFAMILIAR 15 4 1.095 func/u013.bmp
192.027 20.000 20.000 n/a 999 20000 20.000 func/i999.bmp
212.623 .873 .554 SCRAMBLED 17 4 1.718 func/s006.bmp
215.83 .863 .558 FAMOUS 7 7 1.115 func/f015.bmp
218.937 .984 .479 SCRAMBLED 17 7 1.449 func/s014.bmp
222.178 .873 .487 SCRAMBLED 18 7 .834 func/s014.bmp
225.452 .912 .536 UNFAMILIAR 13 4 1.099 func/u002.bmp
228.559 .952 .419 UNFAMILIAR 14 4 .915 func/u002.bmp
231.733 .891 .465 UNFAMILIAR 13 4 1.023 func/u004.bmp
234.89 .947 .496 UNFAMILIAR 14 4 .953 func/u004.bmp
238.164 .824 .560 SCRAMBLED 19 7 1.068 func/s012.bmp
241.187 .922 .425 FAMOUS 5 4 1.154 func/f011.bmp
244.478 .941 .593 SCRAMBLED 17 7 1.283 func/s005.bmp
247.668 .857 .482 SCRAMBLED 18 7 1.023 func/s005.bmp
250.825 .813 .524 SCRAMBLED 19 7 1.329 func/s006.bmp
253.849 .921 .450 FAMOUS 5 7 1.221 func/f007.bmp
257.072 .903 .528 SCRAMBLED 17 7 .788 func/s016.bmp
260.163 .969 .419 FAMOUS 5 4 1.369 func/f010.bmp
263.403 .892 .516 FAMOUS 6 4 1.183 func/f010.bmp
266.627 .950 .562 SCRAMBLED 17 7 1.326 func/s009.bmp
269.901 .935 .561 SCRAMBLED 18 7 1.010 func/s009.bmp
273.025 .896 .434 FAMOUS 7 7 1.431 func/f011.bmp
275.664 20.000 20.000 n/a 999 20000 20.000 func/i999.bmp
296.109 .895 .410 SCRAMBLED 17 4 1.541 func/s010.bmp
299.233 .908 .452 SCRAMBLED 18 4 1.010 func/s010.bmp
302.373 .866 .457 UNFAMILIAR 13 4 1.137 func/u008.bmp
305.53 .880 .519 FAMOUS 7 7 1.127 func/f007.bmp
308.588 .821 .417 SCRAMBLED 17 7 1.208 func/s003.bmp
311.594 .873 .403 SCRAMBLED 18 7 .965 func/s003.bmp
314.784 .967 .543 SCRAMBLED 19 7 1.126 func/s016.bmp
318.008 .913 .495 SCRAMBLED 17 4 1.137 func/s013.bmp
321.165 .957 .477 UNFAMILIAR 13 4 1.073 func/u007.bmp
324.423 .826 .534 UNFAMILIAR 14 4 .934 func/u007.bmp
327.479 .998 .457 UNFAMILIAR 13 4 1.293 func/u015.bmp
330.77 .981 .534 UNFAMILIAR 13 4 1.075 func/u009.bmp
334.011 .920 .491 UNFAMILIAR 15 4 1.075 func/u008.bmp
337.134 .967 .442 FAMOUS 5 7 .754 func/f008.bmp
340.425 .946 .552 FAMOUS 6 7 .917 func/f008.bmp
343.632 .870 .489 UNFAMILIAR 13 4 1.286 func/u003.bmp
346.839 .990 .552 UNFAMILIAR 14 4 1.141 func/u003.bmp
350.146 .937 .542 SCRAMBLED 19 4 1.334 func/s013.bmp
352.836 20.000 20.000 n/a 999 20000 20.000 func/i999.bmp
373.298 .816 .420 UNFAMILIAR 13 4 1.415 func/u001.bmp
376.455 .837 .577 UNFAMILIAR 14 4 1.247 func/u001.bmp
379.646 .825 .572 UNFAMILIAR 13 7 1.292 func/u006.bmp
382.786 .995 .540 UNFAMILIAR 15 4 1.003 func/u015.bmp
385.993 .976 .447 UNFAMILIAR 13 7 1.536 func/u005.bmp
389.3 .906 .558 UNFAMILIAR 15 4 1.078 func/u009.bmp
392.508 .957 .526 FAMOUS 5 7 1.223 func/f016.bmp
395.264 .012 0 n/a 999 0 0 func/Circle.bmp
As mentioned in the introduction, these event files will be adapted in the function ‘subjectinfo’ to demonstrate the setup of a 3x2 factorial design analysis. The original stimulus types (stim_types) FAMOUS, NONFAMILIAR, SCRAMBLED will be replaced with F1 (first presentation of an image of a famous face)/ F2 (second presentation of image), U1/U2 and S1/S1 due to the first or second occurance of the respective stimulus file (stim_file). In addition, stimuli of stimulus type n/a are deleted.
# Get the subject information: to create a GLM model, Nipype needs a list of Bunch objects per run (session)
def subjectinfo(events):
# packages need to be imported within the function for node to work (function is executed in a standalone environment)
from nipype.interfaces.base import Bunch
import pandas as pd
from collections import OrderedDict
trialinfo = pd.read_table(events)
# Filter out rows where stim_type does not contain 'FAMOUS', 'UNFAMILIAR', or 'SCRAMBLED' --> n/a
trialinfo = trialinfo[trialinfo['stim_type'].isin(['FAMOUS', 'UNFAMILIAR', 'SCRAMBLED'])].reset_index(drop=True)
# Create a dictionary to store the count of occurrences for each stim_file
stim_file_count = {}
# Iterate over each row in the dataframe
for index, row in trialinfo.iterrows():
# Get the stim_file value for the current row
stim_file = row['stim_file']
# If the stim_file is not in the stim_file_count dictionary, add it with count 1
if stim_file not in stim_file_count:
stim_file_count[stim_file] = 1
else:
# Increment the count for the stim_file and update the dictionary
stim_file_count[stim_file] += 1
# Get the count of occurrences for the current stim_file
count = stim_file_count[stim_file]
# Determine the new stim_type based on the stim_file and its count
if 'FAMOUS' in row['stim_type']:
new_stim_type = f'F{count}'
elif 'UNFAMILIAR' in row['stim_type']:
new_stim_type = f'U{count}'
else:
# If it's not 'FAMOUS' or 'UNFAMILIAR', it must be 'SCRAMBLED'
new_stim_type = f'S{count}'
# Update the stim_type in the dataframe
trialinfo.at[index, 'stim_type'] = new_stim_type
# Define the custom sorting order (instead of an alphabetic ordering F1, F2, S1, S2, U1, U2
sorting_order = OrderedDict([('F1', 1), ('F2', 2), ('U1', 3), ('U2', 4), ('S1', 5), ('S2', 6)])
conditions = []
onsets = []
durations = []
# Group trialinfo by 'stim_type' and iterate over groups
grouped_trials = trialinfo.groupby('stim_type')
for group_key in sorting_order.keys(): # Use keys() to iterate over keys
group_data = grouped_trials.get_group(group_key)
conditions.append(group_key)
onsets.append(group_data['onset'].tolist())
durations.append(group_data['duration'].tolist())
subject_info = Bunch(conditions=conditions,
onsets=onsets,
durations=durations)
return subject_info
getsubjectinfo = MapNode(Function(input_names=['events'],
output_names=['subject_info'],
function=subjectinfo),
name='getsubjectinfo', iterfield=['events'])wf.connect(datagrabber, 'events', getsubjectinfo, 'events')modelspec = Node(model.SpecifySPMModel(concatenate_runs=True,
input_units = 'secs',
output_units = 'secs',
time_repetition= TR,
high_pass_filter_cutoff=128), #in secs, slow signal drifts with a period > 128 will be removed
name='modelspec')
wf.connect(getsubjectinfo, 'subject_info', modelspec,'subject_info')
wf.connect(gunzip_func, 'out_file', modelspec, 'functional_runs')Level1Design: canonical HRF¶
The design matrix will be constructed without including derivatives of the hemodynamic response function (HRF) and therefore assumes a constant delay and dispersion for the hemodynamic response.
Starting in nipype version 1.8.7., when factor_info parameter is used in Level1design, T and F contrasts (ess, con, spmF and spmT images) are created automatically in EstimateModel by SPM. They need to be connected directly to a data output module
The following lines automatically inform SPM to create a default set of contrats for a factorial design.
# Level1Design - Generates an SPM design matrix
level1design = Node(spm.Level1Design(bases={'hrf':{'derivs': [0,0]}}, # no derivatives
timing_units='secs',
interscan_interval=TR,
microtime_onset=8, #The onset/time-bin in seconds for alignment
microtime_resolution=16, #Number of time-bins per scan in secs
mask_threshold=0.8,
global_intensity_normalization='none',
volterra_expansion_order=1, #do not model interactions
model_serial_correlations='AR(1)'), # serial correlations --> autoregressive AR(1) model during Classical (ReML) parameter estimation
name='level1design')
if Version(NIPYPE_VERSION) > Version("1.8.6"):
# Factors need to match conditions: product of levels (here 6) needs to match number of condition names --> F1, F2, U1, U2, S1, S2
level1design.inputs.factor_info = [dict(name = 'Face', levels = 3),
dict(name = 'Rep', levels = 2)]
wf.connect(modelspec,'session_info', level1design, 'session_info')stty: 'standard input': Inappropriate ioctl for device
# EstimateModel - estimate the parameters of the model
level1estimate = Node(spm.EstimateModel(estimation_method={'Classical':1}),
name='level1estimate')
wf.connect(level1design, 'spm_mat_file', level1estimate, 'spm_mat_file')Specify GLM contrast for nipype<=1.8.6¶
Contrasts need to be set up manually as they are not created automatically in EstimateModel when factor_info parameter is used in Level1Design.
condition_names = ['F1', 'F2', 'U1', 'U2', 'S1', 'S2'] #The condition names must match the names listed in the subjectinfo function described above.
cond1 = ('Positive effect of condition', 'T', condition_names, [1, 1, 1, 1, 1, 1])
# positive effect face
face1 = ('Positive effect of Face_1', 'T', condition_names, [1, 1, -1, -1, 0, 0])
face2 = ('Positive effect of Face_2', 'T', condition_names, [0, 0, 1, 1, -1, -1])
# rep1 > rep2
rep1 = ('Positive effect of Rep', 'T', condition_names, [1, -1, 1, -1, 1, -1])
# positive interaction face x rep
int1 = ('Positive interaction of Face x Rep1', 'T', condition_names, [1, -1, -1, 1, 0, 0])
int2 = ('Positive interaction of Face x Rep2', 'T', condition_names, [0, 0, 1, -1, -1, 1])
contf1 = ['Average effect condition', 'F', [cond1]]
contf2 = ['Main effect Face', 'F', [face1, face2]]
contf3 = ['Main effect Rep', 'F', [rep1]]
contf4 = ['Interaction: Face x Rep', 'F', [int1, int2]]
contrasts = [contf1, contf2, contf3, contf4, cond1, face1, face2, rep1, int1, int2]# EstimateContrast - explicit contrast estimation with nipype version <= 1.8.6 with the defined contrast list
if Version(NIPYPE_VERSION) <= Version("1.8.6"):
level1conest = Node(spm.EstimateContrast(),
name='level1conest')
level1conest.inputs.contrasts = contrasts
wf.connect([(level1estimate, level1conest, [('spm_mat_file','spm_mat_file'),
('beta_images','beta_images'),
('residual_image','residual_image')])])
else:
# NEW Nipype: contrasts already created in EstimateModel
passOutput stream¶
# save all results into one
datasink = Node(DataSink(), name='sinker')
datasink.inputs.base_directory=opj(experiment_dir, "level1_spm_results")wf.connect(infosource, 'subject_id', datasink, 'container')
if Version(NIPYPE_VERSION)<= Version("1.8.6"):
wf.connect([(level1conest, datasink, [('spm_mat_file', '1stLevel.@spm_mat'),
('spmT_images', '1stLevel.@T'),
('con_images', '1stLevel.@con'),
('spmF_images', '1stLevel.@F'),
('ess_images', '1stLevel.@ess')]),
])
# starting in nipype version 1.8.7., when factor_info parameter is used in Level1Design T and F contrasts (ess*, con*, spmF* and spmT* images)
# are created automatically by SPM in EstimateModel
else:
wf.connect(level1design, 'spm_mat_file', datasink, '1stLevel.@spm_mat')
wf.connect([(level1estimate, datasink, [
('spmT_images', '1stLevel.@T'),
('con_images', '1stLevel.@con'),
('spmF_images', '1stLevel.@F'),
('ess_images', '1stLevel.@ess')]),
])subFolders = [('%s/1stLevel' % s, 'sub-%s/' % s)
for s in sub_list]
subFolders1 = [('_subject_id_%s'%(s), '')
for s in sub_list]
subFolders.extend(subFolders1)
datasink.inputs.substitutions = subFolders# Create 1st-level analysis output graph
wf.write_graph(graph2use='colored', format='png', simple_form=True)
# Visualize the graph
from IPython.display import Image
Image(filename=opj(wf.base_dir, wf.name, 'graph.png'))260709-22:59:53,656 nipype.workflow INFO:
Generated workflow graph: /home/jovyan/workspace/books/examples/functional_imaging/spm_analysis/level1_spm/graph.png (graph2use=colored, simple_form=True).

wf.run(plugin="MultiProc") #will use all CPUsstty: 'standard input': Inappropriate ioctl for device
stty: 'standard input': Inappropriate ioctl for device
stty: 'standard input': Inappropriate ioctl for device
stty: 'standard input': Inappropriate ioctl for device
stty: 'standard input': Inappropriate ioctl for device
stty: 'standard input': Inappropriate ioctl for device
stty: 'standard input': Inappropriate ioctl for device
stty: 'standard input': Inappropriate ioctl for device
stty: 'standard input': Inappropriate ioctl for device
stty: 'standard input': Inappropriate ioctl for device
<networkx.classes.digraph.DiGraph at 0x7458d42874d0>Visualize design matrix and list contrasts¶
# Load
spm_data = loadmat(opj(experiment_dir, 'level1_spm_results/sub-01/SPM.mat'),
struct_as_record=False, squeeze_me=True)
SPM = spm_data['SPM']
# Exract Data
designMatrix = SPM.xX.X
names = SPM.xX.name
# Get contrast name
if hasattr(SPM, 'xCon'):
# xCon can be single object or list
if isinstance(SPM.xCon, np.ndarray):
names_contrast = [con.name for con in SPM.xCon]
else:
names_contrast = [SPM.xCon.name]
else:
names_contrast = []
# Plot
normed_design = designMatrix / np.abs(designMatrix).max(axis=0)
fig, ax = plt.subplots(figsize=(10, 8))
im = ax.imshow(normed_design, aspect='auto', cmap='gray')
ax.set_ylabel('Volume id')
ax.set_xticks(np.arange(len(names)))
ax.set_xticklabels(names, rotation=90)
plt.tight_layout()
plt.show()
# Clean up the whole working tree (keeps only your DataSink outputs)
import shutil
shutil.rmtree("spm_analysis/level1_spm", ignore_errors=True)2. Second Level Analysis¶
For a factorial design with 2 factors there are 4 effects to test for: an overall effect, 2 main effects and one two-way interaction:
To test (1) the overall effect, use a [1 1 1 1 1 1] contrast for each subject and take the resulting con images of all subjects into a one-sample t-test at the second level. Then specify a [1] F-contrast (at the second level) to test for significantly non-zero BOLD responses related to the paradigm.
To test for (2) the main effect of Factor Repetition (two levels), use a [1 -1 1 -1 1 -1] contrast for each subject and take the resulting con images into a one-sample t-test at the second level.
To test for (3) the main effect of Factor Face (three levels), use two contrasts per subject [1 1 -1 -1 0 0] and [0 0 1 1 -1 -1] and take all resulting con images (two per subject) into a two-sample t-test design at the second level. Then, use a [1 0; 0 1] F-contrast to test for this main effect.
To test for (4) the interaction between Factors Face and Rep, use two contrasts per subject [1 -1 -1 1 0 0] and [0 0 1 -1 -1 1] and take all resulting con images (two per subject) into a two-sample t-test design at the second level. Use then a [1 0; 0 1] F-contrast to test for this interaction effect.
2.1 One Sample T-Test: Overall effect, main effect of repetition¶
Test for significantly non-zero BOLD responses over all subjects.
con_0005: Positive effect
con_0006: Positive Effect F>S
con_0007: Positive Effect S>U
con_0008: Positive Effect of rep1>rep2
con_0009: Positive Interaction Face (F/S) x Rep
con_0010: Positive Interaction Face (S/U) x Rep
wf_2ndlevel_onesample = Workflow(name='level2_spm_1sample', base_dir=experiment_dir)
wf_2ndlevel_onesample.config["execution"]["crashfile_format"] = "txt"contrast_id = [5, 6, 7, 8, 9, 10] #contrasts con_0005 to con_0010
l2source = Node(DataGrabber(infields= ['con'], outfields=['contrasts']), name='l2source')
l2source.inputs.sort_filelist = True
l2source.inputs.base_directory = opj(experiment_dir, 'level1_spm_results')
l2source.inputs.template = '*'
l2source.inputs.field_template = dict(
contrasts = '*/con_%04d.nii'
)
# iterate over all contrast images
l2source.iterables = [('con', contrast_id)]# OneSampleTTest Design
onesamplettestdes = Node(interface=spm.OneSampleTTestDesign(), name="onesampttestdes")
wf_2ndlevel_onesample.connect([(l2source, onesamplettestdes, [('contrasts', 'in_files')])])# EstimateModel - estimates the model
l2estimate = Node(spm.EstimateModel(estimation_method={'Classical':1}), name='level2estimate')
# EstimateContast - estimates group contrast
l2conestimate = Node(spm.EstimateContrast(group_contrast=True), name = 'level2conestimate')
con_1= ['Group', 'T', ['mean'], [1]]
#con_2= ['Group', 'F', [con_1]] # if an F contrast is also wanted
l2conestimate.inputs.contrasts = [con_1] # con_2, include in list if wanted
# Threshold - thresholds contrasts
level2thresh = Node(spm.Threshold(contrast_index=1,# which contrast in the SPM.mat to use --> here set for con_1: T stat
use_topo_fdr=True, # whether to use FDR over cluster extent probabilities
use_fwe_correction=False, # whether to use FWE (Bonferroni) correction for initial threshold
extent_threshold=0, # minimum cluster size in voxels
height_threshold=0.005, # value for initial thresholding (defining clusters) - voxelwise
height_threshold_type='p-value',
extent_fdr_p_threshold=0.05), # p threshold on FDR corrected cluster size probabilities
name='level2thresh')
wf_2ndlevel_onesample.connect([(onesamplettestdes, l2estimate, [('spm_mat_file', 'spm_mat_file')]),
(l2estimate, l2conestimate, [('spm_mat_file', 'spm_mat_file'),
('beta_images', 'beta_images'),
('residual_image', 'residual_image')]),
(l2conestimate, level2thresh, [('spm_mat_file', 'spm_mat_file'),
('spmT_images', 'stat_image')])
])datasink_2nd = Node(DataSink(), name='datasink_2nd')
datasink_2nd.inputs.base_directory=opj(experiment_dir, 'level2_spm_results_1sample')
wf_2ndlevel_onesample.connect([(l2conestimate, datasink_2nd, [('spm_mat_file', '2ndLevel.@spm_mat'),
('spmT_images', '2ndLevel.@T'),
('con_images', '2ndLevel.@con')]),
(level2thresh, datasink_2nd, [('thresholded_map',
'2ndLevel.@threshold')])
])#replace _con_ with con
subFolders = [('2ndLevel/', '')]
subFolders1 = [('_con_', 'con')]
subFolders.extend(subFolders1)
datasink_2nd.inputs.substitutions = subFoldersfrom IPython.display import Image
wf_2ndlevel_onesample.write_graph(graph2use='colored', format='png', simple_form=True)
Image(filename=opj(wf_2ndlevel_onesample.base_dir, wf_2ndlevel_onesample.name, 'graph.png'))260709-23:01:37,796 nipype.workflow INFO:
Generated workflow graph: /home/jovyan/workspace/books/examples/functional_imaging/spm_analysis/level2_spm_1sample/graph.png (graph2use=colored, simple_form=True).

wf_2ndlevel_onesample.run(plugin="MultiProc")stty: 'standard input': Inappropriate ioctl for device
stty: 'standard input': Inappropriate ioctl for device
stty: 'standard input': Inappropriate ioctl for device
stty: 'standard input': Inappropriate ioctl for device
stty: 'standard input': Inappropriate ioctl for device
stty: 'standard input': Inappropriate ioctl for device
stty: 'standard input': Inappropriate ioctl for device
stty: 'standard input': Inappropriate ioctl for device
stty: 'standard input': Inappropriate ioctl for device
stty: 'standard input': Inappropriate ioctl for device
stty: 'standard input': Inappropriate ioctl for device
stty: 'standard input': Inappropriate ioctl for device
stty: 'standard input': Inappropriate ioctl for device
stty: 'standard input': Inappropriate ioctl for device
stty: 'standard input': Inappropriate ioctl for device
stty: 'standard input': Inappropriate ioctl for device
stty: 'standard input': Inappropriate ioctl for device
stty: 'standard input': Inappropriate ioctl for device
stty: 'standard input': Inappropriate ioctl for device
stty: 'standard input': Inappropriate ioctl for device
stty: 'standard input': Inappropriate ioctl for device
stty: 'standard input': Inappropriate ioctl for device
stty: 'standard input': Inappropriate ioctl for device
stty: 'standard input': Inappropriate ioctl for device
<networkx.classes.digraph.DiGraph at 0x7458d4179480># Clean up the whole working tree (keeps only your DataSink outputs)
shutil.rmtree("spm_analysis/level2_spm_1sample", ignore_errors=True)2.1 Two Sample T-Test: Main effect of face, Interaction Face x Repetition¶
Main effect of face: enter the following 2 contrasts per subject into a two-sample t-test and use 1 0, 0 1 F contrast
con_0006: Positive Effect F>S
con_0007: Positive Effect S>U
Interaction Face x Rep: enter the following 2 contrasts per subject into a two-sample t-test and use 1 0, 0 1 F contrast
con_0009: Positive Interaction Face (F/S) x Rep
con_0010: Positive Interaction Face (S/U) x Rep
wf_2ndlevel_twosample = Workflow(name='level2_spm_2sample', base_dir=experiment_dir)
wf_2ndlevel_twosample.config["execution"]["crashfile_format"] = "txt"contrast_id_1 = [6] #con_0006
contrast_id_2 = [7] #con_0007
l2source2 = Node(DataGrabber(outfields=["group_1", "group_2"]), name='l2source')
l2source2.inputs.sort_filelist = True
l2source2.inputs.contrast_id_1 = contrast_id_1
l2source2.inputs.contrast_id_2 = contrast_id_2
l2source2.inputs.base_directory = opj(experiment_dir, 'level1_spm_results')
l2source2.inputs.template = '*'
l2source2.inputs.template_args = dict(
group_1=[["contrast_id_1"]],
group_2=[["contrast_id_2"]])
l2source2.inputs.field_template = dict(
group_1 = "*/con_%04d.nii",
group_2 ="*/con_%04d.nii",
)# SecondLevelDesign - TwoSampleTTestDesign bases Factorial Design
twosamplettestdes = Node(interface=spm.TwoSampleTTestDesign(), name="twosampttestdes")
twosamplettestdes.inputs.dependent = False # measurements dependent between levels
twosamplettestdes.inputs.unequal_variance = True # equal or unequal between groups
wf_2ndlevel_twosample.connect([(l2source2, twosamplettestdes, [('group_1', 'group1_files')]),
(l2source2, twosamplettestdes, [('group_2', 'group2_files')])])l2estimate2 = Node(spm.EstimateModel(estimation_method={'Classical':1}), name='level2estimate')
# EstimateContast - estimates group contrast
l2conestimate2 = Node(spm.EstimateContrast(group_contrast=True), name = 'level2conestimate')
con_1 = ('Pos effect level 1','T', ['Group_{1}', 'Group_{2}'],[1, 0])
con_2 = ('Pos effect level 2','T', ['Group_{1}', 'Group_{2}'],[0, 1])
con_3 = ('Main effect', 'F', [con_1, con_2]) # main effect of face
l2conestimate2.inputs.contrasts = [con_1, con_2, con_3]
# Threshold - thresholds contrasts
level2thresh2 = MapNode(spm.Threshold(contrast_index=3,# which contrast in the SPM.mat to use --> here set for con_3: main effect
use_topo_fdr=True, # whether to use FDR over cluster extent probabilities
use_fwe_correction=False, # whether to use FWE (Bonferroni) correction for initial threshold
extent_threshold=0, # minimum cluster size in voxels
height_threshold=0.005, # value for initial thresholding (defining clusters) - voxelwise
height_threshold_type='p-value',
extent_fdr_p_threshold=0.05), # P threshold on FDR corrected cluster size probabilities
iterfield=['stat_image'],
name='level2thresh')
wf_2ndlevel_twosample.connect([(twosamplettestdes, l2estimate2, [('spm_mat_file', 'spm_mat_file')]),
(l2estimate2, l2conestimate2, [('spm_mat_file', 'spm_mat_file'),
('beta_images', 'beta_images'),
('residual_image', 'residual_image')]),
(l2conestimate2, level2thresh2, [('spm_mat_file', 'spm_mat_file'),
('spmT_images', 'stat_image')])
])datasink_2nd_2 = Node(DataSink(), name='datasink_2nd_2')
datasink_2nd_2.inputs.base_directory=opj(experiment_dir, 'level2_spm_results_2sample')
wf_2ndlevel_twosample.connect([(l2conestimate2, datasink_2nd_2, [('spm_mat_file', '2ndLevel.@spm_mat'),
('spmT_images', '2ndLevel.@T'),
('con_images', '2ndLevel.@con')]),
(level2thresh2, datasink_2nd_2, [('thresholded_map',
'2ndLevel.@threshold')])
])subFolders = [('2ndLevel/', 'MainEffectFace/')]
subFolders1 = [('_con_', 'con')]
subFolders2 = [('_level2thresh0', 'thresh_con1')]
subFolders3 = [('_level2thresh1', 'thresh_con2')]
subFolders4 = [('_level2thresh2', 'thresh_con3')]
subFolders.extend(subFolders1)
subFolders.extend(subFolders2)
subFolders.extend(subFolders3)
subFolders.extend(subFolders4)
datasink_2nd_2.inputs.substitutions = subFoldersfrom IPython.display import Image
wf_2ndlevel_twosample.write_graph(graph2use='colored', format='png', simple_form=True)
Image(filename=opj(wf_2ndlevel_twosample.base_dir, wf_2ndlevel_twosample.name, 'graph.png'))260709-23:02:38,161 nipype.workflow INFO:
Generated workflow graph: /home/jovyan/workspace/books/examples/functional_imaging/spm_analysis/level2_spm_2sample/graph.png (graph2use=colored, simple_form=True).

wf_2ndlevel_twosample.run(plugin="MultiProc")260709-23:02:38,173 nipype.workflow INFO:
Workflow level2_spm_2sample settings: ['check', 'execution', 'logging', 'monitoring']
260709-23:02:38,178 nipype.workflow INFO:
Running in parallel.
260709-23:02:38,180 nipype.workflow INFO:
[MultiProc] Running 0 tasks, and 1 jobs ready. Free memory (GB): 56.51/56.51, Free processors: 16/16, Free GPU slot:0/0.
260709-23:02:38,437 nipype.workflow INFO:
[Node] Setting-up "level2_spm_2sample.l2source" in "/home/jovyan/workspace/books/examples/functional_imaging/spm_analysis/level2_spm_2sample/l2source".
260709-23:02:38,443 nipype.workflow INFO:
[Node] Executing "l2source" <nipype.interfaces.io.DataGrabber>
260709-23:02:38,447 nipype.workflow INFO:
[Node] Finished "l2source", elapsed time 0.001359s.
260709-23:02:40,181 nipype.workflow INFO:
[Job 0] Completed (level2_spm_2sample.l2source).
260709-23:02:40,184 nipype.workflow INFO:
[MultiProc] Running 0 tasks, and 1 jobs ready. Free memory (GB): 56.51/56.51, Free processors: 16/16, Free GPU slot:0/0.
260709-23:02:40,357 nipype.workflow INFO:
[Node] Setting-up "level2_spm_2sample.twosampttestdes" in "/home/jovyan/workspace/books/examples/functional_imaging/spm_analysis/level2_spm_2sample/twosampttestdes".
260709-23:02:40,364 nipype.workflow INFO:
[Node] Executing "twosampttestdes" <nipype.interfaces.spm.model.TwoSampleTTestDesign>
260709-23:02:42,180 nipype.workflow INFO:
[MultiProc] Running 1 tasks, and 0 jobs ready. Free memory (GB): 56.31/56.51, Free processors: 15/16, Free GPU slot:0/0.
Currently running:
* level2_spm_2sample.twosampttestdes
260709-23:02:53,364 nipype.workflow INFO:
[Node] Finished "twosampttestdes", elapsed time 12.997545s.
260709-23:02:54,181 nipype.workflow INFO:
[Job 1] Completed (level2_spm_2sample.twosampttestdes).
260709-23:02:54,183 nipype.workflow INFO:
[MultiProc] Running 0 tasks, and 1 jobs ready. Free memory (GB): 56.51/56.51, Free processors: 16/16, Free GPU slot:0/0.
260709-23:02:54,292 nipype.workflow INFO:
[Node] Setting-up "level2_spm_2sample.level2estimate" in "/home/jovyan/workspace/books/examples/functional_imaging/spm_analysis/level2_spm_2sample/level2estimate".
260709-23:02:54,298 nipype.workflow INFO:
[Node] Executing "level2estimate" <nipype.interfaces.spm.model.EstimateModel>
260709-23:02:56,181 nipype.workflow INFO:
[MultiProc] Running 1 tasks, and 0 jobs ready. Free memory (GB): 56.31/56.51, Free processors: 15/16, Free GPU slot:0/0.
Currently running:
* level2_spm_2sample.level2estimate
260709-23:03:08,987 nipype.workflow INFO:
[Node] Finished "level2estimate", elapsed time 14.686787s.
260709-23:03:10,182 nipype.workflow INFO:
[Job 2] Completed (level2_spm_2sample.level2estimate).
260709-23:03:10,184 nipype.workflow INFO:
[MultiProc] Running 0 tasks, and 1 jobs ready. Free memory (GB): 56.51/56.51, Free processors: 16/16, Free GPU slot:0/0.
260709-23:03:10,302 nipype.workflow INFO:
[Node] Setting-up "level2_spm_2sample.level2conestimate" in "/home/jovyan/workspace/books/examples/functional_imaging/spm_analysis/level2_spm_2sample/level2conestimate".
260709-23:03:10,311 nipype.workflow INFO:
[Node] Executing "level2conestimate" <nipype.interfaces.spm.model.EstimateContrast>
260709-23:03:12,183 nipype.workflow INFO:
[MultiProc] Running 1 tasks, and 0 jobs ready. Free memory (GB): 56.31/56.51, Free processors: 15/16, Free GPU slot:0/0.
Currently running:
* level2_spm_2sample.level2conestimate
260709-23:03:24,9 nipype.workflow INFO:
[Node] Finished "level2conestimate", elapsed time 13.696088s.
260709-23:03:24,183 nipype.workflow INFO:
[Job 3] Completed (level2_spm_2sample.level2conestimate).
260709-23:03:24,185 nipype.workflow INFO:
[MultiProc] Running 0 tasks, and 1 jobs ready. Free memory (GB): 56.51/56.51, Free processors: 16/16, Free GPU slot:0/0.
260709-23:03:26,186 nipype.workflow INFO:
[MultiProc] Running 0 tasks, and 3 jobs ready. Free memory (GB): 56.51/56.51, Free processors: 16/16, Free GPU slot:0/0.
260709-23:03:26,326 nipype.workflow INFO:
[Node] Setting-up "_level2thresh1" in "/home/jovyan/workspace/books/examples/functional_imaging/spm_analysis/level2_spm_2sample/level2thresh/mapflow/_level2thresh1".
260709-23:03:26,326 nipype.workflow INFO:
[Node] Setting-up "_level2thresh0" in "/home/jovyan/workspace/books/examples/functional_imaging/spm_analysis/level2_spm_2sample/level2thresh/mapflow/_level2thresh0".
260709-23:03:26,327 nipype.workflow INFO:
[Node] Setting-up "_level2thresh2" in "/home/jovyan/workspace/books/examples/functional_imaging/spm_analysis/level2_spm_2sample/level2thresh/mapflow/_level2thresh2".
260709-23:03:26,334 nipype.workflow INFO:
[Node] Executing "_level2thresh0" <nipype.interfaces.spm.model.Threshold>
260709-23:03:26,334 nipype.workflow INFO:
[Node] Executing "_level2thresh1" <nipype.interfaces.spm.model.Threshold>
260709-23:03:26,335 nipype.workflow INFO:
[Node] Executing "_level2thresh2" <nipype.interfaces.spm.model.Threshold>
260709-23:03:28,186 nipype.workflow INFO:
[MultiProc] Running 3 tasks, and 0 jobs ready. Free memory (GB): 55.91/56.51, Free processors: 13/16, Free GPU slot:0/0.
Currently running:
* _level2thresh2
* _level2thresh1
* _level2thresh0
260709-23:03:35,240 nipype.workflow INFO:
[Node] Finished "_level2thresh0", elapsed time 8.904837s.
260709-23:03:35,322 nipype.workflow INFO:
[Node] Finished "_level2thresh1", elapsed time 8.98512s.
260709-23:03:35,358 nipype.workflow INFO:
[Node] Finished "_level2thresh2", elapsed time 9.02094s.
260709-23:03:36,186 nipype.workflow INFO:
[Job 6] Completed (_level2thresh0).
260709-23:03:36,187 nipype.workflow INFO:
[Job 7] Completed (_level2thresh1).
260709-23:03:36,188 nipype.workflow INFO:
[Job 8] Completed (_level2thresh2).
260709-23:03:36,189 nipype.workflow INFO:
[MultiProc] Running 0 tasks, and 1 jobs ready. Free memory (GB): 56.51/56.51, Free processors: 16/16, Free GPU slot:0/0.
260709-23:03:36,309 nipype.workflow INFO:
[Node] Setting-up "_level2thresh0" in "/home/jovyan/workspace/books/examples/functional_imaging/spm_analysis/level2_spm_2sample/level2thresh/mapflow/_level2thresh0".
260709-23:03:36,313 nipype.workflow INFO:
[Node] Cached "_level2thresh0" - collecting precomputed outputs
260709-23:03:36,314 nipype.workflow INFO:
[Node] "_level2thresh0" found cached.
260709-23:03:36,315 nipype.workflow INFO:
[Node] Setting-up "_level2thresh1" in "/home/jovyan/workspace/books/examples/functional_imaging/spm_analysis/level2_spm_2sample/level2thresh/mapflow/_level2thresh1".
260709-23:03:36,317 nipype.workflow INFO:
[Node] Cached "_level2thresh1" - collecting precomputed outputs
260709-23:03:36,318 nipype.workflow INFO:
[Node] "_level2thresh1" found cached.
260709-23:03:36,319 nipype.workflow INFO:
[Node] Setting-up "_level2thresh2" in "/home/jovyan/workspace/books/examples/functional_imaging/spm_analysis/level2_spm_2sample/level2thresh/mapflow/_level2thresh2".
260709-23:03:36,321 nipype.workflow INFO:
[Node] Cached "_level2thresh2" - collecting precomputed outputs
260709-23:03:36,321 nipype.workflow INFO:
[Node] "_level2thresh2" found cached.
260709-23:03:38,186 nipype.workflow INFO:
[Job 4] Completed (level2_spm_2sample.level2thresh).
260709-23:03:38,187 nipype.workflow INFO:
[MultiProc] Running 0 tasks, and 1 jobs ready. Free memory (GB): 56.51/56.51, Free processors: 16/16, Free GPU slot:0/0.
260709-23:03:38,296 nipype.workflow INFO:
[Node] Setting-up "level2_spm_2sample.datasink_2nd_2" in "/home/jovyan/workspace/books/examples/functional_imaging/spm_analysis/level2_spm_2sample/datasink_2nd_2".
260709-23:03:38,305 nipype.workflow INFO:
[Node] Executing "datasink_2nd_2" <nipype.interfaces.io.DataSink>
260709-23:03:38,307 nipype.interface INFO:
sub: /home/jovyan/workspace/books/examples/functional_imaging/spm_analysis/level2_spm_results_2sample/2ndLevel/SPM.mat -> /home/jovyan/workspace/books/examples/functional_imaging/spm_analysis/level2_spm_results_2sample/MainEffectFace/SPM.mat
260709-23:03:38,308 nipype.interface INFO:
sub: /home/jovyan/workspace/books/examples/functional_imaging/spm_analysis/level2_spm_results_2sample/2ndLevel/spmT_0001.nii -> /home/jovyan/workspace/books/examples/functional_imaging/spm_analysis/level2_spm_results_2sample/MainEffectFace/spmT_0001.nii
260709-23:03:38,309 nipype.interface INFO:
sub: /home/jovyan/workspace/books/examples/functional_imaging/spm_analysis/level2_spm_results_2sample/2ndLevel/spmT_0002.nii -> /home/jovyan/workspace/books/examples/functional_imaging/spm_analysis/level2_spm_results_2sample/MainEffectFace/spmT_0002.nii
260709-23:03:38,310 nipype.interface INFO:
sub: /home/jovyan/workspace/books/examples/functional_imaging/spm_analysis/level2_spm_results_2sample/2ndLevel/spmF_0003.nii -> /home/jovyan/workspace/books/examples/functional_imaging/spm_analysis/level2_spm_results_2sample/MainEffectFace/spmF_0003.nii
260709-23:03:38,311 nipype.interface INFO:
sub: /home/jovyan/workspace/books/examples/functional_imaging/spm_analysis/level2_spm_results_2sample/2ndLevel/con_0001.nii -> /home/jovyan/workspace/books/examples/functional_imaging/spm_analysis/level2_spm_results_2sample/MainEffectFace/con_0001.nii
260709-23:03:38,312 nipype.interface INFO:
sub: /home/jovyan/workspace/books/examples/functional_imaging/spm_analysis/level2_spm_results_2sample/2ndLevel/con_0002.nii -> /home/jovyan/workspace/books/examples/functional_imaging/spm_analysis/level2_spm_results_2sample/MainEffectFace/con_0002.nii
260709-23:03:38,313 nipype.interface INFO:
sub: /home/jovyan/workspace/books/examples/functional_imaging/spm_analysis/level2_spm_results_2sample/2ndLevel/ess_0003.nii -> /home/jovyan/workspace/books/examples/functional_imaging/spm_analysis/level2_spm_results_2sample/MainEffectFace/ess_0003.nii
260709-23:03:38,313 nipype.interface INFO:
sub: /home/jovyan/workspace/books/examples/functional_imaging/spm_analysis/level2_spm_results_2sample/2ndLevel/_level2thresh0/spmT_0001_thr.nii -> /home/jovyan/workspace/books/examples/functional_imaging/spm_analysis/level2_spm_results_2sample/MainEffectFace/thresh_con1/spmT_0001_thr.nii
260709-23:03:38,314 nipype.interface INFO:
sub: /home/jovyan/workspace/books/examples/functional_imaging/spm_analysis/level2_spm_results_2sample/2ndLevel/_level2thresh1/spmT_0002_thr.nii -> /home/jovyan/workspace/books/examples/functional_imaging/spm_analysis/level2_spm_results_2sample/MainEffectFace/thresh_con2/spmT_0002_thr.nii
260709-23:03:38,315 nipype.interface INFO:
sub: /home/jovyan/workspace/books/examples/functional_imaging/spm_analysis/level2_spm_results_2sample/2ndLevel/_level2thresh2/spmF_0003_thr.nii -> /home/jovyan/workspace/books/examples/functional_imaging/spm_analysis/level2_spm_results_2sample/MainEffectFace/thresh_con3/spmF_0003_thr.nii
260709-23:03:38,317 nipype.workflow INFO:
[Node] Finished "datasink_2nd_2", elapsed time 0.009333s.
260709-23:03:40,186 nipype.workflow INFO:
[Job 5] Completed (level2_spm_2sample.datasink_2nd_2).
260709-23:03:40,187 nipype.workflow INFO:
[MultiProc] Running 0 tasks, and 0 jobs ready. Free memory (GB): 56.51/56.51, Free processors: 16/16, Free GPU slot:0/0.
stty: 'standard input': Inappropriate ioctl for device
stty: 'standard input': Inappropriate ioctl for device
stty: 'standard input': Inappropriate ioctl for device
stty: 'standard input': Inappropriate ioctl for device
stty: 'standard input': Inappropriate ioctl for device
stty: 'standard input': Inappropriate ioctl for device
<networkx.classes.digraph.DiGraph at 0x74590f2908a0>contrast_id_1 = [9] #con_0009
contrast_id_2 = [10] #con_0010
l2source2.inputs.contrast_id_1 = contrast_id_1
l2source2.inputs.contrast_id_2 = contrast_id_2
subFolders = [('2ndLevel/', 'InteractionFace_Repetition/')]
subFolders.extend(subFolders1)
subFolders.extend(subFolders2)
subFolders.extend(subFolders3)
subFolders.extend(subFolders4)
datasink_2nd_2.inputs.substitutions = subFolders
wf_2ndlevel_twosample.run(plugin="MultiProc")260709-23:03:42,238 nipype.workflow INFO:
Workflow level2_spm_2sample settings: ['check', 'execution', 'logging', 'monitoring']
260709-23:03:42,243 nipype.workflow INFO:
Running in parallel.
260709-23:03:42,245 nipype.workflow INFO:
[MultiProc] Running 0 tasks, and 1 jobs ready. Free memory (GB): 56.51/56.51, Free processors: 16/16, Free GPU slot:0/0.
260709-23:03:42,355 nipype.workflow INFO:
[Node] Outdated cache found for "level2_spm_2sample.l2source".
260709-23:03:42,356 nipype.workflow INFO:
[Node] Outdated cache found for "level2_spm_2sample.l2source".
260709-23:03:42,495 nipype.workflow INFO:
[Node] Setting-up "level2_spm_2sample.l2source" in "/home/jovyan/workspace/books/examples/functional_imaging/spm_analysis/level2_spm_2sample/l2source".
260709-23:03:42,498 nipype.workflow INFO:
[Node] Outdated cache found for "level2_spm_2sample.l2source".
260709-23:03:42,502 nipype.workflow INFO:
[Node] Executing "l2source" <nipype.interfaces.io.DataGrabber>
260709-23:03:42,506 nipype.workflow INFO:
[Node] Finished "l2source", elapsed time 0.001315s.
260709-23:03:44,246 nipype.workflow INFO:
[Job 0] Completed (level2_spm_2sample.l2source).
260709-23:03:44,248 nipype.workflow INFO:
[MultiProc] Running 0 tasks, and 1 jobs ready. Free memory (GB): 56.51/56.51, Free processors: 16/16, Free GPU slot:0/0.
260709-23:03:44,418 nipype.workflow INFO:
[Node] Outdated cache found for "level2_spm_2sample.twosampttestdes".
260709-23:03:44,419 nipype.workflow INFO:
[Node] Outdated cache found for "level2_spm_2sample.twosampttestdes".
260709-23:03:44,422 nipype.workflow INFO:
[Node] Setting-up "level2_spm_2sample.twosampttestdes" in "/home/jovyan/workspace/books/examples/functional_imaging/spm_analysis/level2_spm_2sample/twosampttestdes".
260709-23:03:44,425 nipype.workflow INFO:
[Node] Outdated cache found for "level2_spm_2sample.twosampttestdes".
260709-23:03:44,430 nipype.workflow INFO:
[Node] Executing "twosampttestdes" <nipype.interfaces.spm.model.TwoSampleTTestDesign>
260709-23:03:46,246 nipype.workflow INFO:
[MultiProc] Running 1 tasks, and 0 jobs ready. Free memory (GB): 56.31/56.51, Free processors: 15/16, Free GPU slot:0/0.
Currently running:
* level2_spm_2sample.twosampttestdes
260709-23:03:57,385 nipype.workflow INFO:
[Node] Finished "twosampttestdes", elapsed time 12.952827s.
260709-23:03:58,247 nipype.workflow INFO:
[Job 1] Completed (level2_spm_2sample.twosampttestdes).
260709-23:03:58,249 nipype.workflow INFO:
[MultiProc] Running 0 tasks, and 1 jobs ready. Free memory (GB): 56.51/56.51, Free processors: 16/16, Free GPU slot:0/0.
260709-23:03:58,359 nipype.workflow INFO:
[Node] Outdated cache found for "level2_spm_2sample.level2estimate".
260709-23:03:58,360 nipype.workflow INFO:
[Node] Outdated cache found for "level2_spm_2sample.level2estimate".
260709-23:03:58,363 nipype.workflow INFO:
[Node] Setting-up "level2_spm_2sample.level2estimate" in "/home/jovyan/workspace/books/examples/functional_imaging/spm_analysis/level2_spm_2sample/level2estimate".
260709-23:03:58,366 nipype.workflow INFO:
[Node] Outdated cache found for "level2_spm_2sample.level2estimate".
260709-23:03:58,373 nipype.workflow INFO:
[Node] Executing "level2estimate" <nipype.interfaces.spm.model.EstimateModel>
260709-23:04:00,248 nipype.workflow INFO:
[MultiProc] Running 1 tasks, and 0 jobs ready. Free memory (GB): 56.31/56.51, Free processors: 15/16, Free GPU slot:0/0.
Currently running:
* level2_spm_2sample.level2estimate
260709-23:04:12,983 nipype.workflow INFO:
[Node] Finished "level2estimate", elapsed time 14.608098s.
260709-23:04:14,249 nipype.workflow INFO:
[Job 2] Completed (level2_spm_2sample.level2estimate).
260709-23:04:14,250 nipype.workflow INFO:
[MultiProc] Running 0 tasks, and 1 jobs ready. Free memory (GB): 56.51/56.51, Free processors: 16/16, Free GPU slot:0/0.
260709-23:04:14,369 nipype.workflow INFO:
[Node] Outdated cache found for "level2_spm_2sample.level2conestimate".
260709-23:04:14,370 nipype.workflow INFO:
[Node] Outdated cache found for "level2_spm_2sample.level2conestimate".
260709-23:04:14,375 nipype.workflow INFO:
[Node] Setting-up "level2_spm_2sample.level2conestimate" in "/home/jovyan/workspace/books/examples/functional_imaging/spm_analysis/level2_spm_2sample/level2conestimate".
260709-23:04:14,378 nipype.workflow INFO:
[Node] Outdated cache found for "level2_spm_2sample.level2conestimate".
260709-23:04:14,385 nipype.workflow INFO:
[Node] Executing "level2conestimate" <nipype.interfaces.spm.model.EstimateContrast>
260709-23:04:16,250 nipype.workflow INFO:
[MultiProc] Running 1 tasks, and 0 jobs ready. Free memory (GB): 56.31/56.51, Free processors: 15/16, Free GPU slot:0/0.
Currently running:
* level2_spm_2sample.level2conestimate
260709-23:04:27,927 nipype.workflow INFO:
[Node] Finished "level2conestimate", elapsed time 13.539982s.
260709-23:04:28,250 nipype.workflow INFO:
[Job 3] Completed (level2_spm_2sample.level2conestimate).
260709-23:04:28,252 nipype.workflow INFO:
[MultiProc] Running 0 tasks, and 1 jobs ready. Free memory (GB): 56.51/56.51, Free processors: 16/16, Free GPU slot:0/0.
260709-23:04:30,251 nipype.workflow INFO:
[MultiProc] Running 0 tasks, and 3 jobs ready. Free memory (GB): 56.51/56.51, Free processors: 16/16, Free GPU slot:0/0.
260709-23:04:30,357 nipype.workflow INFO:
[Node] Outdated cache found for "_level2thresh0".
260709-23:04:30,357 nipype.workflow INFO:
[Node] Outdated cache found for "_level2thresh0".
260709-23:04:30,359 nipype.workflow INFO:
[Node] Outdated cache found for "_level2thresh1".
260709-23:04:30,360 nipype.workflow INFO:
[Node] Outdated cache found for "_level2thresh1".
260709-23:04:30,362 nipype.workflow INFO:
[Node] Outdated cache found for "_level2thresh2".
260709-23:04:30,362 nipype.workflow INFO:
[Node] Outdated cache found for "_level2thresh2".
260709-23:04:30,361 nipype.workflow INFO:
[Node] Setting-up "_level2thresh0" in "/home/jovyan/workspace/books/examples/functional_imaging/spm_analysis/level2_spm_2sample/level2thresh/mapflow/_level2thresh0".
260709-23:04:30,364 nipype.workflow INFO:
[Node] Outdated cache found for "_level2thresh0".
260709-23:04:30,363 nipype.workflow INFO:
[Node] Setting-up "_level2thresh1" in "/home/jovyan/workspace/books/examples/functional_imaging/spm_analysis/level2_spm_2sample/level2thresh/mapflow/_level2thresh1".
260709-23:04:30,366 nipype.workflow INFO:
[Node] Outdated cache found for "_level2thresh1".
260709-23:04:30,365 nipype.workflow INFO:
[Node] Setting-up "_level2thresh2" in "/home/jovyan/workspace/books/examples/functional_imaging/spm_analysis/level2_spm_2sample/level2thresh/mapflow/_level2thresh2".
260709-23:04:30,368 nipype.workflow INFO:
[Node] Outdated cache found for "_level2thresh2".
260709-23:04:30,370 nipype.workflow INFO:
[Node] Executing "_level2thresh0" <nipype.interfaces.spm.model.Threshold>
260709-23:04:30,370 nipype.workflow INFO:
[Node] Executing "_level2thresh1" <nipype.interfaces.spm.model.Threshold>
260709-23:04:30,372 nipype.workflow INFO:
[Node] Executing "_level2thresh2" <nipype.interfaces.spm.model.Threshold>
260709-23:04:32,251 nipype.workflow INFO:
[MultiProc] Running 3 tasks, and 0 jobs ready. Free memory (GB): 55.91/56.51, Free processors: 13/16, Free GPU slot:0/0.
Currently running:
* _level2thresh2
* _level2thresh1
* _level2thresh0
260709-23:04:39,52 nipype.workflow INFO:
[Node] Finished "_level2thresh1", elapsed time 8.680071s.
260709-23:04:39,101 nipype.workflow INFO:
[Node] Finished "_level2thresh0", elapsed time 8.729315s.
260709-23:04:39,203 nipype.workflow INFO:
[Node] Finished "_level2thresh2", elapsed time 8.828596s.
260709-23:04:40,251 nipype.workflow INFO:
[Job 6] Completed (_level2thresh0).
260709-23:04:40,252 nipype.workflow INFO:
[Job 7] Completed (_level2thresh1).
260709-23:04:40,252 nipype.workflow INFO:
[Job 8] Completed (_level2thresh2).
260709-23:04:40,254 nipype.workflow INFO:
[MultiProc] Running 0 tasks, and 1 jobs ready. Free memory (GB): 56.51/56.51, Free processors: 16/16, Free GPU slot:0/0.
260709-23:04:40,352 nipype.workflow INFO:
[Node] Outdated cache found for "level2_spm_2sample.level2thresh".
260709-23:04:40,353 nipype.workflow INFO:
[Node] Outdated cache found for "level2_spm_2sample.level2thresh".
260709-23:04:40,358 nipype.workflow INFO:
[Node] Outdated cache found for "level2_spm_2sample.level2thresh".
260709-23:04:40,365 nipype.workflow INFO:
[Node] Setting-up "_level2thresh0" in "/home/jovyan/workspace/books/examples/functional_imaging/spm_analysis/level2_spm_2sample/level2thresh/mapflow/_level2thresh0".
260709-23:04:40,367 nipype.workflow INFO:
[Node] Cached "_level2thresh0" - collecting precomputed outputs
260709-23:04:40,368 nipype.workflow INFO:
[Node] "_level2thresh0" found cached.
260709-23:04:40,370 nipype.workflow INFO:
[Node] Setting-up "_level2thresh1" in "/home/jovyan/workspace/books/examples/functional_imaging/spm_analysis/level2_spm_2sample/level2thresh/mapflow/_level2thresh1".
260709-23:04:40,372 nipype.workflow INFO:
[Node] Cached "_level2thresh1" - collecting precomputed outputs
260709-23:04:40,373 nipype.workflow INFO:
[Node] "_level2thresh1" found cached.
260709-23:04:40,375 nipype.workflow INFO:
[Node] Setting-up "_level2thresh2" in "/home/jovyan/workspace/books/examples/functional_imaging/spm_analysis/level2_spm_2sample/level2thresh/mapflow/_level2thresh2".
260709-23:04:40,376 nipype.workflow INFO:
[Node] Cached "_level2thresh2" - collecting precomputed outputs
260709-23:04:40,377 nipype.workflow INFO:
[Node] "_level2thresh2" found cached.
260709-23:04:42,251 nipype.workflow INFO:
[Job 4] Completed (level2_spm_2sample.level2thresh).
260709-23:04:42,252 nipype.workflow INFO:
[MultiProc] Running 0 tasks, and 1 jobs ready. Free memory (GB): 56.51/56.51, Free processors: 16/16, Free GPU slot:0/0.
260709-23:04:42,356 nipype.workflow INFO:
[Node] Outdated cache found for "level2_spm_2sample.datasink_2nd_2".
260709-23:04:42,357 nipype.workflow INFO:
[Node] Outdated cache found for "level2_spm_2sample.datasink_2nd_2".
260709-23:04:42,360 nipype.workflow INFO:
[Node] Setting-up "level2_spm_2sample.datasink_2nd_2" in "/home/jovyan/workspace/books/examples/functional_imaging/spm_analysis/level2_spm_2sample/datasink_2nd_2".
260709-23:04:42,363 nipype.workflow INFO:
[Node] Outdated cache found for "level2_spm_2sample.datasink_2nd_2".
260709-23:04:42,367 nipype.workflow INFO:
[Node] Executing "datasink_2nd_2" <nipype.interfaces.io.DataSink>
260709-23:04:42,369 nipype.interface INFO:
sub: /home/jovyan/workspace/books/examples/functional_imaging/spm_analysis/level2_spm_results_2sample/2ndLevel/SPM.mat -> /home/jovyan/workspace/books/examples/functional_imaging/spm_analysis/level2_spm_results_2sample/InteractionFace_Repetition/SPM.mat
260709-23:04:42,370 nipype.interface INFO:
sub: /home/jovyan/workspace/books/examples/functional_imaging/spm_analysis/level2_spm_results_2sample/2ndLevel/spmT_0001.nii -> /home/jovyan/workspace/books/examples/functional_imaging/spm_analysis/level2_spm_results_2sample/InteractionFace_Repetition/spmT_0001.nii
260709-23:04:42,371 nipype.interface INFO:
sub: /home/jovyan/workspace/books/examples/functional_imaging/spm_analysis/level2_spm_results_2sample/2ndLevel/spmT_0002.nii -> /home/jovyan/workspace/books/examples/functional_imaging/spm_analysis/level2_spm_results_2sample/InteractionFace_Repetition/spmT_0002.nii
260709-23:04:42,372 nipype.interface INFO:
sub: /home/jovyan/workspace/books/examples/functional_imaging/spm_analysis/level2_spm_results_2sample/2ndLevel/spmF_0003.nii -> /home/jovyan/workspace/books/examples/functional_imaging/spm_analysis/level2_spm_results_2sample/InteractionFace_Repetition/spmF_0003.nii
260709-23:04:42,373 nipype.interface INFO:
sub: /home/jovyan/workspace/books/examples/functional_imaging/spm_analysis/level2_spm_results_2sample/2ndLevel/con_0001.nii -> /home/jovyan/workspace/books/examples/functional_imaging/spm_analysis/level2_spm_results_2sample/InteractionFace_Repetition/con_0001.nii
260709-23:04:42,374 nipype.interface INFO:
sub: /home/jovyan/workspace/books/examples/functional_imaging/spm_analysis/level2_spm_results_2sample/2ndLevel/con_0002.nii -> /home/jovyan/workspace/books/examples/functional_imaging/spm_analysis/level2_spm_results_2sample/InteractionFace_Repetition/con_0002.nii
260709-23:04:42,375 nipype.interface INFO:
sub: /home/jovyan/workspace/books/examples/functional_imaging/spm_analysis/level2_spm_results_2sample/2ndLevel/ess_0003.nii -> /home/jovyan/workspace/books/examples/functional_imaging/spm_analysis/level2_spm_results_2sample/InteractionFace_Repetition/ess_0003.nii
260709-23:04:42,376 nipype.interface INFO:
sub: /home/jovyan/workspace/books/examples/functional_imaging/spm_analysis/level2_spm_results_2sample/2ndLevel/_level2thresh0/spmT_0001_thr.nii -> /home/jovyan/workspace/books/examples/functional_imaging/spm_analysis/level2_spm_results_2sample/InteractionFace_Repetition/thresh_con1/spmT_0001_thr.nii
260709-23:04:42,377 nipype.interface INFO:
sub: /home/jovyan/workspace/books/examples/functional_imaging/spm_analysis/level2_spm_results_2sample/2ndLevel/_level2thresh1/spmT_0002_thr.nii -> /home/jovyan/workspace/books/examples/functional_imaging/spm_analysis/level2_spm_results_2sample/InteractionFace_Repetition/thresh_con2/spmT_0002_thr.nii
260709-23:04:42,378 nipype.interface INFO:
sub: /home/jovyan/workspace/books/examples/functional_imaging/spm_analysis/level2_spm_results_2sample/2ndLevel/_level2thresh2/spmF_0003_thr.nii -> /home/jovyan/workspace/books/examples/functional_imaging/spm_analysis/level2_spm_results_2sample/InteractionFace_Repetition/thresh_con3/spmF_0003_thr.nii
260709-23:04:42,379 nipype.workflow INFO:
[Node] Finished "datasink_2nd_2", elapsed time 0.009914s.
260709-23:04:44,251 nipype.workflow INFO:
[Job 5] Completed (level2_spm_2sample.datasink_2nd_2).
260709-23:04:44,253 nipype.workflow INFO:
[MultiProc] Running 0 tasks, and 0 jobs ready. Free memory (GB): 56.51/56.51, Free processors: 16/16, Free GPU slot:0/0.
stty: 'standard input': Inappropriate ioctl for device
stty: 'standard input': Inappropriate ioctl for device
stty: 'standard input': Inappropriate ioctl for device
stty: 'standard input': Inappropriate ioctl for device
stty: 'standard input': Inappropriate ioctl for device
stty: 'standard input': Inappropriate ioctl for device
<networkx.classes.digraph.DiGraph at 0x74590edf3a80>#Clean up working directory, keep only Datasink
shutil.rmtree("spm_analysis/level2_spm_2sample", ignore_errors=True)Results¶
The group analysis was only done on N=9 subjects, a voxel-wise threshold of p<0.005 was chosen and a cluster-wise FDR threshold of p<0.05 to correct for multiple comparisons.
Look at the positive effect using the plot_stat_map plotting method of nilearn¶
import warnings
warnings.filterwarnings("ignore", message="Non-finite values detected")
plotting.plot_stat_map(opj(experiment_dir, 'level2_spm_results_1sample/con5/spmT_0001_thr.nii'), title='Positive Effect', dim=1, display_mode='y', cut_coords=(-45, -30, -15, 0, 15), threshold=2, vmax=8, cmap='viridis');
Look at the results using the glass brain plotting method of¶
Note: with 5 subjects × 2 runs this is an underpowered demonstration — expect only the strongest contrast to survive thresholding; subtler contrasts may render as empty glass brains.
plotting.plot_glass_brain(opj(experiment_dir, 'level2_spm_results_1sample/con5/spmT_0001_thr.nii'),
colorbar=True, threshold=2, display_mode='lyrz', black_bg=True, vmax=10, title='Positive effect');
plotting.plot_glass_brain(opj(experiment_dir, 'level2_spm_results_1sample/con6/spmT_0001_thr.nii'),
colorbar=True, threshold=2, display_mode='lyrz', black_bg=True, vmax=10, title='Positive effect Famous>Unfamiliar');
plotting.plot_glass_brain(opj(experiment_dir, 'level2_spm_results_1sample/con7/spmT_0001_thr.nii'),
colorbar=True, threshold=2, display_mode='lyrz', black_bg=True, vmax=10, title='Positive effect Unfamiliar>Scambled');
plotting.plot_glass_brain(opj(experiment_dir, 'level2_spm_results_1sample/con8/spmT_0001_thr.nii'),
colorbar=True, threshold=2, display_mode='lyrz', black_bg=True, vmax=10, title='Positive Effect of rep1>rep2');
plotting.plot_glass_brain(opj(experiment_dir, 'level2_spm_results_1sample/con9/spmT_0001_thr.nii'),
colorbar=True, threshold=2, display_mode='lyrz', black_bg=True, vmax=10, title='Positive Interaction Face (Famous/Unfamiliar) x Rep');
plotting.plot_glass_brain(opj(experiment_dir, 'level2_spm_results_1sample/con10/spmT_0001_thr.nii'),
colorbar=True, threshold=2, display_mode='lyrz', black_bg=True, vmax=10, title='Positive Interaction Face (Unfamiliar/Scrambled) x Rep');/tmp/ipykernel_1966/3476432501.py:4: UserWarning: empty mask
plotting.plot_glass_brain(opj(experiment_dir, 'level2_spm_results_1sample/con6/spmT_0001_thr.nii'),
/tmp/ipykernel_1966/3476432501.py:13: UserWarning: empty mask
plotting.plot_glass_brain(opj(experiment_dir, 'level2_spm_results_1sample/con9/spmT_0001_thr.nii'),
/tmp/ipykernel_1966/3476432501.py:16: UserWarning: empty mask
plotting.plot_glass_brain(opj(experiment_dir, 'level2_spm_results_1sample/con10/spmT_0001_thr.nii'),






Visualize main effects face and interaction face x repetition¶
plotting.plot_glass_brain(opj(experiment_dir, 'level2_spm_results_2sample/MainEffectFace/thresh_con3/spmF_0003_thr.nii'),
colorbar=True, display_mode='lyrz', black_bg=True, vmax=10, title='Main effect face');
plotting.plot_glass_brain(opj(experiment_dir, 'level2_spm_results_2sample/InteractionFace_Repetition/thresh_con3/spmF_0003_thr.nii'),
colorbar=True, display_mode='lyrz', black_bg=True, vmax=10, title='Interaction face x repetition');

Dependencies in Jupyter/Python¶
Using the package watermark to document system environment and software versions used in this notebook, alongside the Neurodesktop version extracted from the
JUPYTER_IMAGEorNEURODESKTOP_VERSIONenvironment variables.
import os
%load_ext watermark
%watermark
%watermark --iversions
neurodesktop_version = (
os.environ.get('JUPYTER_IMAGE', '').split(':')[-1] or
os.environ.get('NEURODESKTOP_VERSION', 'unknown')
)
print(f"Neurodesktop version: {neurodesktop_version}")Last updated: 2026-07-09T23:04:54.366536+00:00
Python implementation: CPython
Python version : 3.13.13
IPython version : 9.12.0
Compiler : GCC 14.3.0
OS : Linux
Release : 6.8.0-111-generic
Machine : x86_64
Processor : x86_64
CPU cores : 16
Architecture: 64bit
IPython : 9.12.0
json : 2.0.9
matplotlib: 3.10.9
nilearn : 0.13.1
nipype : 1.11.0
numpy : 2.4.6
packaging : 25.0
pandas : 2.3.3
scipy : 1.16.3
Neurodesktop version: 2026-06-04
- Esteban, O., Markiewicz, C. J., Burns, C., Goncalves, M., Jarecka, D., Ziegler, E., Berleant, S., Ellis, D. G., Pinsard, B., Madison, C., Waskom, M., Notter, M. P., Clark, D., Manhães-Savio, A., Clark, D., Jordan, K., Dayan, M., Halchenko, Y. O., Loney, F., … Ghosh, S. (2025). nipy/nipype: 1.8.6. Zenodo. 10.5281/ZENODO.15054147