def _infer_effect_maps(second_level_input, contrast_def): """Deals with the different possibilities of second_level_input""" # Build the design matrix X and list of imgs Y for GLM fit if isinstance(second_level_input, pd.DataFrame): # If a Dataframe was given, we expect contrast_def to be in map_name def _is_contrast_def(x): return x['map_name'] == contrast_def is_con = second_level_input.apply(_is_contrast_def, axis=1) effect_maps = second_level_input[is_con]['effects_map_path'].tolist() elif isinstance(second_level_input[0], FirstLevelModel): # Get the first level model maps effect_maps = [] for model in second_level_input: effect_map = model.compute_contrast(contrast_def, output_type='effect_size') effect_maps.append(effect_map) else: effect_maps = second_level_input # check niimgs for niimg in effect_maps: check_niimg(niimg, ensure_ndim=3) return effect_maps
def test_fetch_atlas_waxholm_rat_2014(): datadir = os.path.join(tst.tmpdir, 'waxholm_rat_2014') os.mkdir(datadir) # Create dummy json labels file json_filename = os.path.join(datadir, 'WHS_SD_rat_labels.json') with open(json_filename, 'w') as json_content: json.dump({"216": "Spinal cord"}, json_content) # default resolution bunch = atlas.fetch_atlas_waxholm_rat_2014( data_dir=tst.tmpdir, verbose=0) assert_equal( bunch['t2star'], os.path.join(datadir, 'WHS_SD_rat_T2star_v1_01_downsample3.nii.gz')) assert_equal( bunch['maps'], os.path.join(datadir, 'WHS_SD_rat_atlas_v1_01_downsample3.nii.gz')) assert_equal(len(tst.mock_url_request.urls), 2) assert_not_equal(bunch.description, '') # Downsampled 2 times bunch = atlas.fetch_atlas_waxholm_rat_2014( data_dir=tst.tmpdir, verbose=0, downsample='78') assert_equal( bunch['t2star'], os.path.join(datadir, 'WHS_SD_rat_T2star_v1_01_downsample2.nii.gz')) assert_equal( bunch['maps'], os.path.join(datadir, 'WHS_SD_rat_atlas_v1_01_downsample2.nii.gz')) assert_equal(len(tst.mock_url_request.urls), 4) # test resampling anat_file = os.path.join(os.path.dirname(testing_data.__file__), 'anat.nii.gz') anat_img = check_niimg(anat_file) anat_img.to_filename(bunch['t2star']) anat_img = check_niimg(anat_file, dtype=int) anat_img.to_filename(bunch['maps']) bunch = atlas.fetch_atlas_waxholm_rat_2014( data_dir=tst.tmpdir, verbose=0, downsample='200') assert_equal(len(tst.mock_url_request.urls), 4) assert_equal( bunch['t2star'], os.path.join(datadir, 'WHS_SD_rat_T2star_v1_01_200um.nii.gz')) assert_equal( bunch['maps'], os.path.join(datadir, 'WHS_SD_rat_atlas_v1_01_200um.nii.gz')) assert_array_almost_equal(nibabel.load(bunch['t2star']).header.get_zooms(), (.2, .2, .2)) assert_array_almost_equal(nibabel.load(bunch['maps']).header.get_zooms(), (.2, .2, .2))
def test_fetch_atlas_dorr_2008(): datadir = os.path.join(tst.tmpdir, 'dorr_2008') os.mkdir(datadir) dummy = open(os.path.join(datadir, 'c57_brain_atlas_labels.csv'), 'w') dummy.write("\n1,amygdala,51,151\n27,fourth ventricle,118,118") dummy.close() # Default resolution bunch = atlas.fetch_atlas_dorr_2008(data_dir=tst.tmpdir, verbose=0) assert_equal(len(tst.mock_url_request.urls), 2) assert_equal(bunch['t2'], os.path.join(datadir, 'Dorr_2008_average.nii.gz')) assert_equal(bunch['maps'], os.path.join(datadir, 'Dorr_2008_labels.nii.gz')) # test resampling anat_file = os.path.join(os.path.dirname(testing_data.__file__), 'anat.nii.gz') anat_img = check_niimg(anat_file) anat_img.to_filename(bunch['t2']) anat_img = check_niimg(anat_file, dtype=int) anat_img.to_filename(bunch['maps']) bunch = atlas.fetch_atlas_dorr_2008(data_dir=tst.tmpdir, verbose=0, downsample='100') assert_equal(bunch['t2'], os.path.join(datadir, 'Dorr_2008_average_100um.nii.gz')) assert_equal(bunch['maps'], os.path.join(datadir, 'Dorr_2008_labels_100um.nii.gz')) assert_array_almost_equal( nibabel.load(bunch['t2']).header.get_zooms(), (.1, .1, .1)) assert_array_almost_equal( nibabel.load(bunch['maps']).header.get_zooms(), (.1, .1, .1)) assert_equal(nibabel.load(bunch['maps']).get_data().dtype, np.dtype(int)) assert_equal(len(tst.mock_url_request.urls), 2) assert_equal(len(bunch['names']), 3) assert_equal(len(bunch['labels']), 3) # test with 'minc' format bunch = atlas.fetch_atlas_dorr_2008(data_dir=tst.tmpdir, verbose=0, image_format='minc') assert_equal(len(tst.mock_url_request.urls), 4) assert_equal(bunch['t2'], os.path.join(datadir, 'male-female-mouse-atlas.mnc')) assert_equal(bunch['maps'], os.path.join(datadir, 'c57_fixed_labels_resized.mnc')) assert_equal(len(bunch['names']), 3) assert_equal(len(bunch['labels']), 3) assert_not_equal(bunch.description, '')
def dices(labels_file1, labels_file2): data1 = check_niimg(labels_file1).get_data().astype(int) data2 = check_niimg(labels_file2).get_data().astype(int) labels1 = np.unique(data1).tolist() labels2 = np.unique(data2).tolist() dice_coefs = [] labels = np.unique(labels1 + labels2).tolist() labels.remove(0) for label in labels: if label in labels1 and label in labels2: mask_data1 = data1 == label mask_data2 = data2 == label dice_coefs.append(mask_arrays_to_dice(mask_data1, mask_data2)) else: dice_coefs.append(0.) return labels, dice_coefs
def average_images(files): all_data = [] for f in files: data = check_niimg(f).get_data() all_data.append(data) std = np.std(all_data, axis=0) avg = np.mean(all_data, axis=0) # I don't think this is right t_scores = avg / ((1e-10 + std) / np.sqrt(float(len(files)))) return avg, t_scores
def run_analysis(image_file, event_file, output_file, mask_file=None): # Load functional data img = check_niimg(image_file, ensure_ndim=4) img_data = img.get_data() print('Data matrix shape: ' + str(img_data.shape)) # Apply mask if provided if mask_file: mask = check_niimg(mask_file, ensure_ndim=3).get_data().astype(bool) img_data = img_data[mask] print('Masked data matrix shape: ' + str(img_data.shape)) else: img_data = np.reshape(img_data, (245245, img_data.shape[3])) # Get design matrix from nistats dm = get_design_matrix(event_file, img_data.shape[1]) print('Design matrix shape: ' + str(dm.shape)) # Normalize design matrix (data normalized in preprocessing) X = zscore(dm.as_matrix().T).T if PLOT: plt.plot(X) plt.show() # Fit and compute R squareds weights, r_squared = compute_rsquared(X, img_data.T) print('R squared matrix shape: ' + str(r_squared.shape)) # Output results if mask_file: output = np.zeros((65, 77, 49)) output[mask] = r_squared else: output = np.reshape(r_squared, (65, 77, 49)) output[output == 1.0] = 0.0 r_squared_img = Nifti1Image(output, affine=img.affine) r_squared_img.to_filename(output_file)
def compute_mask_contour(mask_file, write_dir=None, out_file=None): mask_img = check_niimg(mask_file) vertices, _ = measure.marching_cubes(mask_img.get_data(), 0) #marching_cubes_lewiner vertices_minus = np.floor(vertices).astype(int) vertices_plus = np.ceil(vertices).astype(int) contour_data = np.zeros(mask_img.shape) contour_data[vertices_minus.T[0], vertices_minus.T[1], vertices_minus.T[2]] = 1 contour_data[vertices_plus.T[0], vertices_plus.T[1], vertices_plus.T[2]] = 1 contour_img = image.new_img_like(mask_img, contour_data) if write_dir is None: write_dir = os.getcwd() if out_file is None: out_file = fname_presuffix(mask_file, suffix='_countour', newpath=write_dir) contour_img.to_filename(out_file) return out_file
def run_preprocessing(image_file, output_file): # Load and crop img = check_niimg(image_file, ensure_ndim=4) img_data = img.get_data() img_data = img_data[:, :, :, 17:] # Initial scanner setup img_data = img_data[:, :, :, 27:] # Starting cartoon img_data = img_data[:, :, :, :975] print('Data matrix shape: ' + str(img_data.shape)) img_data = np.reshape(img_data, (245245, img_data.shape[3])) # Normalize data Y = zscore(img_data).T # Detrend data Y = detrend_data(Y) print('Detrended data matrix: ' + str(Y.shape)) Y = np.reshape(Y.T, (65, 77, 49, 975)) r_squared_img = Nifti1Image(Y, affine=img.affine) r_squared_img.to_filename(output_file)
'c{0}anat_n0_clear_hd.nii'.format(n)) # Try after N3 for n in range(1, 4) ] rough_mask_img = image.math_img('np.max(imgs, axis=-1) > .01', imgs=spm_tissues_files) spm_labels_img = image.math_img('img * (np.argmax(imgs, axis=-1) + 1)', img=rough_mask_img, imgs=spm_tissues_files) spm_gm_wm_img = image.math_img('np.logical_or(img==1, img==2)', img=spm_labels_img) brain_mask_img = masking.intersect_masks( [sammba_brain_mask_file, spm_gm_wm_img], threshold=0) brain_mask_file = os.path.join(sammba_dir, 'anat_n0_precise_brain_mask.nii.gz') brain_contour_file = compute_mask_contour(brain_mask_file) check_niimg(brain_contour_file).to_filename( os.path.join(spm_dir, 'anat_n0_precise_brain_mask_contour.nii')) nwarp_apply = afni.NwarpApply().run transforms = [ os.path.join(sammba_dir, 'anat_n0_unifized_affine_general_warped_WARP.nii.gz'), os.path.join(sammba_dir, 'anat_n0_unifized_masked_aff.aff12.1D') ] warp = "'" + ' '.join(transforms) + "'" sammba_registered_contour_file = fname_presuffix(brain_contour_file, suffix='_warped', newpath=sammba_dir) out_warp_apply = nwarp_apply(in_file=brain_contour_file, master=template_brain_mask_file, warp=warp, interp='nearestneighbor',
def fetch_masks_dorr_2008(image_format='nifti', downsample='30', data_dir=None, resume=True, verbose=1): """Downloads DORR 2008 atlas first, then uses its labels to produce tissue masks. Parameters ---------- image_format : one of {'nifti', 'minc'}, optional Format to download downsample : one of {'30', '100'}, optional Downsampling resolution in microns. data_dir : str, optional Path of the data directory. Use to forec data storage in a non- standard location. Default: None (meaning: default) resume : bool, optional whether to resumed download of a partly-downloaded file. verbose : int, optional verbosity level (0 means no message). Returns ------- mask_imgs: sklearn.datasets.base.Bunch dictionary-like object, contains: - 'brain' : nibabel.nifti1.Nifti1Image brain mask image. - 'gm' : nibabel.nifti1.Nifti1Image grey matter mask image. - 'cc' : nibabel.nifti1.Nifti1Image eroded corpus callosum image. - 'ventricles' : nibabel.nifti1.Nifti1Image eroded ventricles mask image. Notes ----- This function relies on DORR 2008 atlas where we particularly pick ventricles and corpus callosum regions. Then, do a bit post processing such as binary closing operation to more compact brain and grey matter mask image and binary erosion to non-contaminated corpus callosum and ventricles mask images. Note: It is advised to check the mask images with your own data processing. See Also -------- sammba.data_fetchers.fetch_atlas_dorr_2008: for details regarding the DORR 2008 atlas. """ # Fetching DORR 2008 atlas dorr = fetch_atlas_dorr_2008(image_format=image_format, downsample=downsample, data_dir=data_dir, resume=resume, verbose=verbose) maps, names, labels = dorr['maps'], dorr['names'], dorr['labels'] atlas_img = check_niimg(maps) atlas_data = niimg._safe_get_data(atlas_img).astype(int) brain_mask = (atlas_data > 0) brain_mask = ndimage.binary_closing(brain_mask, iterations=2) brain_mask_img = image.new_img_like(atlas_img, brain_mask) corpus_callosum_labels = labels[np.in1d( names.astype(str), ['R corpus callosum', 'L corpus callosum'])] print( np.in1d(names.astype(str), ['R corpus callosum', 'L corpus callosum'])) print(corpus_callosum_labels) print(np.unique(atlas_data)) corpus_callosum_mask = np.max( [atlas_data == value for value in corpus_callosum_labels], axis=0) eroded_corpus_callosum_mask = ndimage.binary_erosion(corpus_callosum_mask, iterations=2) corpus_callosum_mask_img = image.new_img_like(atlas_img, eroded_corpus_callosum_mask) ventricles_names = [ 'R lateral ventricle', 'L lateral ventricle', 'third ventricle', 'fourth ventricle' ] ventricles_labels = labels[np.in1d(names.astype(str), ventricles_names)] ventricles_mask = np.max( [atlas_data == value for value in ventricles_labels], axis=0) eroded_ventricles_mask = ndimage.binary_erosion(ventricles_mask, iterations=2) ventricles_mask_img = image.new_img_like(atlas_img, eroded_ventricles_mask) gm_mask = (atlas_data > 0) gm_mask[ventricles_mask] = 0 gm_mask[corpus_callosum_mask] = 0 gm_mask = ndimage.binary_closing(gm_mask, iterations=2) gm_mask_img = image.new_img_like(atlas_img, gm_mask) mask_imgs = { 'brain': brain_mask_img, 'gm': gm_mask_img, 'cc': corpus_callosum_mask_img, 'ventricles': ventricles_mask_img } return Bunch(**mask_imgs)
''' Averages Nifti images. ''' import sys import numpy as np from nibabel import Nifti1Image from nilearn._utils.niimg_conversions import check_niimg def average_images(files): all_data = [] for f in files: data = check_niimg(f).get_data() all_data.append(data) std = np.std(all_data, axis=0) avg = np.mean(all_data, axis=0) # I don't think this is right t_scores = avg / ((1e-10 + std) / np.sqrt(float(len(files)))) return avg, t_scores if __name__ == '__main__': output_file = sys.argv[1] image_files = sys.argv[2:] avg_data, t_scores = average_images(image_files) affine = check_niimg(image_files[0]).affine avg_nifti = Nifti1Image(avg_data, affine=affine) avg_nifti.to_filename(output_file)
def fit(self, run_imgs, events=None, confounds=None, sample_masks=None, design_matrices=None, bins=100): """Fit the GLM For each run: 1. create design matrix X 2. do a masker job: fMRI_data -> Y 3. fit regression to (Y, X) Parameters ---------- run_imgs : Niimg-like object or list of Niimg-like objects, Data on which the GLM will be fitted. If this is a list, the affine is considered the same for all. events : pandas Dataframe or string or list of pandas DataFrames \ or strings, optional fMRI events used to build design matrices. One events object expected per run_img. Ignored in case designs is not None. If string, then a path to a csv file is expected. confounds : pandas Dataframe, numpy array or string or list of pandas DataFrames, numpy arrays or strings, optional Each column in a DataFrame corresponds to a confound variable to be included in the regression model of the respective run_img. The number of rows must match the number of volumes in the respective run_img. Ignored in case designs is not None. If string, then a path to a csv file is expected. sample_masks : array_like, or list of array_like, optional shape of array: (number of scans - number of volumes removed, ) Indices of retained volumes. Masks the niimgs along time/fourth dimension to perform scrubbing (remove volumes with high motion) and/or remove non-steady-state volumes. Default=None. .. versionadded:: 0.9.2.dev design_matrices : pandas DataFrame or \ list of pandas DataFrames, optional Design matrices that will be used to fit the GLM. If given it takes precedence over events and confounds. bins : int, optional Maximum number of discrete bins for the AR coef histogram. If an autoregressive model with order greater than one is specified then adaptive quantification is performed and the coefficients will be clustered via K-means with `bins` number of clusters. Default=100. """ # Initialize masker_ to None such that attribute exists self.masker_ = None # Raise a warning if both design_matrices and confounds are provided if design_matrices is not None and \ (confounds is not None or events is not None): warn( 'If design matrices are supplied, ' 'confounds and events will be ignored.' ) # Local import to prevent circular imports from nilearn.maskers import NiftiMasker # noqa # Check arguments # Check imgs type if events is not None: _check_events_file_uses_tab_separators(events_files=events) if not isinstance(run_imgs, (list, tuple)): run_imgs = [run_imgs] if design_matrices is None: if events is None: raise ValueError('events or design matrices must be provided') if self.t_r is None: raise ValueError('t_r not given to FirstLevelModel object' ' to compute design from events') else: design_matrices = _check_run_tables(run_imgs, design_matrices, 'design_matrices') # Check that number of events and confound files match number of runs # Also check that events and confound files can be loaded as DataFrame if events is not None: events = _check_run_tables(run_imgs, events, 'events') if confounds is not None: confounds = _check_run_tables(run_imgs, confounds, 'confounds') if sample_masks is not None: sample_masks = _check_run_sample_masks(len(run_imgs), sample_masks) # Learn the mask if self.mask_img is False: # We create a dummy mask to preserve functionality of api ref_img = check_niimg(run_imgs[0]) self.mask_img = Nifti1Image(np.ones(ref_img.shape[:3]), ref_img.affine) if not isinstance(self.mask_img, NiftiMasker): self.masker_ = NiftiMasker(mask_img=self.mask_img, smoothing_fwhm=self.smoothing_fwhm, target_affine=self.target_affine, standardize=self.standardize, mask_strategy='epi', t_r=self.t_r, memory=self.memory, verbose=max(0, self.verbose - 2), target_shape=self.target_shape, memory_level=self.memory_level ) self.masker_.fit(run_imgs[0]) else: # Make sure masker has been fitted otherwise no attribute mask_img_ self.mask_img._check_fitted() if self.mask_img.mask_img_ is None and self.masker_ is None: self.masker_ = clone(self.mask_img) for param_name in ['target_affine', 'target_shape', 'smoothing_fwhm', 't_r', 'memory', 'memory_level']: our_param = getattr(self, param_name) if our_param is None: continue if getattr(self.masker_, param_name) is not None: warn('Parameter %s of the masker' ' overridden' % param_name) setattr(self.masker_, param_name, our_param) self.masker_.fit(run_imgs[0]) else: self.masker_ = self.mask_img # For each run fit the model and keep only the regression results. self.labels_, self.results_, self.design_matrices_ = [], [], [] n_runs = len(run_imgs) t0 = time.time() for run_idx, run_img in enumerate(run_imgs): # Report progress if self.verbose > 0: percent = float(run_idx) / n_runs percent = round(percent * 100, 2) dt = time.time() - t0 # We use a max to avoid a division by zero if run_idx == 0: remaining = 'go take a coffee, a big one' else: remaining = (100. - percent) / max(0.01, percent) * dt remaining = '%i seconds remaining' % remaining sys.stderr.write( "Computing run %d out of %d runs (%s)\n" % (run_idx + 1, n_runs, remaining)) # Build the experimental design for the glm run_img = check_niimg(run_img, ensure_ndim=4) if design_matrices is None: n_scans = get_data(run_img).shape[3] if confounds is not None: confounds_matrix = confounds[run_idx].values if confounds_matrix.shape[0] != n_scans: raise ValueError('Rows in confounds does not match' 'n_scans in run_img at index %d' % (run_idx,)) confounds_names = confounds[run_idx].columns.tolist() else: confounds_matrix = None confounds_names = None start_time = self.slice_time_ref * self.t_r end_time = (n_scans - 1 + self.slice_time_ref) * self.t_r frame_times = np.linspace(start_time, end_time, n_scans) design = make_first_level_design_matrix(frame_times, events[run_idx], self.hrf_model, self.drift_model, self.high_pass, self.drift_order, self.fir_delays, confounds_matrix, confounds_names, self.min_onset ) else: design = design_matrices[run_idx] if sample_masks is not None: sample_mask = sample_masks[run_idx] design = design.iloc[sample_mask, :] else: sample_mask = None self.design_matrices_.append(design) # Mask and prepare data for GLM if self.verbose > 1: t_masking = time.time() sys.stderr.write('Starting masker computation \r') Y = self.masker_.transform(run_img, sample_mask=sample_mask) del run_img # Delete unmasked image to save memory if self.verbose > 1: t_masking = time.time() - t_masking sys.stderr.write('Masker took %d seconds \n' % t_masking) if self.signal_scaling is not False: # noqa Y, _ = mean_scaling(Y, self.signal_scaling) if self.memory: mem_glm = self.memory.cache(run_glm, ignore=['n_jobs']) else: mem_glm = run_glm # compute GLM if self.verbose > 1: t_glm = time.time() sys.stderr.write('Performing GLM computation\r') labels, results = mem_glm(Y, design.values, noise_model=self.noise_model, bins=bins, n_jobs=self.n_jobs) if self.verbose > 1: t_glm = time.time() - t_glm sys.stderr.write('GLM took %d seconds \n' % t_glm) self.labels_.append(labels) # We save memory if inspecting model details is not necessary if self.minimize_memory: for key in results: results[key] = SimpleRegressionResults(results[key]) self.results_.append(results) del Y # Report progress if self.verbose > 0: sys.stderr.write("\nComputation of %d runs done in %i seconds\n\n" % (n_runs, time.time() - t0)) return self
spm_labels_files = [ os.path.join(output_dir, prefix + 'anat_n0_clear_hd_labeled.nii.gz') for (prefix, output_dir) in zip(['wc', 'c'], [spm_dir, sammba_dir]) ] for (prefix, spm_labels_file) in zip(['wc', 'c'], spm_labels_files): spm_tissues_imgs = [ os.path.join(spm_dir, prefix + '{0}anat_n0_clear_hd.nii'.format(n)) # Try after N3 for n in range(1, 4) ] mask_img = image.math_img('np.max(imgs, axis=-1) > .01', imgs=spm_tissues_imgs) spm_labels_img = image.math_img('img * (np.argmax(imgs, axis=-1) + 1)', img=mask_img, imgs=spm_tissues_imgs) check_niimg(spm_labels_img, dtype=float).to_filename(spm_labels_file) nwarp_apply = afni.NwarpApply().run transforms = [ os.path.join(sammba_dir, 'anat_n0_unifized_affine_general_warped_WARP.nii.gz'), os.path.join(sammba_dir, 'anat_n0_unifized_masked_aff.aff12.1D') ] warp = "'" + ' '.join(transforms) + "'" sammba_tissues_files = [] for tissue_file in spm_tissues_imgs: sammba_tissue_file = fname_presuffix(tissue_file, suffix='_warped', newpath=sammba_dir) out_warp_apply = nwarp_apply(in_file=tissue_file, master=template_file,
def fit(self, second_level_input, first_level_conditions=None, confounds=None, design_matrix=None): """ Fit the second-level GLM 1. create design matrix 2. do a masker job: fMRI_data -> Y 3. fit regression to (Y, X) Parameters ---------- second_level_input: list of `FirstLevelModel` objects or pandas DataFrame or list of Niimg-like objects. If list of `FirstLevelModel` objects, then first_level_conditions must be provided. If a pandas DataFrame, then they have to contain subject_id, map_name, effects_map_path. If list of Niimg-like objects then this is taken literally as Y for the model fit and design_matrix must be provided. first_level_conditions: list of (str, (str or array)) pairs or list of (str, str) pairs or None If second_level_input is a list of `FirstLevelModel` objects then it is mandatory to provide a list with contrast names as first item (employed as column names in the design matrix) and contrast definitions as second item. The contrast definitions are passed to the compute_contrast method of `FirstLevelModel`. The contrast definitions can be a str or array. Check the compute_contrast documentation of `FirstLevelModel` for more details on the contrast definitions. If second_level_input is a pandas DataFrame then a list with column names as first item (employed in the design matrix) and their corresponding map name as second item, where the map names correspond to those in the second_level_input map_name column. If first_level_conditions is set to None then all maps are included and the map_name is used as the column names in the design matrix. If second_level_input is a list of Niimg-like objects then this argument is ignored. confounds: pandas DataFrame, optional Must contain a subject_id column. All other columns are considered as confounds and included in the model. If design_matrix is provided then this argument is ignored. The resulting second level design matrix uses the same column names as in the given DataFrame for confounds. At least two columns are expected, "subject_id" and at least one confound. design_matrix: pandas DataFrame, optional Design matrix to fit the GLM. The number of rows in the design matrix must agree with the number of maps derived from second_level_input and first_level_conditions. Ensure that the order of maps given by first_level_conditions or inferred directly from a second_level_input dataframe matches the order of the rows in the design matrix. """ # Check parameters # check first level input if isinstance(second_level_input, list): if len(second_level_input) < 2: raise ValueError('A second level model requires a list with at' 'least two first level models or niimgs') # Check FirstLevelModel objects case if isinstance(second_level_input[0], FirstLevelModel): if first_level_conditions is None: raise ValueError('First level models input requires' 'first_level_conditions to be provided') models_input = enumerate(second_level_input) for model_idx, first_level_model in models_input: if not isinstance(first_level_model, FirstLevelModel): raise ValueError(' object at idx %d is %s instead of' ' FirstLevelModel object' % (model_idx, type(first_level_model))) if confounds is not None: if first_level_model.subject_id is None: raise ValueError( 'In case confounds are provided, first level ' 'objects need to provide the attribute ' 'subject_id to match rows appropriately. Model' ' at idx %d do not provide it. To set it, you ' 'can do first_level_model.subject_id = "01"' % (model_idx)) # Check niimgs case elif isinstance(second_level_input[0], (str, Nifti1Image)): if design_matrix is None: raise ValueError('List of niimgs as second_level_input' ' require a design matrix to be provided') for model_idx, niimg in enumerate(second_level_input): if not isinstance(niimg, (str, Nifti1Image)): raise ValueError(' object at idx %d is %s instead of' ' Niimg-like object' % (model_idx, type(niimg))) # Check pandas dataframe case elif isinstance(second_level_input, pd.DataFrame): for col in ['subject_id', 'map_name', 'effects_map_path']: if col not in second_level_input.columns: raise ValueError('second_level_input DataFrame must have' ' columns subject_id, map_name and' ' effects_map_path') if first_level_conditions is not None: for name, cond in first_level_conditions: if not isinstance(cond, str) and isinstance(name, str): raise ValueError('When second_level_input is a' ' DataFrame, first_level_conditions ' 'must be (str, str) pair') else: raise ValueError('second_level_input must be a list of' ' `FirstLevelModel` objects, a pandas DataFrame' ' or a list Niimg-like objects. Instead %s ' 'was provided' % type(second_level_input)) # check conditions if provided if first_level_conditions is not None: if isinstance(first_level_conditions, list): for cidx, (name, cond) in enumerate(first_level_conditions): if not isinstance(name, str): raise ValueError('condition name at idx %d is %s ' 'instead of str' % (cidx, type(name))) if not isinstance(cond, (str, np.ndarray)): raise ValueError('condition at idx %d is %s instead of' ' str or array' % (cidx, type(cond))) else: raise ValueError('first_level_conditions is not a list. ' 'It is %s instead' % type(first_level_conditions)) # check confounds if confounds is not None: if not isinstance(confounds, pd.DataFrame): raise ValueError('confounds must be a pandas DataFrame') if 'subject_id' not in confounds.columns: raise ValueError('confounds DataFrame must contain column' '"subject_id"') if len(confounds.columns) < 2: raise ValueError('confounds should contain at least 2 columns' 'one called "subject_id" and the other with' 'a given confound') # check design matrix if design_matrix is not None: if not isinstance(design_matrix, pd.DataFrame): raise ValueError('design matrix must be a pandas DataFrame') # Build the design matrix X and list of imgs Y for GLM fit if isinstance(second_level_input, pd.DataFrame): maps_table = second_level_input # Get only first level conditions if provided if first_level_conditions is not None: for name, condition in first_level_conditions: if condition not in maps_table['map_name'].tolist(): raise ValueError('condition %s not present in' ' second_level_input' % condition) condition_list = [cond[0] for cond in first_level_conditions] in_cond = maps_table.apply( lambda x: x['map_name'] in condition_list, axis=1) maps_table = maps_table[in_cond] # Create design matrix if necessary if design_matrix is None: design_matrix = create_second_level_design( maps_table, confounds) # get effect maps for fixed effects GLM effects_maps = maps_table['effects_map_path'].tolist() elif isinstance(second_level_input[0], FirstLevelModel): # Check models were fit for model_idx, model in enumerate(second_level_input): if model.labels_ is None: raise ValueError('Model at idx %d has not been fit' % model_idx) # Get the first level model maps maps_table = pd.DataFrame(columns=['map_name', 'subject_id']) effects_maps = [] for model in second_level_input: for con_name, con_def in first_level_conditions: maps_table.loc[len(maps_table)] = [ con_name, model.subject_id ] eff_map = model.compute_contrast(con_def, output_type='effect_size') effects_maps.append(eff_map) # Get the design matrix if design_matrix is None: design_matrix = create_second_level_design( maps_table, confounds) else: effects_maps = second_level_input # set design matrix, given or computed self.design_matrix_ = design_matrix # check design matrix X and effect maps Y agree on number of rows if len(effects_maps) != design_matrix.shape[0]: raise ValueError('design_matrix does not match the number of maps ' 'considered. Rows in design matrix do not agree ' 'with number of maps') # check niimgs for niimg in effects_maps: check_niimg(niimg, ensure_ndim=3) # Report progress t0 = time.time() if self.verbose > 0: sys.stderr.write("Computing second level model. " "Go take a coffee\r") # Learn the mask. Assume the first level imgs have been masked. if not isinstance(self.mask, NiftiMasker): self.masker_ = NiftiMasker(mask_img=self.mask, smoothing_fwhm=self.smoothing_fwhm, memory=self.memory, verbose=max(0, self.verbose - 1), memory_level=self.memory_level) else: self.masker_ = clone(self.mask) for param_name in ['smoothing_fwhm', 'memory', 'memory_level']: our_param = getattr(self, param_name) if our_param is None: continue if getattr(self.masker_, param_name) is not None: warn('Parameter %s of the masker overriden' % param_name) setattr(self.masker_, param_name, our_param) self.masker_.fit(effects_maps[0]) # Fit the model Y = self.masker_.transform(effects_maps) if self.memory is not None: arg_ignore = ['n_jobs', 'noise_model'] mem_glm = self.memory.cache(run_glm, ignore=arg_ignore) else: mem_glm = run_glm labels, results = mem_glm(Y, design_matrix.as_matrix(), n_jobs=self.n_jobs, noise_model='ols') # We save memory if inspecting model details is not necessary if self.minimize_memory: for key in results: results[key] = SimpleRegressionResults(results[key]) self.labels_ = labels self.results_ = results del Y # Report progress if self.verbose > 0: sys.stderr.write("\nComputation of second level model done in " "%i seconds\n" % (time.time() - t0)) return self
def fit(self, second_level_input, confounds=None, design_matrix=None): """ Fit the second-level GLM 1. create design matrix 2. do a masker job: fMRI_data -> Y 3. fit regression to (Y, X) Parameters ---------- second_level_input: list of `FirstLevelModel` objects or pandas DataFrame or list of Niimg-like objects. Giving FirstLevelModel objects will allow to easily compute the second level contast of arbitrary first level contrasts thanks to the first_level_contrast argument of the compute_contrast method. Effect size images will be computed for each model to contrast at the second level. If a pandas DataFrame, then they have to contain subject_label, map_name and effects_map_path. It can contain multiple maps that would be selected during contrast estimation with the argument first_level_contrast of the compute_contrast function. The DataFrame will be sorted based on the subject_label column to avoid order inconsistencies when extracting the maps. So the rows of the automatically computed design matrix, if not provided, will correspond to the sorted subject_label column. If list of Niimg-like objects then this is taken literally as Y for the model fit and design_matrix must be provided. confounds: pandas DataFrame, optional Must contain a subject_label column. All other columns are considered as confounds and included in the model. If design_matrix is provided then this argument is ignored. The resulting second level design matrix uses the same column names as in the given DataFrame for confounds. At least two columns are expected, "subject_label" and at least one confound. design_matrix: pandas DataFrame, optional Design matrix to fit the GLM. The number of rows in the design matrix must agree with the number of maps derived from second_level_input. Ensure that the order of maps given by a second_level_input list of Niimgs matches the order of the rows in the design matrix. """ # Check parameters # check first level input if isinstance(second_level_input, list): if len(second_level_input) < 2: raise ValueError('A second level model requires a list with at' 'least two first level models or niimgs') # Check FirstLevelModel objects case if isinstance(second_level_input[0], FirstLevelModel): models_input = enumerate(second_level_input) for model_idx, first_level_model in models_input: if (first_level_model.labels_ is None or first_level_model.results_ is None): raise ValueError( 'Model %s at index %i has not been fit yet' '' % (first_level_model.subject_label, model_idx)) if not isinstance(first_level_model, FirstLevelModel): raise ValueError(' object at idx %d is %s instead of' ' FirstLevelModel object' % (model_idx, type(first_level_model))) if confounds is not None: if first_level_model.subject_label is None: raise ValueError( 'In case confounds are provided, first level ' 'objects need to provide the attribute ' 'subject_label to match rows appropriately.' 'Model at idx %d does not provide it. ' 'To set it, you can do ' 'first_level_model.subject_label = "01"' '' % (model_idx)) # Check niimgs case elif isinstance(second_level_input[0], (str, Nifti1Image)): if design_matrix is None: raise ValueError('List of niimgs as second_level_input' ' require a design matrix to be provided') for model_idx, niimg in enumerate(second_level_input): if not isinstance(niimg, (str, Nifti1Image)): raise ValueError(' object at idx %d is %s instead of' ' Niimg-like object' % (model_idx, type(niimg))) # Check pandas dataframe case elif isinstance(second_level_input, pd.DataFrame): for col in ['subject_label', 'map_name', 'effects_map_path']: if col not in second_level_input.columns: raise ValueError('second_level_input DataFrame must have' ' columns subject_label, map_name and' ' effects_map_path') # Make sure subject_label contain strings second_level_columns = second_level_input.columns.tolist() labels_index = second_level_columns.index('subject_label') labels_dtype = second_level_input.dtypes[labels_index] if not isinstance(labels_dtype, np.object): raise ValueError('subject_label column must be of dtype ' 'object instead of dtype %s' % labels_dtype) elif isinstance(second_level_input, (str, Nifti1Image)): if design_matrix is None: raise ValueError('List of niimgs as second_level_input' ' require a design matrix to be provided') second_level_input = check_niimg(niimg=second_level_input, ensure_ndim=4) else: raise ValueError('second_level_input must be a list of' ' `FirstLevelModel` objects, a pandas DataFrame' ' or a list Niimg-like objects. Instead %s ' 'was provided' % type(second_level_input)) # check confounds if confounds is not None: if not isinstance(confounds, pd.DataFrame): raise ValueError('confounds must be a pandas DataFrame') if 'subject_label' not in confounds.columns: raise ValueError('confounds DataFrame must contain column' '"subject_label"') if len(confounds.columns) < 2: raise ValueError('confounds should contain at least 2 columns' 'one called "subject_label" and the other' 'with a given confound') # Make sure subject_label contain strings labels_index = confounds.columns.tolist().index('subject_label') labels_dtype = confounds.dtypes[labels_index] if not isinstance(labels_dtype, np.object): raise ValueError('subject_label column must be of dtype ' 'object instead of dtype %s' % labels_dtype) # check design matrix if design_matrix is not None: if not isinstance(design_matrix, pd.DataFrame): raise ValueError('design matrix must be a pandas DataFrame') # sort a pandas dataframe by subject_label to avoid inconsistencies # with the design matrix row order when automatically extracting maps if isinstance(second_level_input, pd.DataFrame): columns = second_level_input.columns.tolist() column_index = columns.index('subject_label') sorted_matrix = sorted(second_level_input.values, key=lambda x: x[column_index]) sorted_input = pd.DataFrame(sorted_matrix, columns=columns) second_level_input = sorted_input self.second_level_input_ = second_level_input self.confounds_ = confounds # Report progress t0 = time.time() if self.verbose > 0: sys.stderr.write("Fitting second level model. " "Take a deep breath\r") # Select sample map for masker fit and get subjects_label for design if isinstance(second_level_input, pd.DataFrame): sample_map = second_level_input['effects_map_path'][0] labels = second_level_input['subject_label'] subjects_label = labels.values.tolist() elif isinstance(second_level_input, Nifti1Image): sample_map = mean_img(second_level_input) elif isinstance(second_level_input[0], FirstLevelModel): sample_model = second_level_input[0] sample_condition = sample_model.design_matrices_[0].columns[0] sample_map = sample_model.compute_contrast( sample_condition, output_type='effect_size') labels = [model.subject_label for model in second_level_input] subjects_label = labels else: # In this case design matrix had to be provided sample_map = mean_img(second_level_input) # Create and set design matrix, if not given if design_matrix is None: design_matrix = make_second_level_design_matrix( subjects_label, confounds) self.design_matrix_ = design_matrix # Learn the mask. Assume the first level imgs have been masked. if not isinstance(self.mask, NiftiMasker): self.masker_ = NiftiMasker(mask_img=self.mask, smoothing_fwhm=self.smoothing_fwhm, memory=self.memory, verbose=max(0, self.verbose - 1), memory_level=self.memory_level) else: self.masker_ = clone(self.mask) for param_name in ['smoothing_fwhm', 'memory', 'memory_level']: our_param = getattr(self, param_name) if our_param is None: continue if getattr(self.masker_, param_name) is not None: warn('Parameter %s of the masker overriden' % param_name) setattr(self.masker_, param_name, our_param) self.masker_.fit(sample_map) # Report progress if self.verbose > 0: sys.stderr.write("\nComputation of second level model done in " "%i seconds\n" % (time.time() - t0)) return self
def _index_img(img_file, index): """ Return the volume in `index` 4th dimension index of `img_file`. If the image is 3D and idx is zero will return the container of `img_file`. """ imgs = check_niimg(img_file, ensure_ndim=4, atleast_4d=True) return _index_img(imgs, index)
def dice(mask_file1, mask_file2): mask_data1 = check_niimg(mask_file1).get_data() > 0 mask_data2 = check_niimg(mask_file2).get_data() > 0 numerator = np.logical_and(mask_data1, mask_data2).sum() denominator = mask_data1.sum() + mask_data2.sum() return 2 * numerator / float(denominator)
sammba_registered_ventricles_file = fname_presuffix( ventricles_mask_file, suffix='_allineated', newpath=sammba_dir) allineate = afni.Allineate().run out_allineate = allineate(in_file=ventricles_mask_file, master=template_ventricles_mask_file, in_matrix=os.path.join( sammba_dir, 'anat_n0_unifized_masked_aff.aff12.1D'), out_file=sammba_registered_ventricles_file, interpolation='nearestneighbour', environ={'AFNI_DECONFLICT': 'OVERWRITE'}) spm_registered_ventricles_file = os.path.join( spm_dir, 'wmanual_ventricles_mask.nii') spm_registered_ventricles_data = check_niimg( spm_registered_ventricles_file).get_data() template_shape = check_niimg(template_ventricles_mask_file).shape if spm_registered_ventricles_data.shape != template_shape: uncropped_spm_registered_ventricles_data = np.vstack( (np.zeros((1, ) + template_shape[1:]), spm_registered_ventricles_data)) uncropped_spm_registered_ventricles_data = np.nan_to_num( uncropped_spm_registered_ventricles_data) uncropped_spm_registered_contour_file = fname_presuffix( spm_registered_ventricles_file, suffix='_uncropped') image.new_img_like( spm_registered_ventricles_file, uncropped_spm_registered_ventricles_data).to_filename( uncropped_spm_registered_contour_file) else:
def cluster_stats(stat_img, mask_img, threshold, height_control='fpr', cluster_th=0, nulls=None): """ Return a list of clusters, each cluster being represented by a dictionary. Clusters are sorted by descending size order. Within each cluster, local maxima are sorted by descending statical value Parameters ---------- stat_img: Niimg-like object, statsitical image (presumably in z scale) mask_img: Niimg-like object, mask image threshold: float, cluster forming threshold (either a p-value or z-scale value) height_control: string false positive control meaning of cluster forming threshold: 'fpr'|'fdr'|'bonferroni'|'none' cluster_th: int or float, cluster size threshold nulls: dictionary, statistics of the null distribution Notes ----- If there is no cluster, an empty list is returned """ if nulls is None: nulls = {} # Masking mask_img, stat_img = check_niimg(mask_img), check_niimg(stat_img) if not _check_same_fov(mask_img, stat_img): raise ValueError('mask_img and stat_img do not have the same fov') mask = mask_img.get_data().astype(np.bool) affine = mask_img.get_affine() stat_map = stat_img.get_data() * mask n_voxels = mask.sum() # Thresholding if height_control == 'fpr': z_th = norm.isf(threshold) elif height_control == 'fdr': z_th = fdr_threshold(stat_map[mask], threshold) elif height_control == 'bonferroni': z_th = norm.isf(threshold / n_voxels) else: # Brute-force thresholding z_th = threshold p_th = norm.sf(z_th) # General info info = { 'n_voxels': n_voxels, 'threshold_z': z_th, 'threshold_p': p_th, 'threshold_pcorr': np.minimum(1, p_th * n_voxels) } above_th = stat_map > z_th above_values = stat_map * above_th if (above_th == 0).all(): return [], info # Extract connected components above threshold labels, n_labels = label(above_th) # Extract the local maxima anove the threshold maxima_mask = (above_values == np.maximum(z_th, maximum_filter(above_values, 3))) x, y, z = np.array(np.where(maxima_mask)) maxima_coords = np.array(coord_transform(x, y, z, affine)).T maxima_labels = labels[maxima_mask] maxima_values = above_values[maxima_mask] # FDR-corrected p-values max_fdr_p_values = fdr_p_values(stat_map[mask])[maxima_mask[mask]] # Default "nulls" if not 'zmax' in nulls: nulls['zmax'] = 'bonferroni' if not 'smax' in nulls: nulls['smax'] = None if not 's' in nulls: nulls['s'] = None # Make list of clusters, each cluster being a dictionary clusters = [] for k in range(n_labels): cluster_size = np.sum(labels == k + 1) if cluster_size >= cluster_th: # get the position of the maxima that belong to that cluster in_cluster = maxima_labels == k + 1 # sort the maxima by decreasing statistical value max_vals = maxima_values[in_cluster] sorted_ = max_vals.argsort()[::-1] # Report significance levels in each cluster z_score = max_vals[sorted_] p_values = norm.sf(z_score) # Voxel-level corrected p-values fwer_p_value = None if nulls['zmax'] == 'bonferroni': fwer_p_value = np.minimum(1, p_values * n_voxels) elif isinstance(nulls['zmax'], np.ndarray): fwer_p_value = empirical_p_value(clusters['z_score'], nulls['zmax']) # Cluster-level p-values (corrected) cluster_fwer_p_value = None if isinstance(nulls['smax'], np.ndarray): cluster_fwer_p_value = empirical_p_value( cluster_size, nulls['smax']) # Cluster-level p-values (uncorrected) cluster_p_value = None if isinstance(nulls['s'], np.ndarray): cluster_p_value = empirical_p_value(cluster_size, nulls['s']) # write all this into the cluster structure clusters.append({ 'size': cluster_size, 'maxima': maxima_coords[in_cluster][sorted_], 'z_score': z_score, 'fdr_p_value': max_fdr_p_values[in_cluster][sorted_], 'p_value': p_values, 'fwer_p_value': fwer_p_value, 'cluster_fwer_p_value': cluster_fwer_p_value, 'cluster_p_value': cluster_p_value }) # Sort clusters by descending size order order = np.argsort(-np.array([cluster['size'] for cluster in clusters])) clusters = [clusters[i] for i in order] return clusters, info
def fit(self, second_level_input, confounds=None, design_matrix=None): """ Fit the second-level GLM 1. create design matrix 2. do a masker job: fMRI_data -> Y 3. fit regression to (Y, X) Parameters ---------- second_level_input: list of `FirstLevelModel` objects or pandas DataFrame or list of Niimg-like objects. Giving FirstLevelModel objects will allow to easily compute the second level contast of arbitrary first level contrasts thanks to the first_level_contrast argument of the compute_contrast method. Effect size images will be computed for each model to contrast at the second level. If a pandas DataFrame, then they have to contain subject_label, map_name and effects_map_path. It can contain multiple maps that would be selected during contrast estimation with the argument first_level_contrast of the compute_contrast function. The DataFrame will be sorted based on the subject_label column to avoid order inconsistencies when extracting the maps. So the rows of the automatically computed design matrix, if not provided, will correspond to the sorted subject_label column. If list of Niimg-like objects then this is taken literally as Y for the model fit and design_matrix must be provided. confounds: pandas DataFrame, optional Must contain a subject_label column. All other columns are considered as confounds and included in the model. If design_matrix is provided then this argument is ignored. The resulting second level design matrix uses the same column names as in the given DataFrame for confounds. At least two columns are expected, "subject_label" and at least one confound. design_matrix: pandas DataFrame, optional Design matrix to fit the GLM. The number of rows in the design matrix must agree with the number of maps derived from second_level_input. Ensure that the order of maps given by a second_level_input list of Niimgs matches the order of the rows in the design matrix. """ # Check parameters # check first level input if isinstance(second_level_input, list): if len(second_level_input) < 2: raise ValueError('A second level model requires a list with at' 'least two first level models or niimgs') # Check FirstLevelModel objects case if isinstance(second_level_input[0], FirstLevelModel): models_input = enumerate(second_level_input) for model_idx, first_level_model in models_input: if (first_level_model.labels_ is None or first_level_model.results_ is None): raise ValueError( 'Model %s at index %i has not been fit yet' '' % (first_level_model.subject_label, model_idx)) if not isinstance(first_level_model, FirstLevelModel): raise ValueError(' object at idx %d is %s instead of' ' FirstLevelModel object' % (model_idx, type(first_level_model))) if confounds is not None: if first_level_model.subject_label is None: raise ValueError( 'In case confounds are provided, first level ' 'objects need to provide the attribute ' 'subject_label to match rows appropriately.' 'Model at idx %d does not provide it. ' 'To set it, you can do ' 'first_level_model.subject_label = "01"' '' % (model_idx)) # Check niimgs case elif isinstance(second_level_input[0], (str, Nifti1Image)): if design_matrix is None: raise ValueError('List of niimgs as second_level_input' ' require a design matrix to be provided') for model_idx, niimg in enumerate(second_level_input): if not isinstance(niimg, (str, Nifti1Image)): raise ValueError(' object at idx %d is %s instead of' ' Niimg-like object' % (model_idx, type(niimg))) # Check pandas dataframe case elif isinstance(second_level_input, pd.DataFrame): for col in ['subject_label', 'map_name', 'effects_map_path']: if col not in second_level_input.columns: raise ValueError('second_level_input DataFrame must have' ' columns subject_label, map_name and' ' effects_map_path') # Make sure subject_label contain strings second_level_columns = second_level_input.columns.tolist() labels_index = second_level_columns.index('subject_label') labels_dtype = second_level_input.dtypes[labels_index] if not isinstance(labels_dtype, np.object): raise ValueError('subject_label column must be of dtype ' 'object instead of dtype %s' % labels_dtype) elif isinstance(second_level_input, (str, Nifti1Image)): if design_matrix is None: raise ValueError('List of niimgs as second_level_input' ' require a design matrix to be provided') second_level_input = check_niimg(niimg=second_level_input, ensure_ndim=4) else: raise ValueError('second_level_input must be a list of' ' `FirstLevelModel` objects, a pandas DataFrame' ' or a list Niimg-like objects. Instead %s ' 'was provided' % type(second_level_input)) # check confounds if confounds is not None: if not isinstance(confounds, pd.DataFrame): raise ValueError('confounds must be a pandas DataFrame') if 'subject_label' not in confounds.columns: raise ValueError('confounds DataFrame must contain column' '"subject_label"') if len(confounds.columns) < 2: raise ValueError('confounds should contain at least 2 columns' 'one called "subject_label" and the other' 'with a given confound') # Make sure subject_label contain strings labels_index = confounds.columns.tolist().index('subject_label') labels_dtype = confounds.dtypes[labels_index] if not isinstance(labels_dtype, np.object): raise ValueError('subject_label column must be of dtype ' 'object instead of dtype %s' % labels_dtype) # check design matrix if design_matrix is not None: if not isinstance(design_matrix, pd.DataFrame): raise ValueError('design matrix must be a pandas DataFrame') # sort a pandas dataframe by subject_label to avoid inconsistencies # with the design matrix row order when automatically extracting maps if isinstance(second_level_input, pd.DataFrame): columns = second_level_input.columns.tolist() column_index = columns.index('subject_label') sorted_matrix = sorted( second_level_input.values, key=lambda x: x[column_index]) sorted_input = pd.DataFrame(sorted_matrix, columns=columns) second_level_input = sorted_input self.second_level_input_ = second_level_input self.confounds_ = confounds # Report progress t0 = time.time() if self.verbose > 0: sys.stderr.write("Fitting second level model. " "Take a deep breath\r") # Select sample map for masker fit and get subjects_label for design if isinstance(second_level_input, pd.DataFrame): sample_map = second_level_input['effects_map_path'][0] labels = second_level_input['subject_label'] subjects_label = labels.values.tolist() elif isinstance(second_level_input, Nifti1Image): sample_map = mean_img(second_level_input) elif isinstance(second_level_input[0], FirstLevelModel): sample_model = second_level_input[0] sample_condition = sample_model.design_matrices_[0].columns[0] sample_map = sample_model.compute_contrast( sample_condition, output_type='effect_size') labels = [model.subject_label for model in second_level_input] subjects_label = labels else: # In this case design matrix had to be provided sample_map = mean_img(second_level_input) # Create and set design matrix, if not given if design_matrix is None: design_matrix = make_second_level_design_matrix(subjects_label, confounds) self.design_matrix_ = design_matrix # Learn the mask. Assume the first level imgs have been masked. if not isinstance(self.mask, NiftiMasker): self.masker_ = NiftiMasker( mask_img=self.mask, smoothing_fwhm=self.smoothing_fwhm, memory=self.memory, verbose=max(0, self.verbose - 1), memory_level=self.memory_level) else: self.masker_ = clone(self.mask) for param_name in ['smoothing_fwhm', 'memory', 'memory_level']: our_param = getattr(self, param_name) if our_param is None: continue if getattr(self.masker_, param_name) is not None: warn('Parameter %s of the masker overriden' % param_name) setattr(self.masker_, param_name, our_param) self.masker_.fit(sample_map) # Report progress if self.verbose > 0: sys.stderr.write("\nComputation of second level model done in " "%i seconds\n" % (time.time() - t0)) return self
''' import sys import numpy as np from nibabel import Nifti1Image from nilearn._utils.niimg_conversions import check_niimg def variance_partition(d1, d2, comb): d1 = np.maximum(d1, 0) d2 = np.maximum(d2, 0) comb = np.maximum(comb, 0) only_d1 = comb - d2 only_d2 = comb - d1 intersection = d1 - only_d1 return only_d1, only_d2, intersection if __name__ == '__main__': img = check_niimg(sys.argv[1]) data1 = img.get_data() data2 = check_niimg(sys.argv[2]).get_data() data_combined = check_niimg(sys.argv[3]).get_data() ex1, ex2, intersection = variance_partition(data1, data2, data_combined) ex1_img = Nifti1Image(ex1, affine=img.affine) ex1_img.to_filename(sys.argv[4]) ex2_img = Nifti1Image(ex2, affine=img.affine) ex2_img.to_filename(sys.argv[5]) intersection_img = Nifti1Image(intersection, affine=img.affine) intersection_img.to_filename(sys.argv[6])
def cluster_stats(stat_img, mask_img, threshold, height_control='fpr', cluster_th=0, nulls=None): """ Return a list of clusters, each cluster being represented by a dictionary. Clusters are sorted by descending size order. Within each cluster, local maxima are sorted by descending statical value Parameters ---------- stat_img: Niimg-like object, statsitical image (presumably in z scale) mask_img: Niimg-like object, mask image threshold: float, cluster forming threshold (either a p-value or z-scale value) height_control: string false positive control meaning of cluster forming threshold: 'fpr'|'fdr'|'bonferroni'|'none' cluster_th: int or float, cluster size threshold nulls: dictionary, statistics of the null distribution Notes ----- If there is no cluster, an empty list is returned """ if nulls is None: nulls = {} # Masking mask_img, stat_img = check_niimg(mask_img), check_niimg(stat_img) if not _check_same_fov(mask_img, stat_img): raise ValueError('mask_img and stat_img do not have the same fov') mask = mask_img.get_data().astype(np.bool) affine = mask_img.get_affine() stat_map = stat_img.get_data() * mask n_voxels = mask.sum() # Thresholding if height_control == 'fpr': z_th = norm.isf(threshold) elif height_control == 'fdr': z_th = fdr_threshold(stat_map[mask], threshold) elif height_control == 'bonferroni': z_th = norm.isf(threshold / n_voxels) else: # Brute-force thresholding z_th = threshold p_th = norm.sf(z_th) # General info info = {'n_voxels': n_voxels, 'threshold_z': z_th, 'threshold_p': p_th, 'threshold_pcorr': np.minimum(1, p_th * n_voxels)} above_th = stat_map > z_th above_values = stat_map * above_th if (above_th == 0).all(): return [], info # Extract connected components above threshold labels, n_labels = label(above_th) # Extract the local maxima anove the threshold maxima_mask = (above_values == np.maximum(z_th, maximum_filter(above_values, 3))) x, y, z = np.array(np.where(maxima_mask)) maxima_coords = np.array(coord_transform(x, y, z, affine)).T maxima_labels = labels[maxima_mask] maxima_values = above_values[maxima_mask] # FDR-corrected p-values max_fdr_p_values = fdr_p_values(stat_map[mask])[maxima_mask[mask]] # Default "nulls" if not 'zmax' in nulls: nulls['zmax'] = 'bonferroni' if not 'smax' in nulls: nulls['smax'] = None if not 's' in nulls: nulls['s'] = None # Make list of clusters, each cluster being a dictionary clusters = [] for k in range(n_labels): cluster_size = np.sum(labels == k + 1) if cluster_size >= cluster_th: # get the position of the maxima that belong to that cluster in_cluster = maxima_labels == k + 1 # sort the maxima by decreasing statistical value max_vals = maxima_values[in_cluster] sorted_ = max_vals.argsort()[::-1] # Report significance levels in each cluster z_score = max_vals[sorted_] p_values = norm.sf(z_score) # Voxel-level corrected p-values fwer_p_value = None if nulls['zmax'] == 'bonferroni': fwer_p_value = np.minimum(1, p_values * n_voxels) elif isinstance(nulls['zmax'], np.ndarray): fwer_p_value = empirical_p_value( clusters['z_score'], nulls['zmax']) # Cluster-level p-values (corrected) cluster_fwer_p_value = None if isinstance(nulls['smax'], np.ndarray): cluster_fwer_p_value = empirical_p_value( cluster_size, nulls['smax']) # Cluster-level p-values (uncorrected) cluster_p_value = None if isinstance(nulls['s'], np.ndarray): cluster_p_value = empirical_p_value( cluster_size, nulls['s']) # write all this into the cluster structure clusters.append({ 'size': cluster_size, 'maxima': maxima_coords[in_cluster][sorted_], 'z_score': z_score, 'fdr_p_value': max_fdr_p_values[in_cluster][sorted_], 'p_value': p_values, 'fwer_p_value': fwer_p_value, 'cluster_fwer_p_value': cluster_fwer_p_value, 'cluster_p_value': cluster_p_value }) # Sort clusters by descending size order order = np.argsort(- np.array([cluster['size'] for cluster in clusters])) clusters = [clusters[i] for i in order] return clusters, info
def fit(self, run_imgs, events=None, confounds=None, design_matrices=None): """ Fit the GLM For each run: 1. create design matrix X 2. do a masker job: fMRI_data -> Y 3. fit regression to (Y, X) Parameters ---------- run_imgs: Niimg-like object or list of Niimg-like objects, See http://nilearn.github.io/manipulating_images/input_output.html#inputing-data-file-names-or-image-objects Data on which the GLM will be fitted. If this is a list, the affine is considered the same for all. events: pandas Dataframe or string or list of pandas DataFrames or strings fMRI events used to build design matrices. One events object expected per run_img. Ignored in case designs is not None. If string, then a path to a csv file is expected. confounds: pandas Dataframe or string or list of pandas DataFrames or strings Each column in a DataFrame corresponds to a confound variable to be included in the regression model of the respective run_img. The number of rows must match the number of volumes in the respective run_img. Ignored in case designs is not None. If string, then a path to a csv file is expected. design_matrices: pandas DataFrame or list of pandas DataFrames, Design matrices that will be used to fit the GLM. If given it takes precedence over events and confounds. """ # Check arguments # Check imgs type if events is not None: _check_events_file_uses_tab_separators(events_files=events) if not isinstance(run_imgs, (list, tuple)): run_imgs = [run_imgs] if design_matrices is None: if events is None: raise ValueError('events or design matrices must be provided') if self.t_r is None: raise ValueError('t_r not given to FirstLevelModel object' ' to compute design from events') else: design_matrices = _check_run_tables(run_imgs, design_matrices, 'design_matrices') # Check that number of events and confound files match number of runs # Also check that events and confound files can be loaded as DataFrame if events is not None: events = _check_run_tables(run_imgs, events, 'events') if confounds is not None: confounds = _check_run_tables(run_imgs, confounds, 'confounds') # Learn the mask if self.mask_img is False: # We create a dummy mask to preserve functionality of api ref_img = check_niimg(run_imgs[0]) self.mask_img = Nifti1Image(np.ones(ref_img.shape[:3]), ref_img.affine) if not isinstance(self.mask_img, NiftiMasker): self.masker_ = NiftiMasker(mask_img=self.mask_img, smoothing_fwhm=self.smoothing_fwhm, target_affine=self.target_affine, standardize=self.standardize, mask_strategy='epi', t_r=self.t_r, memory=self.memory, verbose=max(0, self.verbose - 2), target_shape=self.target_shape, memory_level=self.memory_level) self.masker_.fit(run_imgs[0]) else: if self.mask_img.mask_img_ is None and self.masker_ is None: self.masker_ = clone(self.mask_img) for param_name in [ 'target_affine', 'target_shape', 'smoothing_fwhm', 't_r', 'memory', 'memory_level' ]: our_param = getattr(self, param_name) if our_param is None: continue if getattr(self.masker_, param_name) is not None: warn('Parameter %s of the masker' ' overriden' % param_name) setattr(self.masker_, param_name, our_param) self.masker_.fit(run_imgs[0]) else: self.masker_ = self.mask_img # For each run fit the model and keep only the regression results. self.labels_, self.results_, self.design_matrices_ = [], [], [] n_runs = len(run_imgs) t0 = time.time() for run_idx, run_img in enumerate(run_imgs): # Report progress if self.verbose > 0: percent = float(run_idx) / n_runs percent = round(percent * 100, 2) dt = time.time() - t0 # We use a max to avoid a division by zero if run_idx == 0: remaining = 'go take a coffee, a big one' else: remaining = (100. - percent) / max(0.01, percent) * dt remaining = '%i seconds remaining' % remaining sys.stderr.write("Computing run %d out of %d runs (%s)\n" % (run_idx + 1, n_runs, remaining)) # Build the experimental design for the glm run_img = check_niimg(run_img, ensure_ndim=4) if design_matrices is None: n_scans = run_img.get_data().shape[3] if confounds is not None: confounds_matrix = confounds[run_idx].values if confounds_matrix.shape[0] != n_scans: raise ValueError('Rows in confounds does not match' 'n_scans in run_img at index %d' % (run_idx, )) confounds_names = confounds[run_idx].columns.tolist() else: confounds_matrix = None confounds_names = None start_time = self.slice_time_ref * self.t_r end_time = (n_scans - 1 + self.slice_time_ref) * self.t_r frame_times = np.linspace(start_time, end_time, n_scans) design = make_first_level_design_matrix( frame_times, events[run_idx], self.hrf_model, self.drift_model, self.high_pass, self.drift_order, self.fir_delays, confounds_matrix, confounds_names, self.min_onset) else: design = design_matrices[run_idx] self.design_matrices_.append(design) # Mask and prepare data for GLM if self.verbose > 1: t_masking = time.time() sys.stderr.write('Starting masker computation \r') Y = self.masker_.transform(run_img) if self.verbose > 1: t_masking = time.time() - t_masking sys.stderr.write('Masker took %d seconds \n' % t_masking) if self.signal_scaling: Y, _ = mean_scaling(Y, self.scaling_axis) if self.memory: mem_glm = self.memory.cache(run_glm, ignore=['n_jobs']) else: mem_glm = run_glm # compute GLM if self.verbose > 1: t_glm = time.time() sys.stderr.write('Performing GLM computation\r') labels, results = mem_glm(Y, design.values, noise_model=self.noise_model, bins=100, n_jobs=self.n_jobs) if self.verbose > 1: t_glm = time.time() - t_glm sys.stderr.write('GLM took %d seconds \n' % t_glm) self.labels_.append(labels) # We save memory if inspecting model details is not necessary if self.minimize_memory: for key in results: results[key] = SimpleRegressionResults(results[key]) self.results_.append(results) del Y # Report progress if self.verbose > 0: sys.stderr.write( "\nComputation of %d runs done in %i seconds\n\n" % (n_runs, time.time() - t0)) return self
def _check_second_level_input(second_level_input, design_matrix, confounds=None, flm_object=True, df_object=True): """Checking second_level_input type""" # Check parameters # check first level input if isinstance(second_level_input, list): if len(second_level_input) < 2: raise ValueError('A second level model requires a list with at' ' least two first level models or niimgs') # Check FirstLevelModel objects case if flm_object and isinstance(second_level_input[0], FirstLevelModel): models_input = enumerate(second_level_input) for model_idx, first_level in models_input: if (first_level.labels_ is None or first_level.results_ is None): raise ValueError( 'Model %s at index %i has not been fit yet' '' % (first_level.subject_label, model_idx)) if not isinstance(first_level, FirstLevelModel): raise ValueError(' object at idx %d is %s instead of' ' FirstLevelModel object' % (model_idx, type(first_level))) if confounds is not None: if first_level.subject_label is None: raise ValueError( 'In case confounds are provided, first level ' 'objects need to provide the attribute ' 'subject_label to match rows appropriately.' 'Model at idx %d does not provide it. ' 'To set it, you can do ' 'first_level.subject_label = "01"' '' % (model_idx)) # Check niimgs case elif isinstance(second_level_input[0], (str, Nifti1Image)): if design_matrix is None: raise ValueError('List of niimgs as second_level_input' ' require a design matrix to be provided') for model_idx, niimg in enumerate(second_level_input): if not isinstance(niimg, (str, Nifti1Image)): raise ValueError(' object at idx %d is %s instead of' ' Niimg-like object' % (model_idx, type(niimg))) # Check pandas dataframe case elif df_object and isinstance(second_level_input, pd.DataFrame): for col in ['subject_label', 'map_name', 'effects_map_path']: if col not in second_level_input.columns: raise ValueError('second_level_input DataFrame must have' ' columns subject_label, map_name and' ' effects_map_path') # Make sure subject_label contain strings if not all([ isinstance(_, str) for _ in second_level_input['subject_label'].tolist() ]): raise ValueError('subject_label column must contain only strings') elif isinstance(second_level_input, (str, Nifti1Image)): if design_matrix is None: raise ValueError('List of niimgs as second_level_input' ' require a design matrix to be provided') second_level_input = check_niimg(niimg=second_level_input, ensure_ndim=4) else: if flm_object and df_object: raise ValueError('second_level_input must be a list of' ' `FirstLevelModel` objects, a pandas DataFrame' ' or a list Niimg-like objects. Instead %s ' 'was provided' % type(second_level_input)) else: raise ValueError('second_level_input must be' ' a list Niimg-like objects. Instead %s ' 'was provided' % type(second_level_input))
def _check_second_level_input(second_level_input, design_matrix, confounds=None, flm_object=True, df_object=True): """Checking second_level_input type""" # Check parameters # check first level input if isinstance(second_level_input, list): if len(second_level_input) < 2: raise ValueError('A second level model requires a list with at' ' least two first level models or niimgs') # Check FirstLevelModel objects case if flm_object and isinstance(second_level_input[0], FirstLevelModel): models_input = enumerate(second_level_input) for model_idx, first_level_model in models_input: if (first_level_model.labels_ is None or first_level_model.results_ is None): raise ValueError( 'Model %s at index %i has not been fit yet' '' % (first_level_model.subject_label, model_idx)) if not isinstance(first_level_model, FirstLevelModel): raise ValueError(' object at idx %d is %s instead of' ' FirstLevelModel object' % (model_idx, type(first_level_model))) if confounds is not None: if first_level_model.subject_label is None: raise ValueError( 'In case confounds are provided, first level ' 'objects need to provide the attribute ' 'subject_label to match rows appropriately.' 'Model at idx %d does not provide it. ' 'To set it, you can do ' 'first_level_model.subject_label = "01"' '' % (model_idx)) # Check niimgs case elif isinstance(second_level_input[0], (str, Nifti1Image)): if design_matrix is None: raise ValueError('List of niimgs as second_level_input' ' require a design matrix to be provided') for model_idx, niimg in enumerate(second_level_input): if not isinstance(niimg, (str, Nifti1Image)): raise ValueError(' object at idx %d is %s instead of' ' Niimg-like object' % (model_idx, type(niimg))) # Check pandas dataframe case elif df_object and isinstance(second_level_input, pd.DataFrame): for col in ['subject_label', 'map_name', 'effects_map_path']: if col not in second_level_input.columns: raise ValueError('second_level_input DataFrame must have' ' columns subject_label, map_name and' ' effects_map_path') # Make sure subject_label contain strings second_level_columns = second_level_input.columns.tolist() labels_index = second_level_columns.index('subject_label') labels_dtype = second_level_input.dtypes[labels_index] if not isinstance(labels_dtype, np.object): raise ValueError('subject_label column must be of dtype ' 'object instead of dtype %s' % labels_dtype) elif isinstance(second_level_input, (str, Nifti1Image)): if design_matrix is None: raise ValueError('List of niimgs as second_level_input' ' require a design matrix to be provided') second_level_input = check_niimg(niimg=second_level_input, ensure_ndim=4) else: if flm_object and df_object: raise ValueError('second_level_input must be a list of' ' `FirstLevelModel` objects, a pandas DataFrame' ' or a list Niimg-like objects. Instead %s ' 'was provided' % type(second_level_input)) else: raise ValueError('second_level_input must be' ' a list Niimg-like objects. Instead %s ' 'was provided' % type(second_level_input))
def fetch_atlas_dorr_2008(image_format='nifti', downsample='30', data_dir=None, url=None, resume=True, verbose=1): """Download and load Dorr et al. atlas and average (dated 2008) Parameters ---------- image_format : one of {'nifti', 'minc'}, optional Format to download downsample : one of {'30', '100'}, optional Downsampling resolution in microns. data_dir : str, optional Path of the data directory. Use to forec data storage in a non- standard location. Default: None (meaning: default) url: string, optional Download URL of the dataset. Overwrite the default URL. resume : bool whether to resumed download of a partly-downloaded file. verbose : int verbosity level (0 means no message). Returns ------- data: sklearn.datasets.base.Bunch dictionary-like object, contains: - 't2' : str, path to nifti file containing the T2 weighted average. - 'maps' : str, path to nifti file containing regions definition. - 'names' : str list containing the names of the regions. - 'labels' : int list containing the label value of each region. - 'description' : description about the atlas and the template. References ---------- A.E. Dorr, J.P. Lerch, S. Spring, N. Kabani and R.M. Henkelman. "High resolution three dimensional brain atlas using an average magnetic resonance image of 40 adult C57Bl/6j mice", NeuroImage 42(1):60-69, 2008. See http://www.mouseimaging.ca/research/mouse_atlas.html for more information on this parcellation. Licence: Unknown """ if image_format not in ['nifti', 'minc']: raise ValueError("Images format must be 'nifti' or 'minc', you " "entered {0}".format(image_format)) if downsample not in ['30', '100']: raise ValueError("'downsample' must be '30' or '100', you " "provided {0}".format(downsample)) if url is None: if image_format == 'minc': url = [ 'http://www.mouseimaging.ca/mnc/C57Bl6j_mouse_atlas/', 'http://www.mouseimaging.ca/mnc/C57Bl6j_mouse_atlas/', 'http://www.mouseimaging.ca/research/C57Bl6j_mouse_atlas/' ] else: url = [ 'http://repo.mouseimaging.ca/repo/Dorr_2008_nifti/', 'http://repo.mouseimaging.ca/repo/Dorr_2008_nifti/', 'http://www.mouseimaging.ca/research/C57Bl6j_mouse_atlas/' ] if image_format == 'minc': files = [ 'male-female-mouse-atlas.mnc', 'c57_fixed_labels_resized.mnc', 'c57_brain_atlas_labels.csv' ] else: files = [ 'Dorr_2008_average.nii.gz', 'Dorr_2008_labels.nii.gz', 'c57_brain_atlas_labels.csv' ] files = [(f, u + f, {}) for f, u in zip(files, url)] dataset_name = 'dorr_2008' data_dir = _get_dataset_dir(dataset_name, data_dir=data_dir, verbose=verbose) files_ = _fetch_files(data_dir, files, resume=resume, verbose=verbose) fdescr = _get_dataset_descr(dataset_name) csv_data = np.recfromcsv(files_[2], skip_header=True, names=('roi_id', 'roi_label', 'right_index', 'left_index')) #TODO try dictionary with their region id as key and name as value left_rois = [] right_rois = [] lateral_rois = [] for (idx, label, right_index, left_index) in csv_data: label = label.decode('UTF-8') # for python3 if right_index == left_index: lateral_rois.append((label, right_index)) else: left_rois.append(('L {}'.format(label), left_index)) right_rois.append(('R {}'.format(label), right_index)) rois = lateral_rois + right_rois + left_rois labels, indices = map(list, zip(*rois)) t2 = files_[0] maps = files_[1] if downsample == '100': t2_img = nibabel.load(t2) maps_img = check_niimg(maps, dtype=int) t2 = fname_presuffix(t2, suffix='_100um') maps = fname_presuffix(maps, suffix='_100um') if not os.path.isfile(t2): target_affine = np.eye(3) * .1 t2_img = image.resample_img(t2_img, target_affine) t2_img.to_filename(t2) if not os.path.isfile(maps): maps_img = image.resample_img(maps_img, target_affine, interpolation='nearest') maps_img.to_filename(maps) params = dict(t2=t2, maps=maps, names=np.array(labels)[np.argsort(indices)], labels=np.sort(indices), description=fdescr) return Bunch(**params)
def fetch_masks_dorr_2008(image_format='nifti', downsample='30', data_dir=None, resume=True, verbose=1): """Downloads DORR 2008 atlas first, then uses its labels to produce tissue masks. Parameters ---------- image_format : one of {'nifti', 'minc'}, optional Format to download downsample : one of {'30', '100'}, optional Downsampling resolution in microns. data_dir : str, optional Path of the data directory. Use to forec data storage in a non- standard location. Default: None (meaning: default) resume : bool, optional whether to resumed download of a partly-downloaded file. verbose : int, optional verbosity level (0 means no message). Returns ------- mask_imgs: sklearn.datasets.base.Bunch dictionary-like object, contains: - 'brain' : nibabel.nifti1.Nifti1Image brain mask image. - 'gm' : nibabel.nifti1.Nifti1Image grey matter mask image. - 'cc' : nibabel.nifti1.Nifti1Image eroded corpus callosum mask image. - 'ventricles' : nibabel.nifti1.Nifti1Image eroded ventricles mask image. Notes ----- This function relies on DORR 2008 atlas where we particularly pick ventricles and corpus callosum regions. Then, do a bit post processing such as binary closing operation to more compact brain and grey matter mask image and binary erosion to non-contaminated corpus callosum and ventricles mask images. Note: It is advised to check the mask images with your own data processing. See Also -------- sammba.data_fetchers.fetch_atlas_dorr_2008: for details regarding the DORR 2008 atlas. """ masks_dir = _get_dataset_dir('dorr_2008', data_dir=data_dir, verbose=verbose) if image_format == 'nifti': ext = '.nii.gz' elif image_format == 'minc': ext = '.minc' else: raise ValueError("Images format must be 'nifti' or 'minc', you " "entered {0}".format(image_format)) brain_mask_file = os.path.join( masks_dir, 'dorr_2008_brain_mask_{}{}'.format(downsample, ext)) gm_mask_file = os.path.join( masks_dir, 'dorr_2008_gm_mask_{}{}'.format(downsample, ext)) cc_mask_file = os.path.join( masks_dir, 'dorr_2008_cc_mask_{}{}'.format(downsample, ext)) ventricles_mask_file = os.path.join( masks_dir, 'dorr_2008_ventricles_mask_{}{}'.format(downsample, ext)) existing_mask_files = [ os.path.isfile(f) for f in [brain_mask_file, gm_mask_file, cc_mask_file, ventricles_mask_file] ] if not np.all(existing_mask_files): # Fetching DORR 2008 atlas dorr = fetch_atlas_dorr_2008(image_format=image_format, downsample=downsample, data_dir=data_dir, resume=resume, verbose=verbose) atlas_img = check_niimg(dorr.maps) atlas_data = niimg._safe_get_data(atlas_img).astype(int) if not os.path.isfile(brain_mask_file): brain_mask = (atlas_data > 0) brain_mask = ndimage.binary_closing(brain_mask, iterations=2) brain_mask_img = image.new_img_like(atlas_img, brain_mask) brain_mask_img.to_filename(brain_mask_file) if not os.path.isfile(cc_mask_file): cc_labels = dorr.labels[np.in1d( dorr.names.astype(str), ['R corpus callosum', 'L corpus callosum'])] cc_mask = np.max([atlas_data == value for value in cc_labels], axis=0) eroded_cc_mask = ndimage.binary_erosion(cc_mask, iterations=2) cc_mask_img = image.new_img_like(atlas_img, eroded_cc_mask) cc_mask_img.to_filename(cc_mask_file) if not os.path.isfile(ventricles_mask_file): ventricles_names = [ 'R lateral ventricle', 'L lateral ventricle', 'third ventricle', 'fourth ventricle' ] ventricles_labels = dorr.labels[np.in1d(dorr.names.astype(str), ventricles_names)] ventricles_mask = np.max( [atlas_data == value for value in ventricles_labels], axis=0) eroded_ventricles_mask = ndimage.binary_erosion(ventricles_mask, iterations=2) ventricles_mask_img = image.new_img_like(atlas_img, eroded_ventricles_mask) ventricles_mask_img.to_filename(ventricles_mask_file) if not os.path.isfile(gm_mask_file): gm_mask_img = image.math_img( 'np.logical_not(np.logical_or(ventricles_mask_img, cc_mask_img))', ventricles_mask_img=ventricles_mask_img, cc_mask_img=cc_mask_img) gm_mask_img = image.math_img( 'np.logical_and(brain_mask_img, gm_mask_img)', brain_mask_img=brain_mask_img, gm_mask_img=gm_mask_img) gm_mask_closed_data = ndimage.binary_closing(gm_mask_img.get_data(), iterations=2) gm_mask_img = image.new_img_like(gm_mask_img, gm_mask_closed_data) gm_mask_img.to_filename(gm_mask_file) mask_files = { 'brain': brain_mask_file, 'gm': gm_mask_file, 'cc': cc_mask_file, 'ventricles': ventricles_mask_file } return Bunch(**mask_files)
sammba_registered_atlas_file, suffix='_warped')) spm_atlas_id = atlas_id.replace('_corrected', '') if mouse_id == '_C57_ab2_invivo_corrected.nii.gz': spm_atlas_id = '_Ab2_invivo.nii.gz' elif mouse_id == '_C57_y81_Invivo_corrected.nii.gz': spm_atlas_id = '_y81_invivo.nii.gz' spm_registered_atlas_file = fname_presuffix( spm_atlas_id, newpath=spm_dir, prefix='wbil2_transfo_Atlas', suffix='.nii', use_ext=False) spm_registered_atlas_data = check_niimg( spm_registered_atlas_file).get_data() template_shape = check_niimg(spm_template_atlas_file).shape if spm_registered_atlas_data.shape != template_shape: uncropped_spm_registered_atlas_data = np.vstack( (np.zeros((1, ) + template_shape[1:]), spm_registered_atlas_data)) uncropped_spm_registered_atlas_data = np.nan_to_num( uncropped_spm_registered_atlas_data) uncropped_spm_registered_atlas_file = fname_presuffix( spm_registered_atlas_file, suffix='_uncropped') image.new_img_like( spm_registered_atlas_file, uncropped_spm_registered_atlas_data).to_filename( uncropped_spm_registered_atlas_file) else:
def fit(self, run_imgs, events=None, confounds=None, design_matrices=None): """ Fit the GLM For each run: 1. create design matrix X 2. do a masker job: fMRI_data -> Y 3. fit regression to (Y, X) Parameters ---------- run_imgs: Niimg-like object or list of Niimg-like objects, See http://nilearn.github.io/manipulating_images/input_output.html#inputing-data-file-names-or-image-objects Data on which the GLM will be fitted. If this is a list, the affine is considered the same for all. events: pandas Dataframe or string or list of pandas DataFrames or strings fMRI events used to build design matrices. One events object expected per run_img. Ignored in case designs is not None. If string, then a path to a csv file is expected. confounds: pandas Dataframe or string or list of pandas DataFrames or strings Each column in a DataFrame corresponds to a confound variable to be included in the regression model of the respective run_img. The number of rows must match the number of volumes in the respective run_img. Ignored in case designs is not None. If string, then a path to a csv file is expected. design_matrices: pandas DataFrame or list of pandas DataFrames, Design matrices that will be used to fit the GLM. If given it takes precedence over events and confounds. """ # Check arguments # Check imgs type if events is not None: _check_events_file_uses_tab_separators( events_files=events) if not isinstance(run_imgs, (list, tuple)): run_imgs = [run_imgs] if design_matrices is None: if events is None: raise ValueError('events or design matrices must be provided') if self.t_r is None: raise ValueError('t_r not given to FirstLevelModel object' ' to compute design from events') else: design_matrices = _check_run_tables(run_imgs, design_matrices, 'design_matrices') # Check that number of events and confound files match number of runs # Also check that events and confound files can be loaded as DataFrame if events is not None: events = _check_run_tables(run_imgs, events, 'events') if confounds is not None: confounds = _check_run_tables(run_imgs, confounds, 'confounds') # Learn the mask if self.mask_img is False: # We create a dummy mask to preserve functionality of api ref_img = check_niimg(run_imgs[0]) self.mask_img = Nifti1Image(np.ones(ref_img.shape[:3]), ref_img.affine) if not isinstance(self.mask_img, NiftiMasker): self.masker_ = NiftiMasker( mask_img=self.mask_img, smoothing_fwhm=self.smoothing_fwhm, target_affine=self.target_affine, standardize=self.standardize, mask_strategy='epi', t_r=self.t_r, memory=self.memory, verbose=max(0, self.verbose - 2), target_shape=self.target_shape, memory_level=self.memory_level) self.masker_.fit(run_imgs[0]) else: if self.mask_img.mask_img_ is None and self.masker_ is None: self.masker_ = clone(self.mask_img) for param_name in ['target_affine', 'target_shape', 'smoothing_fwhm', 't_r', 'memory', 'memory_level']: our_param = getattr(self, param_name) if our_param is None: continue if getattr(self.masker_, param_name) is not None: warn('Parameter %s of the masker' ' overriden' % param_name) setattr(self.masker_, param_name, our_param) self.masker_.fit(run_imgs[0]) else: self.masker_ = self.mask_img # For each run fit the model and keep only the regression results. self.labels_, self.results_, self.design_matrices_ = [], [], [] n_runs = len(run_imgs) t0 = time.time() for run_idx, run_img in enumerate(run_imgs): # Report progress if self.verbose > 0: percent = float(run_idx) / n_runs percent = round(percent * 100, 2) dt = time.time() - t0 # We use a max to avoid a division by zero if run_idx == 0: remaining = 'go take a coffee, a big one' else: remaining = (100. - percent) / max(0.01, percent) * dt remaining = '%i seconds remaining' % remaining sys.stderr.write( "Computing run %d out of %d runs (%s)\n" % (run_idx + 1, n_runs, remaining)) # Build the experimental design for the glm run_img = check_niimg(run_img, ensure_ndim=4) if design_matrices is None: n_scans = run_img.get_data().shape[3] if confounds is not None: confounds_matrix = confounds[run_idx].values if confounds_matrix.shape[0] != n_scans: raise ValueError('Rows in confounds does not match' 'n_scans in run_img at index %d' % (run_idx,)) confounds_names = confounds[run_idx].columns.tolist() else: confounds_matrix = None confounds_names = None start_time = self.slice_time_ref * self.t_r end_time = (n_scans - 1 + self.slice_time_ref) * self.t_r frame_times = np.linspace(start_time, end_time, n_scans) design = make_first_level_design_matrix(frame_times, events[run_idx], self.hrf_model, self.drift_model, self.period_cut, self.drift_order, self.fir_delays, confounds_matrix, confounds_names, self.min_onset) else: design = design_matrices[run_idx] self.design_matrices_.append(design) # Mask and prepare data for GLM if self.verbose > 1: t_masking = time.time() sys.stderr.write('Starting masker computation \r') Y = self.masker_.transform(run_img) if self.verbose > 1: t_masking = time.time() - t_masking sys.stderr.write('Masker took %d seconds \n' % t_masking) if self.signal_scaling: Y, _ = mean_scaling(Y, self.scaling_axis) if self.memory: mem_glm = self.memory.cache(run_glm, ignore=['n_jobs']) else: mem_glm = run_glm # compute GLM if self.verbose > 1: t_glm = time.time() sys.stderr.write('Performing GLM computation\r') labels, results = mem_glm(Y, design.values, noise_model=self.noise_model, bins=100, n_jobs=self.n_jobs) if self.verbose > 1: t_glm = time.time() - t_glm sys.stderr.write('GLM took %d seconds \n' % t_glm) self.labels_.append(labels) # We save memory if inspecting model details is not necessary if self.minimize_memory: for key in results: results[key] = SimpleRegressionResults(results[key]) self.results_.append(results) del Y # Report progress if self.verbose > 0: sys.stderr.write("\nComputation of %d runs done in %i seconds\n\n" % (n_runs, time.time() - t0)) return self
def fit(self, run_imgs, paradigms=None, confounds=None, design_matrices=None): """ Fit the GLM For each run: 1. create design matrix X 2. do a masker job: fMRI_data -> Y 3. fit regression to (Y, X) Parameters ---------- run_imgs: Niimg-like object or list of Niimg-like objects, See http://nilearn.github.io/building_blocks/manipulating_mr_images.html#niimg. Data on which the GLM will be fitted. If this is a list, the affine is considered the same for all. paradigms: pandas Dataframe or string or list of pandas DataFrames or strings, fMRI paradigms used to build design matrices. One paradigm expected per run_img. Ignored in case designs is not None. confounds: pandas Dataframe or string or list of pandas DataFrames or strings, Each column in a DataFrame corresponds to a confound variable to be included in the regression model of the respective run_img. The number of rows must match the number of volumes in the respective run_img. Ignored in case designs is not None. design_matrices: pandas DataFrame or list of pandas DataFrames, Design matrices that will be used to fit the GLM. """ # Check arguments # Check imgs type if not isinstance(run_imgs, (list, tuple)): run_imgs = [run_imgs] for rimg in run_imgs: if not isinstance(rimg, (_basestring, Nifti1Image)): raise ValueError('run_imgs must be Niimg-like object or list' ' of Niimg-like objects') # check all information necessary to build design matrices is available if design_matrices is None: if paradigms is None: raise ValueError('paradigms or design matrices must be provided') if self.t_r is None: raise ValueError('t_r not given to FirstLevelModel object' ' to compute design from paradigm') else: design_matrices = _check_run_tables(run_imgs, design_matrices, 'design_matrices') # check the number of paradigm and confound files match number of runs # Also check paradigm and confound files can be loaded as DataFrame if paradigms is not None: paradigms = _check_run_tables(run_imgs, paradigms, 'paradigms') if confounds is not None: confounds = _check_run_tables(run_imgs, confounds, 'confounds') # Learn the mask if not isinstance(self.mask, NiftiMasker): self.masker_ = NiftiMasker( mask_img=self.mask, smoothing_fwhm=self.smoothing_fwhm, target_affine=self.target_affine, standardize=self.standardize, mask_strategy='epi', t_r=self.t_r, memory=self.memory, verbose=max(0, self.verbose - 1), target_shape=self.target_shape, memory_level=self.memory_level) else: self.masker_ = clone(self.mask) for param_name in ['target_affine', 'target_shape', 'smoothing_fwhm', 'low_pass', 'high_pass', 't_r', 'memory', 'memory_level']: our_param = getattr(self, param_name) if our_param is None: continue if getattr(self.masker_, param_name) is not None: warn('Parameter %s of the masker overriden' % param_name) setattr(self.masker_, param_name, our_param) self.masker_.fit(run_imgs[0]) # For each run fit the model and keep only the regression results. self.labels_, self.results_, self.design_matrices_ = [], [], [] n_runs = len(run_imgs) t0 = time.time() for run_idx, run_img in enumerate(run_imgs): # Report progress if self.verbose > 0: percent = float(run_idx) / n_runs percent = round(percent * 100, 2) dt = time.time() - t0 # We use a max to avoid a division by zero if run_idx == 0: remaining = 'go take a coffee, a big one' else: remaining = (100. - percent) / max(0.01, percent) * dt remaining = '%i seconds remaining' % remaining sys.stderr.write(" " * 100 + "\r") sys.stderr.write( "Computing run %d out of %d runs (%s)\r" % (run_idx, n_runs, remaining)) # Build the experimental design for the glm run_img = check_niimg(run_img, ensure_ndim=4) if design_matrices is None: n_scans = run_img.get_data().shape[3] if confounds is not None: confounds_matrix = confounds[run_idx].values if confounds_matrix.shape[0] != n_scans: raise ValueError('Rows in confounds does not match' 'n_scans in run_img at index %d' % (run_idx,)) confounds_names = confounds[run_idx].columns else: confounds_matrix = None confounds_names = None start_time = self.slice_time_ref * self.t_r end_time = (n_scans - 1 + self.slice_time_ref) * self.t_r frame_times = np.linspace(start_time, end_time, n_scans) design = make_design_matrix(frame_times, paradigms[run_idx], self.hrf_model, self.drift_model, self.period_cut, self.drift_order, self.fir_delays, confounds_matrix, confounds_names, self.min_onset) else: design = design_matrices[run_idx] self.design_matrices_.append(design) # Compute GLM Y = self.masker_.transform(run_img) if self.signal_scaling: Y, _ = mean_scaling(Y, self.scaling_axis) if self.memory is not None: mem_glm = self.memory.cache(run_glm) else: mem_glm = run_glm labels, results = mem_glm(Y, design, noise_model=self.noise_model, bins=100, n_jobs=self.n_jobs) self.labels_.append(labels) # We save memory if inspecting model details is not necessary if self.minimize_memory: for key in results: results[key] = SimpleRegressionResults(results[key]) self.results_.append(results) del Y # Report progress if self.verbose > 0: sys.stderr.write("\nComputation of %d runs done in %i seconds\n" % (n_runs, time.time() - t0)) return self
def fit(self, run_imgs, paradigms=None, confounds=None, design_matrices=None): """ Fit the GLM For each run: 1. create design matrix X 2. do a masker job: fMRI_data -> Y 3. fit regression to (Y, X) Parameters ---------- run_imgs: Niimg-like object or list of Niimg-like objects, See http://nilearn.github.io/building_blocks/manipulating_mr_images.html#niimg. Data on which the GLM will be fitted. If this is a list, the affine is considered the same for all. paradigms: pandas Dataframe or string or list of pandas DataFrames or strings, fMRI paradigms used to build design matrices. One paradigm expected per run_img. Ignored in case designs is not None. confounds: pandas Dataframe or string or list of pandas DataFrames or strings, Each column in a DataFrame corresponds to a confound variable to be included in the regression model of the respective run_img. The number of rows must match the number of volumes in the respective run_img. Ignored in case designs is not None. design_matrices: pandas DataFrame or list of pandas DataFrames, Design matrices that will be used to fit the GLM. """ # Check arguments # Check imgs type if not isinstance(run_imgs, (list, tuple)): run_imgs = [run_imgs] for rimg in run_imgs: if not isinstance(rimg, (_basestring, Nifti1Image)): raise ValueError('run_imgs must be Niimg-like object or list' ' of Niimg-like objects') # check all information necessary to build design matrices is available if design_matrices is None: if paradigms is None: raise ValueError( 'paradigms or design matrices must be provided') if self.t_r is None: raise ValueError('t_r not given to FirstLevelModel object' ' to compute design from paradigm') else: design_matrices = _check_run_tables(run_imgs, design_matrices, 'design_matrices') # check the number of paradigm and confound files match number of runs # Also check paradigm and confound files can be loaded as DataFrame if paradigms is not None: paradigms = _check_run_tables(run_imgs, paradigms, 'paradigms') if confounds is not None: confounds = _check_run_tables(run_imgs, confounds, 'confounds') # Learn the mask if not isinstance(self.mask, NiftiMasker): self.masker_ = NiftiMasker(mask_img=self.mask, smoothing_fwhm=self.smoothing_fwhm, target_affine=self.target_affine, standardize=self.standardize, mask_strategy='epi', t_r=self.t_r, memory=self.memory, verbose=max(0, self.verbose - 1), target_shape=self.target_shape, memory_level=self.memory_level) else: self.masker_ = clone(self.mask) for param_name in [ 'target_affine', 'target_shape', 'smoothing_fwhm', 'low_pass', 'high_pass', 't_r', 'memory', 'memory_level' ]: our_param = getattr(self, param_name) if our_param is None: continue if getattr(self.masker_, param_name) is not None: warn('Parameter %s of the masker overriden' % param_name) setattr(self.masker_, param_name, our_param) self.masker_.fit(run_imgs[0]) # For each run fit the model and keep only the regression results. self.labels_, self.results_, self.design_matrices_ = [], [], [] n_runs = len(run_imgs) t0 = time.time() for run_idx, run_img in enumerate(run_imgs): # Report progress if self.verbose > 0: percent = float(run_idx) / n_runs percent = round(percent * 100, 2) dt = time.time() - t0 # We use a max to avoid a division by zero if run_idx == 0: remaining = 'go take a coffee, a big one' else: remaining = (100. - percent) / max(0.01, percent) * dt remaining = '%i seconds remaining' % remaining sys.stderr.write(" " * 100 + "\r") sys.stderr.write("Computing run %d out of %d runs (%s)\r" % (run_idx, n_runs, remaining)) # Build the experimental design for the glm run_img = check_niimg(run_img, ensure_ndim=4) if design_matrices is None: n_scans = run_img.get_data().shape[3] if confounds is not None: confounds_matrix = confounds[run_idx].values if confounds_matrix.shape[0] != n_scans: raise ValueError('Rows in confounds does not match' 'n_scans in run_img at index %d' % (run_idx, )) confounds_names = confounds[run_idx].columns else: confounds_matrix = None confounds_names = None start_time = self.slice_time_ref * self.t_r end_time = (n_scans - 1 + self.slice_time_ref) * self.t_r frame_times = np.linspace(start_time, end_time, n_scans) design = make_design_matrix(frame_times, paradigms[run_idx], self.hrf_model, self.drift_model, self.period_cut, self.drift_order, self.fir_delays, confounds_matrix, confounds_names, self.min_onset) else: design = design_matrices[run_idx] self.design_matrices_.append(design) # Compute GLM Y = self.masker_.transform(run_img) if self.signal_scaling: Y, _ = mean_scaling(Y, self.scaling_axis) if self.memory is not None: mem_glm = self.memory.cache(run_glm) else: mem_glm = run_glm labels, results = mem_glm(Y, design, noise_model=self.noise_model, bins=100, n_jobs=self.n_jobs) self.labels_.append(labels) # We save memory if inspecting model details is not necessary if self.minimize_memory: for key in results: results[key] = SimpleRegressionResults(results[key]) self.results_.append(results) del Y # Report progress if self.verbose > 0: sys.stderr.write("\nComputation of %d runs done in %i seconds\n" % (n_runs, time.time() - t0)) return self