def test_high_level_glm_different_design_matrices(): # test that one can estimate a contrast when design matrices are different shapes, rk = ((7, 8, 7, 15), (7, 8, 7, 19)), 3 mask, fmri_data, design_matrices = generate_fake_fmri_data_and_design(shapes, rk) # add a column to the second design matrix design_matrices[1]['new'] = np.ones((19, 1)) # Fit a glm with two sessions and design matrices multi_session_model = FirstLevelModel(mask_img=mask).fit( fmri_data, design_matrices=design_matrices) z_joint = multi_session_model.compute_contrast( [np.eye(rk)[:1], np.eye(rk + 1)[:1]], output_type='effect_size') assert z_joint.shape == (7, 8, 7) # compare the estimated effects to seprarately-fitted models model1 = FirstLevelModel(mask_img=mask).fit( fmri_data[0], design_matrices=design_matrices[0]) z1 = model1.compute_contrast(np.eye(rk)[:1], output_type='effect_size') model2 = FirstLevelModel(mask_img=mask).fit( fmri_data[1], design_matrices=design_matrices[1]) z2 = model2.compute_contrast(np.eye(rk + 1)[:1], output_type='effect_size') assert_almost_equal(get_data(z1) + get_data(z2), 2 * get_data(z_joint))
def test_z_score_opposite_contrast(): fmri, mask = generate_fake_fmri(shape=(50, 20, 50), length=96, rand_gen=np.random.RandomState(42)) nifti_masker = NiftiMasker(mask_img=mask) data = nifti_masker.fit_transform(fmri) frametimes = np.linspace(0, (96 - 1) * 2, 96) for i in [0, 20]: design_matrix = make_first_level_design_matrix( frametimes, hrf_model='spm', add_regs=np.array(data[:, i]).reshape(-1, 1)) c1 = np.array([1] + [0] * (design_matrix.shape[1] - 1)) c2 = np.array([0] + [1] + [0] * (design_matrix.shape[1] - 2)) contrasts = {'seed1 - seed2': c1 - c2, 'seed2 - seed1': c2 - c1} fmri_glm = FirstLevelModel(t_r=2., noise_model='ar1', standardize=False, hrf_model='spm', drift_model='cosine') fmri_glm.fit(fmri, design_matrices=design_matrix) z_map_seed1_vs_seed2 = fmri_glm.compute_contrast( contrasts['seed1 - seed2'], output_type='z_score') z_map_seed2_vs_seed1 = fmri_glm.compute_contrast( contrasts['seed2 - seed1'], output_type='z_score') assert_almost_equal(z_map_seed1_vs_seed2.get_data().min(), -z_map_seed2_vs_seed1.get_data().max(), decimal=10) assert_almost_equal(z_map_seed1_vs_seed2.get_data().max(), -z_map_seed2_vs_seed1.get_data().min(), decimal=10)
def test_explicit_fixed_effects(): """ tests the fixed effects performed manually/explicitly""" with InTemporaryDirectory(): shapes, rk = ((7, 8, 7, 15), (7, 8, 7, 16)), 3 mask, fmri_data, design_matrices =\ write_fake_fmri_data_and_design(shapes, rk) contrast = np.eye(rk)[1] # session 1 multi_session_model = FirstLevelModel(mask_img=mask).fit( fmri_data[0], design_matrices=design_matrices[:1]) dic1 = multi_session_model.compute_contrast(contrast, output_type='all') # session 2 multi_session_model.fit(fmri_data[1], design_matrices=design_matrices[1:]) dic2 = multi_session_model.compute_contrast(contrast, output_type='all') # fixed effects model multi_session_model.fit(fmri_data, design_matrices=design_matrices) fixed_fx_dic = multi_session_model.compute_contrast(contrast, output_type='all') # manual version contrasts = [dic1['effect_size'], dic2['effect_size']] variance = [dic1['effect_variance'], dic2['effect_variance']] ( fixed_fx_contrast, fixed_fx_variance, fixed_fx_stat, ) = compute_fixed_effects(contrasts, variance, mask) assert_almost_equal(get_data(fixed_fx_contrast), get_data(fixed_fx_dic['effect_size'])) assert_almost_equal(get_data(fixed_fx_variance), get_data(fixed_fx_dic['effect_variance'])) assert_almost_equal(get_data(fixed_fx_stat), get_data(fixed_fx_dic['stat'])) # test without mask variable ( fixed_fx_contrast, fixed_fx_variance, fixed_fx_stat, ) = compute_fixed_effects(contrasts, variance) assert_almost_equal(get_data(fixed_fx_contrast), get_data(fixed_fx_dic['effect_size'])) assert_almost_equal(get_data(fixed_fx_variance), get_data(fixed_fx_dic['effect_variance'])) assert_almost_equal(get_data(fixed_fx_stat), get_data(fixed_fx_dic['stat'])) # ensure that using unbalanced effects size and variance images # raises an error with pytest.raises(ValueError): compute_fixed_effects(contrasts * 2, variance, mask) del mask, multi_session_model
def test_high_level_glm_null_contrasts(): # test that contrast computation is resilient to 0 values. shapes, rk = ((7, 8, 7, 15), (7, 8, 7, 19)), 3 mask, fmri_data, design_matrices = \ generate_fake_fmri_data_and_design(shapes, rk) multi_session_model = FirstLevelModel(mask_img=None).fit( fmri_data, design_matrices=design_matrices) single_session_model = FirstLevelModel(mask_img=None).fit( fmri_data[0], design_matrices=design_matrices[0]) z1 = multi_session_model.compute_contrast( [np.eye(rk)[:1], np.zeros((1, rk))], output_type='stat') z2 = single_session_model.compute_contrast(np.eye(rk)[:1], output_type='stat') np.testing.assert_almost_equal(get_data(z1), get_data(z2))
def run_glm(dmtx, contrasts, fmri_data, mask_img, subject_dic, subject_session_output_dir, tr, slice_time_ref, smoothing_fwhm=False): """ Run the GLM on a given session and compute contrasts Parameters ---------- dmtx : array-like the design matrix for the model contrasts : dict holding the numerical specification of contrasts fmri_data : Nifti1Image the fMRI data fir by the model mask_img : Nifti1Image the mask used for the fMRI data """ from nilearn.glm.first_level import FirstLevelModel fmri_4d = nib.load(fmri_data) # GLM analysis print('Fitting a GLM (this takes time)...') fmri_glm = FirstLevelModel(mask_img=mask_img, t_r=tr, slice_time_ref=slice_time_ref, smoothing_fwhm=smoothing_fwhm).fit( fmri_4d, design_matrices=dmtx) # compute contrasts z_maps = {} for contrast_id, contrast_val in contrasts.items(): print("\tcontrast id: %s" % contrast_id) # store stat maps to disk for map_type in ['z_score', 'stat', 'effect_size', 'effect_variance']: stat_map = fmri_glm.compute_contrast(contrast_val, output_type=map_type) map_dir = os.path.join(subject_session_output_dir, '%s_maps' % map_type) if not os.path.exists(map_dir): os.makedirs(map_dir) map_path = os.path.join(map_dir, '%s.nii.gz' % contrast_id) print("\t\tWriting %s ..." % map_path) stat_map.to_filename(map_path) # collect zmaps for contrasts we're interested in if map_type == 'z_score': z_maps[contrast_id] = map_path return z_maps, fmri_glm
def test_first_level_hrf_model(hrf_model, spaces): """ Ensure that FirstLevelModel runs without raising errors for different values of hrf_model. In particular, one checks that it runs without raising errors when given a custom response function. Also ensure that it computes contrasts without raising errors, even when event (ie condition) names have spaces. """ shapes, rk = [(10, 10, 10, 25)], 3 mask, fmri_data, _ =\ generate_fake_fmri_data_and_design(shapes, rk) events = basic_paradigm(condition_names_have_spaces=spaces) model = FirstLevelModel(t_r=2.0, mask_img=mask, hrf_model=hrf_model) model.fit(fmri_data, events) columns = model.design_matrices_[0].columns model.compute_contrast(f"{columns[0]}-{columns[1]}")
def test_high_level_glm_with_paths(): shapes, rk = ((7, 8, 7, 15), (7, 8, 7, 14)), 3 with InTemporaryDirectory(): mask_file, fmri_files, design_files = write_fake_fmri_data_and_design(shapes, rk) multi_session_model = FirstLevelModel(mask_img=None).fit( fmri_files, design_matrices=design_files) z_image = multi_session_model.compute_contrast(np.eye(rk)[1]) assert_array_equal(z_image.affine, load(mask_file).affine) assert get_data(z_image).std() < 3. # Delete objects attached to files to avoid WindowsError when deleting # temporary directory (in Windows) del z_image, fmri_files, multi_session_model
def test_high_level_glm_one_session(): shapes, rk = [(7, 8, 9, 15)], 3 mask, fmri_data, design_matrices = generate_fake_fmri_data_and_design(shapes, rk) single_session_model = FirstLevelModel(mask_img=None).fit( fmri_data[0], design_matrices=design_matrices[0]) assert isinstance(single_session_model.masker_.mask_img_, Nifti1Image) single_session_model = FirstLevelModel(mask_img=mask).fit( fmri_data[0], design_matrices=design_matrices[0]) z1 = single_session_model.compute_contrast(np.eye(rk)[:1]) assert isinstance(z1, Nifti1Image)
def test_high_level_glm_different_design_matrices_formulas(): # test that one can estimate a contrast when design matrices are different shapes, rk = ((7, 8, 7, 15), (7, 8, 7, 19)), 3 mask, fmri_data, design_matrices =\ generate_fake_fmri_data_and_design(shapes, rk) # make column names identical design_matrices[1].columns = design_matrices[0].columns # add a column to the second design matrix design_matrices[1]['new'] = np.ones((19, 1)) # Fit a glm with two sessions and design matrices multi_session_model = FirstLevelModel(mask_img=mask).fit( fmri_data, design_matrices=design_matrices) # Compute contrast with formulas cols_formula = tuple(design_matrices[0].columns[:2]) formula = "%s-%s" % cols_formula with pytest.warns(UserWarning, match='One contrast given, ' 'assuming it for all 2 runs'): multi_session_model.compute_contrast(formula, output_type='effect_size')
def test_high_level_glm_with_data(): with InTemporaryDirectory(): shapes, rk = ((7, 8, 7, 15), (7, 8, 7, 16)), 3 mask, fmri_data, design_matrices = write_fake_fmri_data_and_design(shapes, rk) multi_session_model = FirstLevelModel(mask_img=None).fit( fmri_data, design_matrices=design_matrices) n_voxels = get_data(multi_session_model.masker_.mask_img_).sum() z_image = multi_session_model.compute_contrast(np.eye(rk)[1]) assert np.sum(get_data(z_image) != 0) == n_voxels assert get_data(z_image).std() < 3. # with mask multi_session_model = FirstLevelModel(mask_img=mask).fit( fmri_data, design_matrices=design_matrices) z_image = multi_session_model.compute_contrast( np.eye(rk)[:2], output_type='z_score') p_value = multi_session_model.compute_contrast( np.eye(rk)[:2], output_type='p_value') stat_image = multi_session_model.compute_contrast( np.eye(rk)[:2], output_type='stat') effect_image = multi_session_model.compute_contrast( np.eye(rk)[:2], output_type='effect_size') variance_image = multi_session_model.compute_contrast( np.eye(rk)[:2], output_type='effect_variance') assert_array_equal(get_data(z_image) == 0., get_data(load(mask)) == 0.) assert (get_data(variance_image)[get_data(load(mask)) > 0] > .001 ).all() all_images = multi_session_model.compute_contrast( np.eye(rk)[:2], output_type='all') assert_array_equal(get_data(all_images['z_score']), get_data(z_image)) assert_array_equal(get_data(all_images['p_value']), get_data(p_value)) assert_array_equal(get_data(all_images['stat']), get_data(stat_image)) assert_array_equal(get_data(all_images['effect_size']), get_data(effect_image)) assert_array_equal(get_data(all_images['effect_variance']), get_data(variance_image)) # Delete objects attached to files to avoid WindowsError when deleting # temporary directory (in Windows) del (all_images, design_matrices, effect_image, fmri_data, mask, multi_session_model, n_voxels, p_value, rk, shapes, stat_image, variance_image, z_image)
def test_high_level_glm_one_session(): shapes, rk = [(7, 8, 9, 15)], 3 mask, fmri_data, design_matrices = generate_fake_fmri_data_and_design(shapes, rk) # Give an unfitted NiftiMasker as mask_img and check that we get an error masker = NiftiMasker(mask) with pytest.raises(ValueError, match="It seems that NiftiMasker has not been fitted."): single_session_model = FirstLevelModel(mask_img=masker).fit( fmri_data[0], design_matrices=design_matrices[0]) # Give a fitted NiftiMasker with a None mask_img_ attribute # and check that the masker parameters are overriden by the # FirstLevelModel parameters masker.fit() masker.mask_img_ = None with pytest.warns(UserWarning, match="Parameter memory of the masker overriden"): single_session_model = FirstLevelModel(mask_img=masker).fit( fmri_data[0], design_matrices=design_matrices[0]) # Give a fitted NiftiMasker masker = NiftiMasker(mask) masker.fit() single_session_model = FirstLevelModel(mask_img=masker).fit( fmri_data[0], design_matrices=design_matrices[0]) assert single_session_model.masker_ == masker # Call with verbose (improve coverage) single_session_model = FirstLevelModel(mask_img=None, verbose=1).fit( fmri_data[0], design_matrices=design_matrices[0]) single_session_model = FirstLevelModel(mask_img=None).fit( fmri_data[0], design_matrices=design_matrices[0]) assert isinstance(single_session_model.masker_.mask_img_, Nifti1Image) single_session_model = FirstLevelModel(mask_img=mask).fit( fmri_data[0], design_matrices=design_matrices[0]) z1 = single_session_model.compute_contrast(np.eye(rk)[:1]) assert isinstance(z1, Nifti1Image)
def test_compute_contrast_num_contrasts(): shapes, rk = ((7, 8, 7, 15), (7, 8, 7, 19), (7, 8, 7, 13)), 3 mask, fmri_data, design_matrices = generate_fake_fmri_data_and_design(shapes, rk) # Fit a glm with 3 sessions and design matrices multi_session_model = FirstLevelModel(mask_img=mask).fit( fmri_data, design_matrices=design_matrices) # raise when n_contrast != n_runs | 1 with pytest.raises(ValueError): multi_session_model.compute_contrast([np.eye(rk)[1]]*2) multi_session_model.compute_contrast([np.eye(rk)[1]]*3) with pytest.warns(UserWarning, match='One contrast given, assuming it for all 3 runs'): multi_session_model.compute_contrast([np.eye(rk)[1]])
def test_first_level_contrast_computation(): with InTemporaryDirectory(): shapes = ((7, 8, 9, 10), ) mask, FUNCFILE, _ = write_fake_fmri_data_and_design(shapes) FUNCFILE = FUNCFILE[0] func_img = load(FUNCFILE) # basic test based on basic_paradigm and glover hrf t_r = 10.0 slice_time_ref = 0. events = basic_paradigm() # Ordinary Least Squares case model = FirstLevelModel(t_r, slice_time_ref, mask_img=mask, drift_model='polynomial', drift_order=3, minimize_memory=False) c1, c2, cnull = np.eye(7)[0], np.eye(7)[1], np.zeros(7) # asking for contrast before model fit gives error with pytest.raises(ValueError): model.compute_contrast(c1) # fit model model = model.fit([func_img, func_img], [events, events]) # Check that an error is raised for invalid contrast_def with pytest.raises(ValueError, match="contrast_def must be an " "array or str or list"): model.compute_contrast(37) # smoke test for different contrasts in fixed effects model.compute_contrast([c1, c2]) # smoke test for same contrast in fixed effects model.compute_contrast([c2, c2]) # smoke test for contrast that will be repeated model.compute_contrast(c2) model.compute_contrast(c2, 'F') model.compute_contrast(c2, 't', 'z_score') model.compute_contrast(c2, 't', 'stat') model.compute_contrast(c2, 't', 'p_value') model.compute_contrast(c2, None, 'effect_size') model.compute_contrast(c2, None, 'effect_variance') # formula should work (passing variable name directly) model.compute_contrast('c0') model.compute_contrast('c1') model.compute_contrast('c2') # smoke test for one null contrast in group model.compute_contrast([c2, cnull]) # only passing null contrasts should give back a value error with pytest.raises(ValueError): model.compute_contrast(cnull) with pytest.raises(ValueError): model.compute_contrast([cnull, cnull]) # passing wrong parameters with pytest.raises(ValueError): model.compute_contrast([]) with pytest.raises(ValueError): model.compute_contrast([c1, []]) with pytest.raises(ValueError): model.compute_contrast(c1, '', '') with pytest.raises(ValueError): model.compute_contrast(c1, '', []) # Delete objects attached to files to avoid WindowsError when deleting # temporary directory (in Windows) del func_img, FUNCFILE, model
minimize_memory=True) ######################################################################### # Compute fixed effects of the two runs and compute related images # For this, we first define the contrasts as we would do for a single session n_columns = design_matrices[0].shape[1] contrast_val = np.hstack(([-1, -1, 1, 1], np.zeros(n_columns - 4))) ######################################################################### # Statistics for the first session from nilearn import plotting cut_coords = [-129, -126, 49] contrast_id = 'DSt_minus_SSt' fmri_glm = fmri_glm.fit(fmri_img[0], design_matrices=design_matrices[0]) summary_statistics_session1 = fmri_glm.compute_contrast(contrast_val, output_type='all') plotting.plot_stat_map(summary_statistics_session1['z_score'], bg_img=mean_img_, threshold=3.0, cut_coords=cut_coords, title='{0}, first session'.format(contrast_id)) ######################################################################### # Statistics for the second session fmri_glm = fmri_glm.fit(fmri_img[1], design_matrices=design_matrices[1]) summary_statistics_session2 = fmri_glm.compute_contrast(contrast_val, output_type='all') plotting.plot_stat_map(summary_statistics_session2['z_score'], bg_img=mean_img_, threshold=3.0,
def main(subject, session, sourcedata): runs = range(1, 9) behavior = [] for run in runs: behavior.append(pd.read_table(op.join( sourcedata, f'sub-{subject}/ses-{session}/func/sub-{subject}_ses-{session}_task-task-{run}_events.tsv'))) behavior = pd.concat(behavior, keys=runs, names=['run']) behavior['subject'] = subject behavior = behavior.reset_index().set_index( ['subject', 'run', 'trial_type']) ims = [ op.join(sourcedata, f'derivatives/fmriprep/sub-{subject}/ses-{session}/func/sub-{subject}_ses-{session}_task-task_run-{run}_space-T1w_desc-preproc_bold.nii.gz') for run in runs] mask_img = op.join(sourcedata, f'derivatives/fmriprep/sub-{subject}/ses-{session}/func/sub-{subject}_ses-{session}_task-task_run-1_space-T1w_desc-brain_mask.nii.gz') fmriprep_confounds_include = ['global_signal', 'dvars', 'framewise_displacement', 'trans_x', 'trans_y', 'trans_z', 'rot_x', 'rot_y', 'rot_z', 'a_comp_cor_00', 'a_comp_cor_01', 'a_comp_cor_02', 'a_comp_cor_03', 'cosine00', 'cosine01', 'cosine02', 'cosine03', 'non_steady_state_outlier00', 'non_steady_state_outlier01', 'non_steady_state_outlier02'] fmriprep_confounds = [ op.join(sourcedata, f'derivatives/fmriprep/sub-{subject}/ses-{session}/func/sub-{subject}_ses-{session}_task-task_run-{run}_desc-confounds_timeseries.tsv') for run in runs] fmriprep_confounds = [pd.read_table( cf)[fmriprep_confounds_include] for cf in fmriprep_confounds] retroicor_confounds = [ op.join(sourcedata, f'derivatives/physiotoolbox/sub-{subject}/ses-{session}/func/sub-{subject}_ses-{session}_task-task_run-{run}_desc-retroicor_timeseries.tsv') for run in runs] retroicor_confounds = [pd.read_table( cf, header=None, usecols=range(18)) for cf in retroicor_confounds] confounds = [pd.concat((rcf, fcf), axis=1) for rcf, fcf in zip(retroicor_confounds, fmriprep_confounds)] confounds = [c.fillna(method='bfill') for c in confounds] print(behavior) print(confounds) model = FirstLevelModel(t_r=2.3, slice_time_ref=.5, signal_scaling=False, drift_model=None, mask_img=mask_img, smoothing_fwhm=0.0) stimulus1 = behavior.xs('stimulus 1', 0, 'trial_type', drop_level=False).reset_index('trial_type')[['onset', 'trial_type']] stimulus1['duration'] = 0.6 stimulus2 = behavior.xs('stimulus 2', 0, 'trial_type', drop_level=False).reset_index('trial_type')[['onset', 'trial_type']] stimulus2['duration'] = 0.6 n1 = behavior.xs('stimulus 1', 0, 'trial_type', drop_level=False).reset_index('trial_type')[['onset', 'trial_type', 'n1']] n1['duration'] = 0.6 def zscore(n): return (n - n.mean()) / n.std() n1['modulation'] = zscore(n1['n1']) n1['trial_type'] = 'n_dots1' n2 = behavior.xs('stimulus 2', 0, 'trial_type', drop_level=False).reset_index('trial_type')[['onset', 'trial_type', 'n2']] n2['duration'] = 0.6 def zscore(n): return (n - n.mean()) / n.std() n2['modulation'] = zscore(n2['n2']) n2['trial_type'] = 'n_dots2' p1 = behavior.xs('stimulus 1', 0, 'trial_type', drop_level=False).reset_index('trial_type')[['onset', 'trial_type', 'prob1']] p1 = p1[p1.prob1 == 1.0] p1['duration'] = 0.6 p1['trial_type'] = 'certain1' p2 = behavior.xs('stimulus 2', 0, 'trial_type', drop_level=False).reset_index('trial_type')[['onset', 'trial_type', 'prob2']] p2 = p2[p2.prob2 == 1.0] p2['duration'] = 0.6 p2['trial_type'] = 'certain2' events = pd.concat((stimulus1, stimulus2, n1, n2, p1, p2)).sort_values('onset') events['modulation'].fillna(1.0, inplace=True) print(events) model.fit(ims, [r for _, r in events.groupby(['run'])], confounds) zmaps = {} results_dir = op.join(sourcedata, 'derivatives', 'glm', 'simple_task', f'sub-{subject}', f'ses-{session}') if not op.exists(results_dir): os.makedirs(results_dir) for key in ['stimulus 1', 'stimulus 2', 'n_dots1', 'n_dots2', 'certain1', 'certain2']: zmaps[key] = model.compute_contrast(key) zmaps[key].to_filename(op.join(results_dir, f'sub-{subject}_ses-{session}_zmap_{key}.nii.gz'))
active_minus_rest = conditions['active'] - conditions['rest'] ############################################################################### # Let's look at it: plot the coefficients of the contrast, indexed by # the names of the columns of the design matrix. from nilearn.reporting import plot_contrast_matrix plot_contrast_matrix(active_minus_rest, design_matrix=design_matrix) ############################################################################### # Below, we compute the estimated effect. It is in BOLD signal unit, # but has no statistical guarantees, because it does not take into # account the associated variance. eff_map = fmri_glm.compute_contrast(active_minus_rest, output_type='effect_size') ############################################################################### # In order to get statistical significance, we form a t-statistic, and # directly convert it into z-scale. The z-scale means that the values # are scaled to match a standard Gaussian distribution (mean=0, # variance=1), across voxels, if there were no effects in the data. z_map = fmri_glm.compute_contrast(active_minus_rest, output_type='z_score') ############################################################################### # Plot thresholded z scores map # ------------------------------ # # We display it on top of the average # functional image of the series (could be the anatomical image of the
def main(subject, session, bids_folder, smoothed=False, pca_confounds=False, space='fsnative', n_jobs=14): derivatives = op.join(bids_folder, 'derivatives') runs = range(1, 9) ims = [ op.join( derivatives, f'fmriprep/sub-{subject}/ses-{session}/func/sub-{subject}_ses-{session}_task-task_run-{run}_space-T1w_desc-preproc_bold.nii.gz' ) for run in runs ] mask = op.join( derivatives, f'fmriprep/sub-{subject}/ses-{session}/func/sub-{subject}_ses-{session}_task-task_run-1_space-T1w_desc-brain_mask.nii.gz' ) base_dir = 'glm_stim1' if smoothed: base_dir += '.smoothed' if pca_confounds: base_dir += '.pca_confounds' base_dir = op.join(derivatives, base_dir, f'sub-{subject}', f'ses-{session}', 'func') if not op.exists(base_dir): os.makedirs(base_dir) behavior = [] for run in runs: behavior.append( pd.read_table( op.join( bids_folder, f'sub-{subject}/ses-{session}/func/sub-{subject}_ses-{session}_task-task_run-{run}_events.tsv' ))) behavior = pd.concat(behavior, keys=runs, names=['run']) behavior = behavior.reset_index().set_index(['run', 'trial_type']) stimulus1 = behavior.xs( 'stimulus 1', 0, 'trial_type', drop_level=False).reset_index('trial_type')[['onset', 'trial_type']] stimulus1['duration'] = 0.6 stimulus2 = behavior.xs('stimulus 2', 0, 'trial_type', drop_level=False).reset_index('trial_type')[[ 'onset', 'trial_type', 'trial_nr' ]] stimulus2['duration'] = 0.6 stimulus2['trial_type'] = stimulus2.trial_nr.map( lambda trial: f'trial_{trial}') print(stimulus2) n1 = behavior.xs('stimulus 1', 0, 'trial_type', drop_level=False).reset_index('trial_type')[[ 'onset', 'trial_type', 'n1' ]] n1['duration'] = 0.6 def zscore(n): return (n - n.mean()) / n.std() n1['modulation'] = zscore(n1['n1']) n1['trial_type'] = 'n_dots1' p1 = behavior.xs('stimulus 1', 0, 'trial_type', drop_level=False).reset_index('trial_type')[[ 'onset', 'trial_type', 'prob1' ]] p1 = p1[p1.prob1 == 1.0] p1['duration'] = 0.6 p1['trial_type'] = 'certain1' events = pd.concat( (stimulus1, stimulus2, n1, p1)).set_index('trial_nr', append=True).sort_index() events['modulation'].fillna(1.0, inplace=True) print(events) fmriprep_confounds_include = [ 'global_signal', 'dvars', 'framewise_displacement', 'trans_x', 'trans_y', 'trans_z', 'rot_x', 'rot_y', 'rot_z', 'a_comp_cor_00', 'a_comp_cor_01', 'a_comp_cor_02', 'a_comp_cor_03', 'cosine00', 'cosine01', 'cosine02', 'cosine03', 'non_steady_state_outlier00', 'non_steady_state_outlier01', 'non_steady_state_outlier02' ] fmriprep_confounds = [ op.join( bids_folder, f'derivatives/fmriprep/sub-{subject}/ses-{session}/func/sub-{subject}_ses-{session}_task-task_run-{run}_desc-confounds_timeseries.tsv' ) for run in runs ] fmriprep_confounds = [ pd.read_table(cf)[fmriprep_confounds_include] for cf in fmriprep_confounds ] retroicor_confounds = [ op.join( bids_folder, f'derivatives/physiotoolbox/sub-{subject}/ses-{session}/func/sub-{subject}_ses-{session}_task-task_run-{run}_desc-retroicor_timeseries.tsv' ) for run in runs ] retroicor_confounds = [ pd.read_table(cf, header=None, usecols=range(18)) if op.exists(cf) else pd.DataFrame(np.zeros((160, 0))) for cf in retroicor_confounds ] confounds = [ pd.concat((rcf, fcf), axis=1) for rcf, fcf in zip(retroicor_confounds, fmriprep_confounds) ] confounds = [c.fillna(method='bfill') for c in confounds] t_r, n_scans = 2.3, 160 frame_times = t_r * (np.arange(n_scans) + .5) model = FirstLevelModel(t_r=2.3, slice_time_ref=.5, signal_scaling=False, drift_model=None, mask_img=mask, smoothing_fwhm=0.0) single_trial_betas = [] for run in runs: im = image.math_img('(im / im.mean(-1)[..., np.newaxis]) * 100 - 100', im=ims[run - 1]) model.fit(im, events.loc[run], confounds[run - 1]) for trial in range(1 + (run - 1) * 24, 1 + run * 24): print(trial) single_trial_betas.append( model.compute_contrast(f'trial_{trial}', output_type='effect_size')) single_trial_betas = image.concat_imgs(single_trial_betas) single_trial_betas.to_filename( op.join( base_dir, f'sub-{subject}_ses-{session}_task-task_space-T1w_desc-stims2_pe.nii.gz' ))
def get_contrasts(fmri_img: Union[str, PathLike, PosixPath, Nifti1Image], events: Union[str, PathLike, PosixPath, pd.DataFrame], desc: str = 'effect_size', design_kws: Union[dict, Bunch] = None, glm_kws: Union[dict, Bunch] = None, masker_kws: Union[dict, Bunch] = None, standardize: bool = True, scale: bool = False, scale_between: tuple = (0, 1), maximize: bool = False, masker: [MultiNiftiMasker, NiftiLabelsMasker, NiftiMapsMasker, NiftiMasker] = None, feature_labels: Union[Sequence, pd.Index] = None, session=None, **kwargs ) -> Bunch: """ Return dict-like structure containing experimental contrasts. Using ``nilearn.glm.first_level.FirstLevel`` object, contrasts are first computed trial-wise. Then, the same is done for each experimental condition in ``trial_type_cols`` if a list of string is provided. Args: fmri_img: str, PathLike, PosixPath or Nifti1Image In-memory or path pointing to a ``nibabel.nifti1.Nifti1Image``. events: : str, PathLike, PosixPath or DataFrame In-memory or path pointing to a ``pandas.DataFrame``. desc: str (Default = 'effect_size') String passed to ``nilearn.glm.first_level.FirstLevel.compute_contrast`` ``desc`` parameter. design_kws: dict or Bunch (Deault = None) Dict-like mapping of keyword arguments passed to ``nilearn.glm.first_level.make_first_level_design_matrix``. If a ``session`` object is passed in the parameters, the value under the corresponding key is used. glm_kws: dict or Bunch (Deault = None) Dict-like mapping of keyword arguments passed to ``nilearn.glm.first_level.FirstLevel.__init__``. If a ``session`` object is passed in the parameters, the value under the corresponding key is used. masker_kws: dict or Bunch (Deault = None) Dict-like mapping of keyword arguments passed to ``masker.__init__``. If a ``session`` object is passed in the parameters, the value under the corresponding key is used. standardize: bool (Default = True) If true (by default), the extracted brain signals are standardized using a ``sklearn.preprocessing.StandardScaler`` object (demeaning ans scaling to variance). It is generally advised to standardize data for machine-learning operations. See notes for documentation, tutorials and more. scale: bool (Default = False) If true, the extracted brain signals are scaled (between 0 and 1 by default) using a ``sklearn.preprocessing.MinMaxScaler`` object. It is generally advised to standardize data for machine-learning operations. See notes for documentation, tutorials and more. scale_between: tuple (Default = (0, 1) Values between which the signal should be scaled. Default is (0, 1) - left = min, right = max. Only used if ``scale`` parameter is True. maximize: bool (Default = False) If true, scale each feature by its maximum absolute value. From the docs of ``sklearn.preprocessing.MaxAbsScaler``: '[...] Scales and translates each feature individually such that the maximal absolute value of each feature in training set is 1.0. Does not shift/center the data, and thus does not destroy any sparsity.' masker: MultiNiftiMasker, NiftiLabelsMasker, NiftiMapsMasker or NiftiMasker (Default = None) Masker object from the ``nilearn.input_data`` module meant to perform brain signal extraction (conversion from 4D or 3D image to 2D data). If omitted, a NiftiMasker with default parameters is used. feature_labels: List or pd.Index (Default = None) List of feature names used as columns for the brain signal matrix. Number of labels and number of features must match. An error is raised otherwise. session: dict or Bunch (Default = None) Dict-like structure containing all required and/or optional parameters. The functions ``fetch_fmriprep_session`` and ``get_fmri_session`` from ``cimaq_decoding_utils`` return a ``session`` object. It is similar to the return values of ``nilearn.datasets.fetch{dataset_name}`` functions. Returns: ``sklearn.utils.Bunch`` Dict-like structure with the following keys: ['model', 'contrast_img', 'signals', 'feature_labels', 'condition_labels'] Notes: https://scikit-learn.org/stable/modules/preprocessing.html#preprocessing """ from sklearn.pipeline import Pipeline from sklearn.preprocessing import MaxAbsScaler, MinMaxScaler from sklearn.preprocessing import StandardScaler from cimaq_decoding_utils import get_frame_times, get_t_r # Parameter initialization design_defs, glm_defs = {}, {} fmri_img = nimage.image.load_img(fmri_img) events = [events if isinstance(events, pd.DataFrame) else pd.read_csv(events, sep=['\t' if splitext(events)[1][1] == 't' else ','][0])][0] if session is not None: design_defs.update(session.design_defs) glm_defs.update(session.glm_defs) t_r, frame_times = get_t_r(fmri_img), get_frame_times(fmri_img) if design_kws is not None: design_defs.update(design_kws) if glm_kws is not None: glm_defs.update(glm_kws) # GLM initialization and contrast computation design = make_first_level_design_matrix(frame_times, events=events.iloc[1:, :], **design_defs) model = FirstLevelModel(**glm_defs).fit(run_imgs=fmri_img, design_matrices=design.iloc[:, 1:]) contrasts = nimage.concat_imgs([model.compute_contrast( trial, desc=desc) for trial in tqdm_(design.columns[:-1].astype(str), ncols=100, desc='Computing Contrasts')]) # Brain signals extraction pipe_components = ((standardize, 'standardize', StandardScaler()), (maximize, 'maximize', MaxAbsScaler()), (scale, 'scale', MinMaxScaler(scale_between))) pipe_components = [item[1:] for item in list(filter(lambda x: x[0], pipe_components))] signals = masker.transform_single_imgs(contrasts) if pipe_components != []: pipeline = Pipeline(pipe_components) signals = pipeline.fit_transform(signals) signals = pd.DataFrame(signals, index=design.iloc[:, :-1].columns) if feature_labels is not None: signals.set_axis(feature_labels, axis=1, inplace=True) return Bunch(model=model, contrast_img=contrasts, signals=signals, feature_labels=feature_labels)
def main(subject, session, sourcedata): runs = range(1, 5) behavior = [] for run in runs: behavior.append( pd.read_table( op.join( sourcedata, f'sub-{subject}/ses-{session}/func/sub-{subject}_ses-{session}_task-mapper_run-{run}_events.tsv' ))) behavior = pd.concat(behavior, keys=runs, names=['run']) behavior['subject'] = subject behavior = behavior.reset_index().set_index( ['subject', 'run', 'trial_type']) ims = [ op.join( sourcedata, f'derivatives/fmriprep/sub-{subject}/ses-{session}/func/sub-{subject}_ses-{session}_task-mapper_run-{run}_space-T1w_desc-preproc_bold.nii.gz' ) for run in runs ] fmriprep_confounds_include = [ 'global_signal', 'dvars', 'framewise_displacement', 'trans_x', 'trans_y', 'trans_z', 'rot_x', 'rot_y', 'rot_z', 'a_comp_cor_00', 'a_comp_cor_01', 'a_comp_cor_02', 'a_comp_cor_03', 'cosine00', 'cosine01', 'cosine02', 'non_steady_state_outlier00', 'non_steady_state_outlier01', 'non_steady_state_outlier02' ] fmriprep_confounds = [ op.join( sourcedata, f'derivatives/fmriprep/sub-{subject}/ses-{session}/func/sub-{subject}_ses-{session}_task-mapper_run-{run}_desc-confounds_timeseries.tsv' ) for run in runs ] fmriprep_confounds = [ pd.read_table(cf)[fmriprep_confounds_include] for cf in fmriprep_confounds ] retroicor_confounds = [ op.join( sourcedata, f'derivatives/physiotoolbox/sub-{subject}/ses-{session}/func/sub-{subject}_ses-{session}_task-mapper_run-{run}_desc-retroicor_timeseries.tsv' ) for run in runs ] retroicor_confounds = [ pd.read_table(cf, header=None, usecols=range(18)) for cf in retroicor_confounds ] confounds = [ pd.concat((rcf, fcf), axis=1) for rcf, fcf in zip(retroicor_confounds, fmriprep_confounds) ] confounds = [c.fillna(method='bfill') for c in confounds] model = FirstLevelModel(t_r=2.3, slice_time_ref=.5, signal_scaling=False, drift_model=None, smoothing_fwhm=0.0) responses = behavior.xs( 'response', 0, 'trial_type', drop_level=False).reset_index('trial_type')[['onset', 'trial_type']] responses['duration'] = 0.0 responses = responses[responses.onset > 0] stimulation = behavior.xs('stimulation', 0, 'trial_type', drop_level=False).reset_index('trial_type')[[ 'onset', 'duration', 'n_dots', 'trial_type' ]] stimulation_mod = stimulation.copy() stimulation_mod['modulation'] = np.log(stimulation_mod['n_dots']) stimulation_mod['modulation'] = (stimulation_mod['modulation'] - stimulation_mod['modulation'].mean(0) ) / stimulation_mod['modulation'].std() stimulation_mod['trial_type'] = 'stimulation*n_dots' targets = behavior.xs('targets', 0, 'trial_type') hazard_regressor = targets[~targets.hazard1.isnull()].copy() hazard_regressor['modulation'] = hazard_regressor['hazard1'] hazard_regressor['modulation'] = (hazard_regressor['modulation'] - hazard_regressor['modulation'].mean() ) / hazard_regressor['modulation'].std() hazard_regressor['trial_type'] = 'hazard1' hazard_regressor['duration'] = 0.0 hazard_regressor = hazard_regressor[[ 'trial_type', 'duration', 'modulation', 'onset' ]] events = pd.concat( (responses, stimulation, stimulation_mod, hazard_regressor)) events['modulation'].fillna(1.0, inplace=True) model.fit(ims, [r for _, r in events.groupby(['run'])], confounds) zmaps = {} results_dir = op.join(sourcedata, 'derivatives', 'glm', 'simple_mapper', f'sub-{subject}', f'ses-{session}') if not op.exists(results_dir): os.makedirs(results_dir) for key in ['response', 'stimulation', 'stimulation*n_dots', 'hazard1']: zmaps[key] = model.compute_contrast(key) zmaps[key].to_filename( op.join(results_dir, f'sub-{subject}_ses-{session}_zmap_{key}.nii.gz'))
add_reg_names=["pcc_seed"]) dmn_contrast = np.array([1] + [0] * (design_matrix.shape[1] - 1)) contrasts = {'seed_based_glm': dmn_contrast} ######################################################################### # Perform first level analysis # ---------------------------- # Setup and fit GLM. first_level_model = FirstLevelModel(t_r=t_r, slice_time_ref=slice_time_ref) first_level_model = first_level_model.fit(run_imgs=adhd_dataset.func[0], design_matrices=design_matrix) ######################################################################### # Estimate the contrast. print('Contrast seed_based_glm computed.') z_map = first_level_model.compute_contrast(contrasts['seed_based_glm'], output_type='z_score') # Saving snapshots of the contrasts filename = 'dmn_z_map.png' display = plotting.plot_stat_map(z_map, threshold=3.0, title='Seed based GLM', cut_coords=pcc_coords) display.add_markers(marker_coords=[pcc_coords], marker_color='g', marker_size=300) display.savefig(filename) print("Save z-map in '{0}'.".format(filename)) ########################################################################### # Generating a report
def run_subject(sub, out_dir): """ Runs pattern estimation for a single subject. """ print(f"INFO: Processing {sub}") # Define in- and output directories bids_dir = op.join(f'../{sub}') fprep_dir = op.join(f'../derivatives/fmriprep/{sub}') out_dir = op.join(out_dir, sub) funcs = sorted( glob(fprep_dir + '/ses-?/func/*task-face*space-MNI*desc-preproc_bold.nii.gz')) for func in funcs: t_r = nib.load(func).header['pixdim'][4] conf = func.split('_space')[0] + '_desc-confounds_timeseries.tsv' mask = func.replace('preproc_bold', 'brain_mask') events = bids_dir + func.split(fprep_dir)[1].split( '_space')[0] + '_events.tsv' flm = FirstLevelModel(t_r=t_r, slice_time_ref=0.5, hrf_model='glover', drift_model='cosine', high_pass=0.01, mask_img=mask, smoothing_fwhm=None, noise_model='ols', n_jobs=1, minimize_memory=False) # Select confounds conf = pd.read_csv(conf, sep='\t').loc[:, [ 'trans_x', 'trans_y', 'trans_z', 'rot_x', 'rot_y', 'rot_z', 'csf', 'white_matter' ]] # Redefine output dir this_out_dir = op.join(out_dir, func.split(fprep_dir)[1].split('/')[1]) for d in ['patterns', 'model', 'figures']: if not op.isdir(op.join(this_out_dir, d)): os.makedirs(op.join(this_out_dir, d), exist_ok=True) # Fit model flm.fit(run_imgs=func, events=events, confounds=conf) # Save some stuff! f_base = op.basename(func).split('preproc')[0] rsq_out = op.join(this_out_dir, 'model', f_base + 'model_r2.nii.gz') flm.r_square[0].to_filename(rsq_out) dm = flm.design_matrices_[0] dm_out = op.join(this_out_dir, 'model', f_base + 'design_matrix.tsv') dm.to_csv(dm_out, sep='\t', index=False) dmfig_out = op.join(this_out_dir, 'figures', f_base + 'design_matrix.png') plot_design_matrix(dm, output_file=dmfig_out) dmcorrfig_out = op.join(this_out_dir, 'figures', f_base + 'design_corr.png') labels = dm.columns.tolist()[:-1] ax = plot_design_matrix(dm.drop('constant', axis=1).corr()) ax.set_yticks(range(len(labels))) ax.set_yticklabels(labels) plt.savefig(dmcorrfig_out) plt.close() resids_out = op.join(this_out_dir, 'model', f_base + 'model_residuals.nii.gz') flm.residuals[0].to_filename(resids_out) trials = [l for l in labels if 'STIM' in l] b, vb = [], [] for trial in trials: dat = flm.compute_contrast(trial, stat_type='t', output_type='all') b.append(dat['effect_size']) vb.append(dat['effect_variance']) beta_out = op.join(this_out_dir, 'patterns', f_base + 'trial_beta.nii.gz') image.concat_imgs(b).to_filename(beta_out) varbeta_out = op.join(this_out_dir, 'patterns', f_base + 'trial_varbeta.nii.gz') image.concat_imgs(vb).to_filename(varbeta_out)
def sub_tcontrasts3(session:Union[dict,Bunch]=None, sub_id:str=None, tr:float=None, frame_times:list=None, hrf_model:str=None, events:pd.DataFrame=None, fmri_img:Nifti1Image=None, sub_outdir:Union[str,os.PathLike]=None): """ Create beta values maps using nilearn first-level model. The beta values correspond to the following contrasts between conditions: correctsource (cs), wrongsource (ws), cs_minus_ws, cs_minus_miss, ws_minus_miss, cs_minus_ctl, ws_minus_ctl hit, miss, hit_minus_miss, hit_minus_ctl and miss_minus_ctl Parameters: ---------- sub_id: string (subject's dccsub_id) tr: float (length of time to repetition, in seconds) frames_times: list of float (onsets of fMRI frames, in seconds) hrf_model: string (type of HRF model) confounds: pandas dataframe (motion and other noise regressors) all_events: string (task information: trials' onset time, duration and label) fmrsub_idir: string (path to directory with fMRI data) outdir: string (path to subject's image output directory) Return: ---------- None (beta maps are exported in sub_outdir) """ if isinstance(session, dict): session = Bunch(**session) # Model 1: encoding vs control conditions events3 = session.events.copy(deep = True) cols = ['onset', 'duration', 'ctl_miss_ws_cs'] events3 = events3[cols] events3.rename(columns={'ctl_miss_ws_cs':'trial_type'}, inplace=True) # create the model - Should data be standardized? model3 = FirstLevelModel(**session.glm_defs) # create the design matrices design3 = make_first_level_design_matrix(events=events3, **session.design_defs) # fit model with design matrix model3 = model3.fit(session.cleaned_fmri, design_matrices = design3) # Condition order: control, correct source, missed, wrong source (alphabetical) #contrast 3.1: wrong source ws_vec = np.repeat(0, design3.shape[1]) ws_vec[3] = 1 b31_map = model3.compute_contrast(ws_vec, output_type='effect_size') #"effect_size" for betas b31_name = f'betas_{session.sub_id}_ws.nii' #contrast 3.2: correct source cs_vec = np.repeat(0, design3.shape[1]) cs_vec[1] = 1 b32_map = model3.compute_contrast(cs_vec, output_type='effect_size') #"effect_size" for betas b32_name = f'betas_{session.sub_id}_cs.nii' #contrast 3.3: correct source minus wrong source cs_minus_ws_vec = np.repeat(0, design3.shape[1]) cs_minus_ws_vec[1] = 1 cs_minus_ws_vec[3] = -1 b33_map = model3.compute_contrast(cs_minus_ws_vec, output_type='effect_size') #"effect_size" for betas b33_name = f'betas_{session.sub_id}_cs_minus_ws.nii' #contrast 3.4: correct source minus miss cs_minus_miss_vec = np.repeat(0, design3.shape[1]) cs_minus_miss_vec[1] = 1 cs_minus_miss_vec[2] = -1 b34_map = model3.compute_contrast(cs_minus_miss_vec, output_type='effect_size') #"effect_size" for betas b34_name = f'betas_{session.sub_id}_cs_minus_miss.nii' #contrast 3.5: wrong source minus miss ws_minus_miss_vec = np.repeat(0, design3.shape[1]) ws_minus_miss_vec[3] = 1 ws_minus_miss_vec[2] = -1 b35_map = model3.compute_contrast(ws_minus_miss_vec, output_type='effect_size') #"effect_size" for betas b35_name = f'betas_{session.sub_id}_ws_minus_miss.nii' #contrast 3.6: correct source minus control cs_minus_ctl_vec = np.repeat(0, design3.shape[1]) cs_minus_ctl_vec[1] = 1 cs_minus_ctl_vec[0] = -1 b36_map = model3.compute_contrast(cs_minus_ctl_vec, output_type='effect_size') #"effect_size" for betas b36_name = f'betas_{session.sub_id}_cs_minus_ctl.nii' #contrast 3.7: wrong source minus control ws_minus_ctl_vec = np.repeat(0, design3.shape[1]) ws_minus_ctl_vec[3] = 1 ws_minus_ctl_vec[0] = -1 b37_map = model3.compute_contrast(ws_minus_ctl_vec, output_type='effect_size') #"effect_size" for betas b37_name = f'betas_{session.sub_id}_ws_minus_ctl.nii' contrasts = ((b31_map, b31_name), (b32_map, b32_name), (b33_map, b33_name), (b34_map, b34_name), (b35_map, b35_name), (b36_map, b36_name), (b37_map, b37_name)) if sub_outdir is not None: savedir = os.path.join(sub_outdir, session.sub_id, session.ses_id) os.makedirs(savedir, exist_ok=True) [nibabel.save(*contrast) for contrast in contrasts] return contrasts
######################################################################### # Take a look at the contrasts. plot_contrast_matrix(contrasts['left-right'], design_matrix) ######################################################################### # Take a breath. # # We can now proceed by estimating the contrasts and displaying them. import matplotlib.pyplot as plt from nilearn.plotting import plot_stat_map fig = plt.figure(figsize=(11, 3)) for index, (contrast_id, contrast_val) in enumerate(contrasts.items()): ax = plt.subplot(1, len(contrasts), 1 + index) z_map = first_level_model.compute_contrast(contrast_val, output_type='z_score') plot_stat_map(z_map, display_mode='z', threshold=3.0, title=contrast_id, axes=ax, cut_coords=1) plt.show() ######################################################################### # The result is acceptable. Note that we're asking a lot of questions # to a small dataset, yet with a relatively large number of experimental # conditions. #
lsa_glm = FirstLevelModel(**glm_parameters) lsa_glm.fit(fmri_file, lsa_events_df) fig, ax = plt.subplots(figsize=(10, 10)) plotting.plot_design_matrix(lsa_glm.design_matrices_[0], ax=ax) fig.show() ############################################################################## # Aggregate beta maps from the LSA model based on condition # ````````````````````````````````````````````````````````` # Collect the parameter estimate maps lsa_beta_maps = {cond: [] for cond in events_df['trial_type'].unique()} trialwise_conditions = lsa_events_df['trial_type'].unique() for condition in trialwise_conditions: beta_map = lsa_glm.compute_contrast(condition, output_type='effect_size') # Drop the trial number from the condition name to get the original name condition_name = condition.split('__')[0] lsa_beta_maps[condition_name].append(beta_map) # We can concatenate the lists of 3D maps into a single 4D beta series for # each condition, if we want lsa_beta_maps = { name: image.concat_imgs(maps) for name, maps in lsa_beta_maps.items() } ############################################################################## # Define the LSS models # --------------------- # We will now create a separate LSS model for each trial of interest.
contrast_matrix = np.eye(len(names)) for i in range(len(names)): contrasts[names[i]] = contrast_matrix[i] # more interesting contrasts""" contrasts = {'active-rest': contrasts['active'] - contrasts['rest']} # fit GLM print('\r\nFitting a GLM (this takes time) ..') fmri_glm = FirstLevelModel(noise_model='ar1', standardize=False, t_r=tr).fit( [nibabel.concat_images(subject_data.func[0])], design_matrices=design_matrix) # save computed mask mask_path = os.path.join(subject_data.output_dir, "mask.nii.gz") print("Saving mask image %s" % mask_path) nibabel.save(fmri_glm.masker_.mask_img_, mask_path) # compute bg unto which activation will be projected anat_img = nibabel.load(subject_data.anat) print("Computing contrasts ..") z_maps = {} effects_maps = {} for contrast_id, contrast_val in contrasts.items(): print("\tcontrast id: %s" % contrast_id) z_map = fmri_glm.compute_contrast(contrasts[contrast_id], output_type='z_score') z_maps[contrast_id] = z_map
def sub_tcontrasts1(session:Union[dict,Bunch]=None, sub_id:str=None, tr:float=None, frame_times:list=None, hrf_model:str=None, events:pd.DataFrame=None, fmri_img:Nifti1Image=None, sub_outdir:Union[str,os.PathLike]=None): """ Create beta values maps using nilearn first-level model. The beta values correspond to the following contrasts between conditions: control, encoding, and encoding_minus_control Parameters: ---------- sub_id: string (subject's dccsub_id) tr: float (length of time to repetition, in seconds) frames_times: list of float (onsets of fMRI frames, in seconds) hrf_model: string (type of HRF model) confounds: pandas dataframe (motion and other noise regressors) all_events: string (task information: trials' onset time, duration and label) fmrsub_idir: string (path to directory with fMRI data) outdir: string (path to subject's image output directory) Return: ---------- None (beta maps are exported in sub_outdir) """ if isinstance(session, dict): session = Bunch(**session) # Model 1: encoding vs control conditions events1 = session.events.copy(deep = True) cols = ['onset', 'duration', 'trial_type'] events1 = events1[cols] # create the model - Should data be standardized? model1 = FirstLevelModel(**session.glm_defs) # create the design matrices design1 = make_first_level_design_matrix(events=events1, **session.design_defs) # fit model with design matrix model1 = model1.fit(session.cleaned_fmri, design_matrices = design1) # Condition order: control, encoding (alphabetical) # contrast 1.1: control condition ctl_vec = np.repeat(0, design1.shape[1]) ctl_vec[0] = 1 b11_map = model1.compute_contrast(ctl_vec, output_type='effect_size') #"effect_size" for betas b11_name = f'betas_{session.sub_id}_ctl.nii' #contrast 1.2: encoding condition enc_vec = np.repeat(0, design1.shape[1]) enc_vec[1] = 1 b12_map = model1.compute_contrast(enc_vec, output_type='effect_size') #"effect_size" for betas b12_name = f'betas_{session.sub_id}_enc.nii' #contrast 1.3: encoding minus control encMinCtl_vec = np.repeat(0, design1.shape[1]) encMinCtl_vec[1] = 1 encMinCtl_vec[0] = -1 b13_map = model1.compute_contrast(encMinCtl_vec, output_type='effect_size') #"effect_size" for betas b13_name = f'betas_{session.sub_id}_enc_minus_ctl.nii' contrasts = ((b11_map, b11_name), (b12_map, b12_name), (b13_map, b13_name)) if sub_outdir is not None: savedir = os.path.join(sub_outdir, session.sub_id, session.ses_id) os.makedirs(savedir, exist_ok=True) [nibabel.save(*contrast) for contrast in contrasts] return contrasts
from nilearn.glm.first_level import FirstLevelModel fmri_glm = FirstLevelModel(t_r=7, drift_model='cosine', signal_scaling=False, mask_img=mask, minimize_memory=False) fmri_glm = fmri_glm.fit(fmri_img, events) ######################################################################### # Calculate and plot contrast # --------------------------- from nilearn import plotting z_map = fmri_glm.compute_contrast('active - rest') plotting.plot_stat_map(z_map, bg_img=mean_img, threshold=3.1) ######################################################################### # Extract the largest clusters # ---------------------------- from nilearn.reporting import get_clusters_table from nilearn.maskers import NiftiSpheresMasker table = get_clusters_table(z_map, stat_threshold=3.1, cluster_threshold=20).set_index('Cluster ID', drop=True) table.head() # get the 6 largest clusters' max x, y, and z coordinates
memory='nilearn_cache') ############################################################################## # Run the glm on data from each session # ------------------------------------- for session in unique_sessions: # grab the fmri data for that particular session fmri_session = index_img(func_filename, sessions == session) # fit the glm glm.fit(fmri_session, events=events[session]) # set up contrasts: one per condition conditions = events[session].trial_type.unique() for condition_ in conditions: z_maps.append(glm.compute_contrast(condition_)) condition_idx.append(condition_) session_idx.append(session) ######################################################################### # Generating a report # ------------------- # Since we have already computed the FirstLevelModel # and have the contrast, we can quickly create a summary report. from nilearn.image import mean_img from nilearn.reporting import make_glm_report mean_img_ = mean_img(func_filename) report = make_glm_report(glm, contrasts=conditions, bg_img=mean_img_,
from nilearn.glm.first_level import FirstLevelModel print('Fitting a GLM') fmri_glm = FirstLevelModel() fmri_glm = fmri_glm.fit(fmri_img, design_matrices=design_matrices) ######################################################################### # Now we can compute contrast-related statistical maps (in z-scale), and plot # them. print('Computing contrasts') from nilearn import plotting # Iterate on contrasts for contrast_id, contrast_val in contrasts.items(): print("\tcontrast id: %s" % contrast_id) # compute the contrasts z_map = fmri_glm.compute_contrast( contrast_val, output_type='z_score') # plot the contrasts as soon as they're generated # the display is overlaid on the mean fMRI image # a threshold of 3.0 is used, more sophisticated choices are possible plotting.plot_stat_map( z_map, bg_img=mean_image, threshold=3.0, display_mode='z', cut_coords=3, black_bg=True, title=contrast_id) plotting.show() ######################################################################### # Based on the resulting maps we observe that the analysis results in # wide activity for the 'effects of interest' contrast, showing the # implications of large portions of the visual cortex in the # conditions. By contrast, the differential effect between "faces" and # "scrambled" involves sparser, more anterior and lateral regions. It # also displays some responses in the frontal lobe.
def sub_tcontrasts2(session:Union[dict,Bunch]=None, sub_id:str=None, tr:float=None, frame_times:list=None, hrf_model:str=None, events:pd.DataFrame=None, fmri_img:Nifti1Image=None, sub_outdir:Union[str,os.PathLike]=None): """ Create beta values maps using nilearn first-level model. The beta values correspond to the following contrasts between conditions: hit, miss, hit_minus_miss, hit_minus_ctl and miss_minus_ctl Parameters: ---------- sub_id: string (subject's dccsub_id) tr: float (length of time to repetition, in seconds) frames_times: list of float (onsets of fMRI frames, in seconds) hrf_model: string (type of HRF model) confounds: pandas dataframe (motion and other noise regressors) all_events: string (task information: trials' onset time, duration and label) fmrsub_idir: string (path to directory with fMRI data) outdir: string (path to subject's image output directory) Return: ---------- None (beta maps are exported in sub_outdir) """ if isinstance(session, dict): session = Bunch(**session) # Model 1: encoding vs control conditions events2 = session.events.copy(deep = True) cols = ['onset', 'duration', 'recognition_performance'] events2 = events2[cols] events2.rename(columns={'recognition_performance':'trial_type'}, inplace=True) # create the model - Should data be standardized? model2 = FirstLevelModel(**session.glm_defs) # create the design matrices design2 = make_first_level_design_matrix(events=events2,**session.design_defs) # fit model with design matrix model2 = model2.fit(session.cleaned_fmri, design_matrices = design2) # Condition order: control, hit, missed (alphabetical) #contrast 2.1: miss miss_vec = np.repeat(0, design2.shape[1]) miss_vec[2] = 1 b21_map = model2.compute_contrast(miss_vec, output_type='effect_size') #"effect_size" for betas b21_name = f'betas_{session.sub_id}_miss.nii' # b21_name = os.path.join(sub_outdir, 'betas_sub'+str(sub_id)+'_miss.nii') # nibabel.save(b21_map, b21_name) #contrast 2.2: hit hit_vec = np.repeat(0, design2.shape[1]) hit_vec[1] = 1 b22_map = model2.compute_contrast(hit_vec, output_type='effect_size') #"effect_size" for betas b22_name = f'betas_{session.sub_id}_hit.nii' #contrast 2.3: hit minus miss hit_min_miss_vec = np.repeat(0, design2.shape[1]) hit_min_miss_vec[1] = 1 hit_min_miss_vec[2] = -1 b23_map = model2.compute_contrast(hit_min_miss_vec, output_type='effect_size') #"effect_size" for betas b23_name = f'betas_{session.sub_id}_hit_minus_miss.nii' #contrast 2.4: hit minus control hit_min_ctl_vec = np.repeat(0, design2.shape[1]) hit_min_ctl_vec[1] = 1 hit_min_ctl_vec[0] = -1 b24_map = model2.compute_contrast(hit_min_ctl_vec, output_type='effect_size') #"effect_size" for betas b24_name = f'betas_{session.sub_id}_hit_minus_ctl.nii' #contrast 2.5: miss minus control miss_min_ctl_vec = np.repeat(0, design2.shape[1]) miss_min_ctl_vec[2] = 1 miss_min_ctl_vec[0] = -1 b25_map = model2.compute_contrast(miss_min_ctl_vec, output_type='effect_size') #"effect_size" for betas b25_name = f'betas_{session.sub_id}_miss_minus_ctl.nii' contrasts = ((b21_map, b21_name), (b22_map, b22_name), (b23_map, b23_name), (b24_map, b24_name), (b25_map, b25_name)) if sub_outdir is not None: savedir = os.path.join(sub_outdir, session.sub_id, session.ses_id) os.makedirs(savedir, exist_ok=True) [nibabel.save(*contrast) for contrast in contrasts] return contrasts