Skip to content

Instantly share code, notes, and snippets.

@emdupre
Last active June 3, 2020 14:01
Show Gist options
  • Select an option

  • Save emdupre/dad8c4f27fa992d02fd9a9292b4bbb66 to your computer and use it in GitHub Desktop.

Select an option

Save emdupre/dad8c4f27fa992d02fd9a9292b4bbb66 to your computer and use it in GitHub Desktop.
import numpy as np
import pandas as pd
import nibabel as nib
from pathlib import Path, PurePath
from nilearn import image
from numpy.lib import recfunctions
from nilearn.input_data import NiftiMasker
from nistats.first_level_model import FirstLevelModel
"""
Utilities for postprocessing the data.
"""
def _subset_confounds(tsv):
"""
Only retain those confounds listed in `keep_confounds`
Parameters
----------
tsv: str
Local file path to the fMRIPrep generated confound files
"""
keep_confounds = ['trans_x', 'trans_y', 'trans_z',
'rot_x', 'rot_y', 'rot_z']
# load in tsv and subset to only include our desired regressors
tsv = str(tsv)
confounds = np.recfromcsv(tsv, delimiter='\t')
selected_confounds = confounds[keep_confounds]
return selected_confounds
def _relabel_wm_events(events):
"""
Relabels trial types for working memory (WM) events, so that we will
decode on object category rather than n-back level.
Parameters
----------
events: str
File-path to a BIDS-formatted events.tsv file in the CNeuroMod
project
"""
df = pd.read_table(events)
category = df.trial_type.str.split('_', expand=True)[1]
df.trial_type = category
return df
def _generate_beta_maps(scans, confounds, events, conditions, mask, fname):
"""
Generates beta-maps for use in decoding
Parameters
----------
scans: list
A list of Niimg-like objects or file paths for the
appropriate BOLD files collected during the task
confounds: list
Any confounds to correct for in the cleaned data set
events: list
A list of pd.DataFrames or file paths for BIDS-formatted
events.tsv files
conditions: list
A list of conditions for which to generate beta maps.
Must correspond to trial_types in provided events
mask: str
The mask within which to process data
fname: str
The filename with which to save the resulting maps.
"""
if len(scans) != len(events):
err_msg = ("Number of event files does not match the " +
"number of provided BOLD files. Please re-confirm the " +
"file listings.")
raise ValueError(err_msg)
glm = FirstLevelModel(mask_img=mask, t_r=1.49, high_pass=0.01,
smoothing_fwhm=5, standardize=True)
z_maps, condition_idx, session_idx = [], [], []
for scan, event, confound in zip(scans, events, confounds):
session = PurePath(scan).parts[2] # This is poorly designed, liable to break
glm.fit(run_imgs=scan, events=event, confounds=confound)
for condition in conditions:
z_maps.append(glm.compute_contrast(condition))
condition_idx.append(condition)
session_idx.append(session)
sid = fname.split('_')[0] # safe since we set the filename
nib.save(image.concat_imgs(z_maps), fname)
np.savetxt('{}_labels.csv'.format(sid), condition_idx, fmt='%s')
np.savetxt('{}_runs.csv'.format(sid), session_idx, fmt='%s')
def postproc_task(subject, task_label, tpl_mask):
"""
Parameters
----------
subject: str
The full subject identifier, e.g. 'sub-01'
task_label: str
The task label used in naming the files, dropping the 'task-' key,
e.g., 'wm'
tpl_mask: str
The local file path to the grey matter mask derived from
the template
"""
func = 'space-MNI152NLin2009cAsym_desc-preproc_bold.nii.gz'
regr = 'desc-confounds_regressors.tsv'
scans = sorted(Path('derivatives', 'fmriprep', subject).rglob(
'*_task-{}*{}'.format(task_label, func)))
regressors = sorted(Path('derivatives', 'fmriprep', subject).rglob(
'*_task-{}*{}'.format(task_label, regr)))
events = sorted(Path(subject).rglob(
'*_task-{}*events.tsv'.format(task_label)))
scans = [str(s) for s in scans]
confounds = [pd.DataFrame.from_records(_subset_confounds(r))
for r in regressors]
# we know that sub-05 only has nine sessions of the WM task
# so we'll subset all subjects to the first 9 runs for balanced data
# availability. This can be removed later once additional data is collected
scans = scans[:9]
confounds = confounds[:9]
events = events[:9]
if task_label == 'wm':
events = [_relabel_wm_events(e) for e in events]
else:
events = [pd.read_table(e) for e in events]
_generate_beta_maps(
scans=scans, confounds=confounds, events=events,
conditions=['body', 'face', 'place', 'tools'],
mask=tpl_mask, fname='{}_task-{}_{}'.format(
subject, task_label, func.replace('preproc', 'postproc')))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment