def test_parcellations_fit_on_multi_nifti_images(): data = np.zeros((10, 11, 12, 5)) data[9, 10, 2] = 1 data[4, 9, 3] = 2 fmri_img = nibabel.Nifti1Image(data, affine=np.eye(4)) # List of fmri images fmri_imgs = [fmri_img, fmri_img, fmri_img] parcellator = Parcellations(method='kmeans', n_parcels=5) parcellator.fit(fmri_imgs) assert_true(parcellator.labels_img_ is not None) parcellator = Parcellations(method='ward', n_parcels=5) parcellator.fit(fmri_imgs) assert_true(parcellator.labels_img_ is not None) # Smoke test with explicit mask image mask_img = np.ones((10, 11, 12)) mask_img = nibabel.Nifti1Image(mask_img, np.eye(4)) parcellator = Parcellations(method='kmeans', n_parcels=5, mask=mask_img) parcellator.fit(fmri_imgs) parcellator = Parcellations(method='ward', n_parcels=5, mask=mask_img) parcellator.fit(fmri_imgs)
def test_parcellations_fit_on_multi_nifti_images(method, test_image): fmri_imgs = [test_image] * 3 parcellator = Parcellations(method=method, n_parcels=5) parcellator.fit(fmri_imgs) assert parcellator.labels_img_ is not None # Smoke test with explicit mask image mask_img = np.ones((10, 11, 12)) mask_img = nibabel.Nifti1Image(mask_img, np.eye(4)) parcellator = Parcellations(method=method, n_parcels=5, mask=mask_img) parcellator.fit(fmri_imgs)
def test_parcellations_no_warnings(): data = np.zeros((10, 11, 12, 5)) img = nibabel.Nifti1Image(data, affine=np.eye(4)) parcellator = Parcellations(method='kmeans', n_parcels=1) with pytest.warns(None) as record: parcellator.fit(img) assert all([r.category is not UserWarning for r in record.list])
def test_parcellations_transform_single_nifti_image(): # Test with NiftiLabelsMasker extraction of timeseries data # after building a parcellations image # Here, data has ones. zeros will be considered as background labels # not foreground labels data = np.ones((10, 11, 12, 8)) data[6, 7, 8] = 2 data[9, 10, 11] = 3 parcels = 5 fmri_img = nibabel.Nifti1Image(data, affine=np.eye(4)) for method in ['kmeans', 'ward', 'complete', 'average', 'rena']: parcellator = Parcellations(method=method, n_parcels=parcels) parcellator.fit(fmri_img) # transform to signals signals = parcellator.transform(fmri_img) # Test if the signals extracted are of same shape as inputs # Here, we simply return numpy array for single subject input assert signals.shape == (fmri_img.shape[3], parcels) # Test for single subject but in a list. signals = parcellator.transform([fmri_img]) assert signals.shape == (fmri_img.shape[3], parcels)
def test_inverse_transform_single_nifti_image(): data = np.ones((10, 11, 12, 10)) data[6, 7, 8] = 2 data[9, 10, 11] = 3 fmri_img = nibabel.Nifti1Image(data, affine=np.eye(4)) methods = ['kmeans', 'ward', 'complete', 'average', 'rena'] for method in methods: parcellate = Parcellations(method=method, n_parcels=5) # Fit parcellate.fit(fmri_img) assert parcellate.labels_img_ is not None # Transform fmri_reduced = parcellate.transform(fmri_img) assert isinstance(fmri_reduced, np.ndarray) # Shape matching with (scans, regions) assert fmri_reduced.shape, (10, 5) # Inverse transform fmri_compressed = parcellate.inverse_transform(fmri_reduced) # A single Nifti image for single subject input assert isinstance(fmri_compressed, nibabel.Nifti1Image) # returns shape of fmri_img assert fmri_compressed.shape, (10, 11, 12, 10) # fmri_reduced in a list fmri_compressed = parcellate.inverse_transform([fmri_reduced]) # A single Nifti image for single subject input assert isinstance(fmri_compressed, nibabel.Nifti1Image) # returns shape of fmri_img assert fmri_compressed.shape, (10, 11, 12, 10)
def test_parcellations_fit_on_single_nifti_image(): # Test return attributes for each method data = np.zeros((10, 11, 12, 5)) data[9, 10, 2] = 1 data[4, 9, 3] = 2 fmri_img = nibabel.Nifti1Image(data, affine=np.eye(4)) methods = ['kmeans', 'ward', 'complete', 'average', 'rena'] n_parcels = [5, 10, 15] for n_parcel, method in zip(n_parcels, methods): parcellator = Parcellations(method=method, n_parcels=n_parcel) parcellator.fit(fmri_img) # Test that object returns attribute labels_img_ assert parcellator.labels_img_ is not None # Test object returns attribute masker_ assert parcellator.masker_ is not None assert parcellator.mask_img_ is not None if method not in ['kmeans', 'rena']: # Test that object returns attribute connectivity_ # only for AgglomerativeClustering methods assert parcellator.connectivity_ is not None labels_img = parcellator.labels_img_ assert parcellator.labels_img_ is not None # After inverse_transform, shape must match with original input # data assert labels_img.shape, (data.shape[0], data.shape[1], data.shape[2])
def test_errors_raised_in_check_parameters_fit(method, test_image): """Test whether an error is raised or not given a false method type. """ with pytest.raises(ValueError, match=("The method you have selected " "is not implemented '{0}'".format(method))): Parcellations(method=method).fit(test_image)
def test_errors_raised_in_check_parameters_fit(): # Test whether an error is raised or not given # a false method type # valid_methods = ['kmeans', 'ward', 'complete', 'average'] data = np.zeros((6, 7, 8, 5)) img = nibabel.Nifti1Image(data, affine=np.eye(4)) method_raise1 = Parcellations(method=None) assert_raises_regex(ValueError, "Parcellation method is specified as None. ", method_raise1.fit, img) for invalid_method in ['kmens', 'avg', 'complte']: method_raise2 = Parcellations(method=invalid_method) msg = ("The method you have selected is not implemented " "'{0}'".format(invalid_method)) assert_raises_regex(ValueError, msg, method_raise2.fit, img)
def test_parcellations_transform_multi_nifti_images(method, n_parcel, test_image_2): fmri_imgs = [test_image_2] * 3 parcellator = Parcellations(method=method, n_parcels=n_parcel) parcellator.fit(fmri_imgs) # transform multi images to signals. # In return, we have length equal to the number of images signals = parcellator.transform(fmri_imgs) assert signals[0].shape == (test_image_2.shape[3], n_parcel) assert signals[1].shape == (test_image_2.shape[3], n_parcel) assert signals[2].shape == (test_image_2.shape[3], n_parcel) assert len(signals) == len(fmri_imgs)
def test_parcellations_transform_with_multi_confounds_multi_images( method, n_parcel, test_image_2): # noqa: E501 rng = np.random.RandomState(42) fmri_imgs = [test_image_2] * 3 confounds = rng.standard_normal(size=(10, 3)) confounds_list = [confounds] * 3 parcellator = Parcellations(method=method, n_parcels=n_parcel) parcellator.fit(fmri_imgs) signals = parcellator.transform(fmri_imgs, confounds=confounds_list) assert isinstance(signals, list) # n_parcels=5, length of data=10 assert signals[0].shape == (10, n_parcel)
def test_parcellations_transform_single_nifti_image(method, n_parcel, test_image_2): """Test with NiftiLabelsMasker extraction of timeseries data after building a parcellations image.""" parcellator = Parcellations(method=method, n_parcels=n_parcel) parcellator.fit(test_image_2) # transform to signals signals = parcellator.transform(test_image_2) # Test if the signals extracted are of same shape as inputs # Here, we simply return numpy array for single subject input assert signals.shape == (test_image_2.shape[3], n_parcel) # Test for single subject but in a list. signals = parcellator.transform([test_image_2]) assert signals.shape == (test_image_2.shape[3], n_parcel)
def test_fit_transform(method, n_parcel, test_image_2): rng = np.random.RandomState(42) fmri_imgs = [test_image_2] * 3 confounds = rng.standard_normal(size=(10, 3)) confounds_list = [confounds] * 3 parcellator = Parcellations(method=method, n_parcels=n_parcel) signals = parcellator.fit_transform(fmri_imgs) assert parcellator.labels_img_ is not None if method not in ['kmeans', 'rena', 'hierarchical_kmeans']: assert parcellator.connectivity_ is not None assert parcellator.masker_ is not None # fit_transform with confounds signals = parcellator.fit_transform(fmri_imgs, confounds=confounds_list) assert isinstance(signals, list) assert signals[0].shape == (10, n_parcel)
def test_parcellations_fit_on_single_nifti_image(method, n_parcel, test_image): """Test return attributes for each method.""" parcellator = Parcellations(method=method, n_parcels=n_parcel) parcellator.fit(test_image) # Test that object returns attribute labels_img_ labels_img = parcellator.labels_img_ assert labels_img is not None # After inverse_transform, shape must match with # original input data assert labels_img.shape == test_image.shape[:3] # Test object returns attribute masker_ assert parcellator.masker_ is not None assert parcellator.mask_img_ is not None if method not in ['kmeans', 'rena', 'hierarchical_kmeans']: # Test that object returns attribute connectivity_ # only for AgglomerativeClustering methods assert parcellator.connectivity_ is not None
def test_inverse_transform_single_nifti_image(method, n_parcel, test_image_2): parcellate = Parcellations(method=method, n_parcels=n_parcel) parcellate.fit(test_image_2) assert parcellate.labels_img_ is not None fmri_reduced = parcellate.transform(test_image_2) assert isinstance(fmri_reduced, np.ndarray) # Shape matching with (scans, regions) assert fmri_reduced.shape == (10, n_parcel) fmri_compressed = parcellate.inverse_transform(fmri_reduced) # A single Nifti image for single subject input assert isinstance(fmri_compressed, nibabel.Nifti1Image) # returns shape of fmri_img assert fmri_compressed.shape == test_image_2.shape # fmri_reduced in a list fmri_compressed = parcellate.inverse_transform([fmri_reduced]) # A single Nifti image for single subject input assert isinstance(fmri_compressed, nibabel.Nifti1Image) # returns shape of fmri_img assert fmri_compressed.shape == test_image_2.shape
def test_transform_3d_input_images(): # test list of 3D images data = np.ones((10, 11, 12)) data[6, 7, 8] = 2 data[9, 10, 11] = 3 img = nibabel.Nifti1Image(data, affine=np.eye(4)) imgs = [img] * 3 parcellate = Parcellations(method='ward', n_parcels=20) X = parcellate.fit_transform(imgs) assert isinstance(X, list) # (number of samples, number of features) assert np.concatenate(X).shape == (3, 20) # inverse transform imgs_ = parcellate.inverse_transform(X) assert isinstance(imgs_, list) # test single 3D image X = parcellate.fit_transform(imgs[0]) assert isinstance(X, np.ndarray) assert X.shape == (1, 20)
def test_parcellations_transform_with_multi_confounds_multi_images(): rng = np.random.RandomState(42) data = np.ones((10, 11, 12, 10)) data[6, 7, 8] = 2 data[9, 10, 11] = 3 fmri_img = nibabel.Nifti1Image(data, affine=np.eye(4)) fmri_imgs = [fmri_img, fmri_img, fmri_img] confounds = rng.standard_normal(size=(10, 3)) confounds_list = (confounds, confounds, confounds) for method in ['kmeans', 'ward', 'complete', 'average', 'rena']: parcellator = Parcellations(method=method, n_parcels=5) parcellator.fit(fmri_imgs) signals = parcellator.transform(fmri_imgs, confounds=confounds_list) assert isinstance(signals, list) # n_parcels=5, length of data=10 assert signals[0].shape == (10, 5)
def test_parcellations_transform_multi_nifti_images(): data = np.ones((10, 11, 12, 10)) data[6, 7, 8] = 2 data[9, 10, 11] = 3 parcels = 5 fmri_img = nibabel.Nifti1Image(data, affine=np.eye(4)) fmri_imgs = [fmri_img, fmri_img, fmri_img] for method in ['kmeans', 'ward', 'complete', 'average', 'rena']: parcellator = Parcellations(method=method, n_parcels=parcels) parcellator.fit(fmri_imgs) # transform multi images to signals. In return, we have length # equal to the number of images signals = parcellator.transform(fmri_imgs) assert signals[0].shape == (fmri_img.shape[3], parcels) assert signals[1].shape == (fmri_img.shape[3], parcels) assert signals[2].shape == (fmri_img.shape[3], parcels) assert len(signals) == len(fmri_imgs)
def test_fit_transform(): rng = np.random.RandomState(42) data = np.ones((10, 11, 12, 10)) data[6, 7, 8] = 2 data[9, 10, 11] = 3 fmri_img = nibabel.Nifti1Image(data, affine=np.eye(4)) fmri_imgs = [fmri_img, fmri_img, fmri_img] confounds = rng.standard_normal(size=(10, 3)) confounds_list = [confounds, confounds, confounds] for method in ['kmeans', 'ward', 'complete', 'average', 'rena']: parcellator = Parcellations(method=method, n_parcels=5) signals = parcellator.fit_transform(fmri_imgs) assert parcellator.labels_img_ is not None if method not in ['kmeans', 'rena']: assert parcellator.connectivity_ is not None assert parcellator.masker_ is not None # fit_transform with confounds signals = parcellator.fit_transform(fmri_imgs, confounds=confounds_list) assert isinstance(signals, list) assert signals[0].shape == (10, 5)
def test_parcellations_no_warnings(test_empty_image): parcellator = Parcellations(method='kmeans', n_parcels=1) with pytest.warns(None) as record: parcellator.fit(test_empty_image) assert all([r.category is not UserWarning for r in record.list])
def test_parcellations_warnings(): data = np.zeros((10, 11, 12, 5)) img = nibabel.Nifti1Image(data, affine=np.eye(4)) parcellator = Parcellations(method='kmeans', n_parcels=7) with pytest.warns(UserWarning): parcellator.fit(img)
def test_error_parcellation_method_none(test_image): with pytest.raises(ValueError, match="Parcellation method is specified as None. "): Parcellations(method=None).fit(test_image)
def _make_parcellation(imgs, clustering_index, clustering, n_pieces, masker, smoothing_fwhm=5, verbose=0): """Convenience function to use nilearn Parcellation class in our pipeline. It is used to find local regions of the brain in which alignment will be later applied. For alignment computational efficiency, regions should be of hundreds of voxels. Parameters ---------- imgs: Niimgs data to cluster clustering_index: list of integers Clustering is performed on a subset of the data chosen randomly in timeframes. This index carries this subset. clustering: string or 3D Niimg In : {'kmeans', 'ward', 'rena'}, passed to nilearn Parcellations class. If you aim for speed, choose k-means (and check kmeans_smoothing_fwhm parameter) If you want spatially connected and/or reproducible regions use 'ward' If you want balanced clusters (especially from timeseries) used 'hierarchical_kmeans' For 'rena', need nilearn > 0.5.2 If 3D Niimg, image used as predefined clustering, n_pieces is ignored n_pieces: int number of different labels masker: instance of NiftiMasker or MultiNiftiMasker Masker to be used on the data. For more information see: http://nilearn.github.io/manipulating_images/masker_objects.html smoothing_fwhm: None or int By default 5mm smoothing will be applied before kmeans clustering to have more compact clusters (but this will not change the data later). To disable this option, this parameter should be None. Returns ------- labels : list of ints (len n_features) Parcellation of features in clusters """ # check if clustering is provided if type(clustering) == nib.nifti1.Nifti1Image or os.path.isfile( clustering): _check_same_fov(masker.mask_img_, clustering) labels = _apply_mask_fmri(clustering, masker.mask_img_).astype(int) # otherwise check it's needed, if not return 1 everywhere elif n_pieces == 1: labels = np.ones(int(masker.mask_img_.get_fdata().sum()), dtype=np.int8) # otherwise check requested clustering method elif clustering == "hierarchical_kmeans" and n_pieces > 1: imgs_subset = index_img(imgs, clustering_index) if smoothing_fwhm is not None: X = masker.transform(smooth_img(imgs_subset, smoothing_fwhm)) else: X = masker.transform(imgs_subset) labels = _hierarchical_k_means( X.T, n_clusters=n_pieces, verbose=verbose) + 1 elif clustering in ['kmeans', 'ward', 'rena'] and n_pieces > 1: imgs_subset = index_img(imgs, clustering_index) if clustering == "kmeans" and smoothing_fwhm is not None: images_to_parcel = smooth_img(imgs_subset, smoothing_fwhm) else: images_to_parcel = imgs_subset try: parcellation = Parcellations(method=clustering, n_parcels=n_pieces, mask=masker, scaling=False, n_iter=20, verbose=verbose) except TypeError: if clustering == "rena" and (version.parse(nilearn.__version__) <= version.parse("0.5.2")): raise InputError(( 'ReNA algorithm is only available in Nilearn version > 0.5.2. \ Your version is {}. If you want to use ReNA, please run "pip install nilearn --upgrade"' .format(nilearn.__version__))) else: parcellation = Parcellations(method=clustering, n_parcels=n_pieces, mask=masker, verbose=verbose) parcellation.fit(images_to_parcel) labels = _apply_mask_fmri(parcellation.labels_img_, masker.mask_img_).astype(int) else: raise InputError(( 'Clustering should be "kmeans", "ward", "rena", "hierarchical_kmeans", \ or a 3D Niimg, and n_pieces should be an integer ≥ 1')) if verbose > 0: unique_labels, counts = np.unique(labels, return_counts=True) print("The alignment will be applied on parcels of sizes {}".format( counts)) # raise warning if some parcels are bigger than 1000 voxels _check_labels(labels) return labels
def test_parcellations_warnings(test_empty_image): parcellator = Parcellations(method='kmeans', n_parcels=7) with pytest.warns(UserWarning): parcellator.fit(test_empty_image)