Exemplo n.º 1
0
def test_nodemaker_tools_parlistfile_WB():
    """
    Test nodemaker_tools_parlistfile_WB functionality
    """
    # Set example inputs
    base_dir = str(Path(__file__).parent / "examples")
    parlistfile = f"{base_dir}/miscellaneous/whole_brain_cluster_labels_PCA200.nii.gz"

    start_time = time.time()
    [WB_coords, _, _] = nodemaker.get_names_and_coords_of_parcels(parlistfile)
    print("%s%s%s" % (
        'get_names_and_coords_of_parcels (User-atlas whole-brain version) --> finished: ',
        str(np.round(time.time() - start_time, 1)), 's'))

    WB_labels = np.arange(len(WB_coords) +
                          1)[np.arange(len(WB_coords) + 1) != 0].tolist()

    start_time = time.time()

    WB_parcel_list = nodemaker.gen_img_list(parlistfile)
    [WB_parcels_map_nifti,
     parcel_list_exp] = nodemaker.create_parcel_atlas(WB_parcel_list)
    print(
        "%s%s%s" %
        ('create_parcel_atlas (User-atlas whole-brain version) --> finished: ',
         str(np.round(time.time() - start_time, 1)), 's'))

    assert WB_coords is not None
    assert WB_labels is not None
    assert WB_parcel_list is not None
    assert WB_parcels_map_nifti is not None
    assert parcel_list_exp is not None
Exemplo n.º 2
0
def node_gen(coords, parcel_list, labels, dir_path, ID, parc, atlas, uatlas):
    """
    In the case that masking was not applied, this function generate nodes based on atlas definitions established by
    fetch_nodes_and_labels.

    Parameters
    ----------
    coords : list
        List of (x, y, z) tuples in mm-space corresponding to a coordinate atlas used or
        which represent the center-of-mass of each parcellation node.
    parcel_list : list
        List of 3D boolean numpy arrays or binarized Nifti1Images corresponding to ROI masks.
    labels : list
        List of string labels corresponding to ROI nodes.
    dir_path : str
        Path to directory containing subject derivative data for given run.
    ID : str
        A subject id or other unique identifier.
    parc : bool
        Indicates whether to use parcels instead of coordinates as ROI nodes.
    atlas : str
        Name of a Nilearn-hosted coordinate or parcellation/label-based atlas supported for fetching.
        See Nilearn's datasets.atlas module for more detailed reference.
    uatlas : str
        File path to atlas parcellation Nifti1Image in MNI template space.

    Returns
    -------
    net_parcels_map_nifti : Nifti1Image
        A nibabel-based nifti image consisting of a 3D array with integer voxel intensities corresponding to ROI
        membership.
    coords : list
        List of (x, y, z) tuples in mm-space corresponding to a coordinate atlas used or
        which represent the center-of-mass of each parcellation node.
    labels : list
        List of string labels corresponding to ROI nodes.
    atlas : str
        Name of a Nilearn-hosted coordinate or parcellation/label-based atlas supported for fetching.
        See Nilearn's datasets.atlas module for more detailed reference.
    uatlas : str
        File path to atlas parcellation Nifti1Image in MNI template space.
    dir_path : str
        Path to directory containing subject derivative data for given run.
    """
    try:
        import cPickle as pickle
    except ImportError:
        import _pickle as pickle
    from pynets.core import nodemaker

    [net_parcels_map_nifti, _] = nodemaker.create_parcel_atlas(parcel_list)

    coords = list(tuple(x) for x in coords)

    assert (len(coords) == len(labels) == len(
        np.unique(np.asarray(net_parcels_map_nifti.dataobj))[1:]))

    return net_parcels_map_nifti, coords, labels, atlas, uatlas, dir_path
Exemplo n.º 3
0
def test_nodemaker_tools_masking_parlistfile_RSN():
    """
    Test nodemaker_tools_masking_parlistfile_RSN functionality
    """
    # Set example inputs
    base_dir = str(Path(__file__).parent/"examples")
    dir_path = base_dir + '/002/fmri'
    func_file = dir_path + '/002.nii.gz'
    parlistfile = base_dir + '/whole_brain_cluster_labels_PCA200.nii.gz'
    roi = base_dir + '/pDMN_3_bin.nii.gz'
    network = 'Default'
    ID = '002'
    perc_overlap = 0.10
    parc = True

    start_time = time.time()
    [coords, _, _] = nodemaker.get_names_and_coords_of_parcels(parlistfile)
    print("%s%s%s" % ('get_names_and_coords_of_parcels --> finished: ',
    str(np.round(time.time() - start_time, 1)), 's'))

    labels = np.arange(len(coords) + 1)[np.arange(len(coords) + 1) != 0].tolist()

    start_time = time.time()
    parcel_list = nodemaker.gen_img_list(parlistfile)
    [net_coords, net_parcel_list, net_labels, network] = nodemaker.get_node_membership(network, func_file, coords,
                                                                                            labels, parc,
                                                                                            parcel_list)
    print("%s%s%s" % ('get_node_membership --> finished: ', str(np.round(time.time() - start_time, 1)), 's'))

    start_time = time.time()
    [net_coords_masked, net_labels_masked, net_parcel_list_masked] = nodemaker.parcel_masker(roi, net_coords,
                                                                                                  net_parcel_list,
                                                                                                  net_labels,
                                                                                                  dir_path, ID,
                                                                                                  perc_overlap)
    print("%s%s%s" % ('parcel_masker --> finished: ', str(np.round(time.time() - start_time, 1)), 's'))

    start_time = time.time()
    [net_parcels_map_nifti, parcel_list_exp] = nodemaker.create_parcel_atlas(net_parcel_list_masked)
    print("%s%s%s" % ('create_parcel_atlas --> finished: ', str(np.round(time.time() - start_time, 1)), 's'))

    start_time = time.time()
    out_path = nodemaker.gen_network_parcels(parlistfile, network, net_labels_masked, dir_path)
    print("%s%s%s" % ('gen_network_parcels --> finished: ', str(np.round(time.time() - start_time, 1)), 's'))

    assert coords is not None
    assert net_coords is not None
    assert net_labels is not None
    assert net_parcel_list is not None
    assert net_coords_masked is not None
    assert net_labels_masked is not None
    assert net_parcel_list_masked is not None
    assert out_path is not None
    assert net_parcels_map_nifti is not None
    assert parcel_list_exp is not None
    assert network is not None
Exemplo n.º 4
0
def test_nodemaker_tools_parlistfile_RSN():
    """
    Test nodemaker_tools_parlistfile_RSN functionality
    """
    import pkg_resources
    # Set example inputs
    base_dir = str(Path(__file__).parent / "examples")
    template = pkg_resources.resource_filename(
        "pynets", f"templates/MNI152_T1_brain_2mm.nii.gz")
    dir_path = f"{base_dir}/BIDS/sub-25659/ses-1/func"
    parlistfile = f"{base_dir}/miscellaneous/whole_brain_cluster_labels_PCA200.nii.gz"
    network = 'Default'
    parc = True

    start_time = time.time()
    [coords, _, _, _] = nodemaker.get_names_and_coords_of_parcels(parlistfile)
    print("%s%s%s" % ('get_names_and_coords_of_parcels --> finished: ',
                      str(np.round(time.time() - start_time, 1)), 's'))

    labels = np.arange(len(coords) +
                       1)[np.arange(len(coords) + 1) != 0].tolist()

    start_time = time.time()

    parcel_list = nodemaker.gen_img_list(parlistfile)

    [net_coords, net_parcel_list, net_labels,
     network] = nodemaker.get_node_membership(network, template, coords,
                                              labels, parc, parcel_list)
    print("%s%s%s" % ('get_node_membership --> finished: ',
                      str(np.round(time.time() - start_time, 1)), 's'))

    start_time = time.time()
    [net_parcels_map_nifti,
     parcel_list_exp] = nodemaker.create_parcel_atlas(net_parcel_list)
    print("%s%s%s" % ('create_parcel_atlas --> finished: ',
                      str(np.round(time.time() - start_time, 1)), 's'))

    start_time = time.time()
    out_path = nodemaker.gen_network_parcels(parlistfile, network, net_labels,
                                             dir_path)
    print("%s%s%s" % ('gen_network_parcels --> finished: ',
                      str(np.round(time.time() - start_time, 1)), 's'))

    assert coords is not None
    assert net_coords is not None
    assert net_labels is not None
    assert net_parcel_list is not None
    assert out_path is not None
    assert net_parcels_map_nifti is not None
    assert parcel_list_exp is not None
    assert network is not None
Exemplo n.º 5
0
def test_nodemaker_tools_parlistfile_RSN():
    """
    Test nodemaker_tools_parlistfile_RSN functionality
    """
    # Set example inputs
    base_dir = str(Path(__file__).parent / "examples")
    func_file = f"{base_dir}/BIDS/sub-0025427/ses-1/func/sub-0025427_ses-1_task-rest_space-MNI152NLin2009cAsym_desc-smoothAROMAnonaggr_bold.nii.gz"
    dir_path = f"{base_dir}/BIDS/sub-0025427/ses-1/func"
    parlistfile = f"{base_dir}/miscellaneous/whole_brain_cluster_labels_PCA200.nii.gz"
    network = 'Default'
    parc = True

    start_time = time.time()
    [coords, _, _] = nodemaker.get_names_and_coords_of_parcels(parlistfile)
    print("%s%s%s" % ('get_names_and_coords_of_parcels --> finished: ',
                      str(np.round(time.time() - start_time, 1)), 's'))

    labels = np.arange(len(coords) +
                       1)[np.arange(len(coords) + 1) != 0].tolist()

    start_time = time.time()

    parcel_list = nodemaker.gen_img_list(parlistfile)

    [net_coords, net_parcel_list, net_labels,
     network] = nodemaker.get_node_membership(network, func_file, coords,
                                              labels, parc, parcel_list)
    print("%s%s%s" % ('get_node_membership --> finished: ',
                      str(np.round(time.time() - start_time, 1)), 's'))

    start_time = time.time()
    [net_parcels_map_nifti,
     parcel_list_exp] = nodemaker.create_parcel_atlas(net_parcel_list)
    print("%s%s%s" % ('create_parcel_atlas --> finished: ',
                      str(np.round(time.time() - start_time, 1)), 's'))

    start_time = time.time()
    out_path = nodemaker.gen_network_parcels(parlistfile, network, net_labels,
                                             dir_path)
    print("%s%s%s" % ('gen_network_parcels --> finished: ',
                      str(np.round(time.time() - start_time, 1)), 's'))

    assert coords is not None
    assert net_coords is not None
    assert net_labels is not None
    assert net_parcel_list is not None
    assert out_path is not None
    assert net_parcels_map_nifti is not None
    assert parcel_list_exp is not None
    assert network is not None
Exemplo n.º 6
0
def test_nodemaker_tools_parlistfile_WB():
    """
    Test nodemaker_tools_parlistfile_WB functionality
    """
    # Set example inputs
    parlistfile = pkg_resources.resource_filename(
        "pynets", "templates/atlases/whole_brain_cluster_labels_PCA200.nii.gz")

    dir_path = str(tempfile.TemporaryDirectory().name)
    os.makedirs(dir_path, exist_ok=True)
    shutil.copy2(parlistfile, f"{dir_path}/{os.path.basename(parlistfile)}")
    parlistfile = f"{dir_path}/{os.path.basename(parlistfile)}"

    start_time = time.time()
    [WB_coords, _, _,
     _] = nodemaker.get_names_and_coords_of_parcels(parlistfile)
    print("%s%s%s" % (
        "get_names_and_coords_of_parcels (User-atlas "
        "whole-brain version) --> finished: ",
        str(np.round(time.time() - start_time, 1)),
        "s",
    ))

    WB_labels = np.arange(len(WB_coords) +
                          1)[np.arange(len(WB_coords) + 1) != 0].tolist()

    start_time = time.time()

    WB_parcel_list = nodemaker.three_to_four_parcellation(parlistfile)
    [WB_parcels_map_nifti,
     parcel_list_exp] = nodemaker.create_parcel_atlas(WB_parcel_list)
    print("%s%s%s" % (
        "create_parcel_atlas (User-atlas whole-brain version) "
        "--> finished: ",
        str(np.round(time.time() - start_time, 1)),
        "s",
    ))

    assert WB_coords is not None
    assert WB_labels is not None
    assert WB_parcel_list is not None
    assert WB_parcels_map_nifti is not None
    assert parcel_list_exp is not None
Exemplo n.º 7
0
    def parcellate(self):
        """
        API for performing any of a variety of clustering routines available through NiLearn.
        """
        import gc
        import time
        import os
        from nilearn.regions import Parcellations
        from pynets.fmri.estimation import fill_confound_nans

        start = time.time()

        if (self.clust_type == 'ward') and (self.local_corr != 'allcorr'):
            if self._local_conn_mat_path is not None:
                if not os.path.isfile(self._local_conn_mat_path):
                    raise FileNotFoundError('File containing sparse matrix of local connectivity structure not found.')
            else:
                raise FileNotFoundError('File containing sparse matrix of local connectivity structure not found.')

        if self.clust_type == 'complete' or self.clust_type == 'average' or self.clust_type == 'single' or \
            self.clust_type == 'ward' or (self.clust_type == 'rena' and self.num_conn_comps == 1) or \
                (self.clust_type == 'kmeans' and self.num_conn_comps == 1):
            self._clust_est = Parcellations(method=self.clust_type, standardize=self._standardize,
                                            detrend=self._detrending,
                                            n_parcels=self.k, mask=self._clust_mask_corr_img,
                                            connectivity=self._local_conn, mask_strategy='background', memory_level=2,
                                            random_state=42)

            if self.conf is not None:
                import pandas as pd
                confounds = pd.read_csv(self.conf, sep='\t')
                if confounds.isnull().values.any():
                    conf_corr = fill_confound_nans(confounds, self._dir_path)
                    self._clust_est.fit(self._func_img, confounds=conf_corr)
                else:
                    self._clust_est.fit(self._func_img, confounds=self.conf)
            else:
                self._clust_est.fit(self._func_img)

            self._clust_est.labels_img_.set_data_dtype(np.uint16)
            nib.save(self._clust_est.labels_img_, self.uatlas)
        elif self.clust_type == 'ncut':
            out_img = parcellate_ncut(self._local_conn, self.k, self._clust_mask_corr_img)
            out_img.set_data_dtype(np.uint16)
            nib.save(out_img, self.uatlas)
        elif self.clust_type == 'rena' or self.clust_type == 'kmeans' and self.num_conn_comps > 1:
            from pynets.core import nodemaker
            from nilearn.regions import connected_regions, Parcellations
            from nilearn.image import iter_img, new_img_like
            from pynets.core.utils import flatten, proportional

            mask_img_list = []
            mask_voxels_dict = dict()
            for i, mask_img in enumerate(list(iter_img(self._conn_comps))):
                mask_voxels_dict[i] = np.int(np.sum(np.asarray(mask_img.dataobj)))
                mask_img_list.append(mask_img)

            # Allocate k across connected components using Hagenbach-Bischoff Quota based on number of voxels
            k_list = proportional(self.k, list(mask_voxels_dict.values()))

            conn_comp_atlases = []
            print("%s%s%s" % ('Building ', len(mask_img_list), ' separate atlases with voxel-proportional nclusters '
                                                               'for each connected component...'))
            for i, mask_img in enumerate(mask_img_list):
                if k_list[i] == 0:
                    # print('0 voxels in component. Discarding...')
                    continue
                self._clust_est = Parcellations(method=self.clust_type, standardize=self._standardize,
                                                detrend=self._detrending,
                                                n_parcels=k_list[i], mask=mask_img,
                                                mask_strategy='background',
                                                memory_level=2,
                                                random_state=42)
                if self.conf is not None:
                    import pandas as pd
                    confounds = pd.read_csv(self.conf, sep='\t')
                    if confounds.isnull().values.any():
                        conf_corr = fill_confound_nans(confounds, self._dir_path)
                        self._clust_est.fit(self._func_img, confounds=conf_corr)
                    else:
                        self._clust_est.fit(self._func_img, confounds=self.conf)
                else:
                    self._clust_est.fit(self._func_img)
                conn_comp_atlases.append(self._clust_est.labels_img_)

            # Then combine the multiple atlases, corresponding to each connected component, into a single atlas
            atlas_of_atlases = []
            for atlas in conn_comp_atlases:
                bna_data = np.around(np.asarray(atlas.dataobj)).astype('uint16')

                # Get an array of unique parcels
                bna_data_for_coords_uniq = np.unique(bna_data)

                # Number of parcels:
                par_max = len(bna_data_for_coords_uniq) - 1
                img_stack = []
                for idx in range(1, par_max + 1):
                    roi_img = bna_data == bna_data_for_coords_uniq[idx].astype('uint16')
                    img_stack.append(roi_img.astype('uint16'))
                img_stack = np.array(img_stack)

                img_list = []
                for idy in range(par_max):
                    img_list.append(new_img_like(atlas, img_stack[idy]))
                atlas_of_atlases.append(img_list)
                del img_list, img_stack, bna_data

            atlas_of_atlases = list(flatten(atlas_of_atlases))

            [super_atlas_ward, _] = nodemaker.create_parcel_atlas(atlas_of_atlases)
            super_atlas_ward.set_data_dtype(np.uint16)

            nib.save(super_atlas_ward, self.uatlas)
            del atlas_of_atlases, super_atlas_ward, conn_comp_atlases, mask_img_list, mask_voxels_dict

        print("%s%s%s" % (self.clust_type, self.k, " clusters: %.2fs" % (time.time() - start)))

        del self._clust_est
        self._func_img.uncache()
        self._clust_mask_corr_img.uncache()
        gc.collect()

        return self.uatlas
Exemplo n.º 8
0
def test_nodemaker_tools_masking_parlistfile_WB():
    """
    Test nodemaker_tools_masking_parlistfile_WB functionality
    """
    # Set example inputs
    base_dir = str(Path(__file__).parent / "examples")
    dir_path = f"{base_dir}/BIDS/sub-0025427/ses-1/func"
    parlistfile = f"{base_dir}/miscellaneous/whole_brain_cluster_labels_PCA200.nii.gz"
    atlas = 'whole_brain_cluster_labels_PCA200'
    roi = f"{base_dir}/miscellaneous/pDMN_3_bin.nii.gz"
    ID = '002'
    parc = True
    perc_overlap = 0.10

    start_time = time.time()
    [WB_coords, _, _] = nodemaker.get_names_and_coords_of_parcels(parlistfile)
    print("%s%s%s" % (
        'get_names_and_coords_of_parcels (Masking whole-brain version) --> finished: ',
        str(np.round(time.time() - start_time, 1)), 's'))

    WB_labels = np.arange(len(WB_coords) +
                          1)[np.arange(len(WB_coords) + 1) != 0].tolist()

    start_time = time.time()
    WB_parcel_list = nodemaker.gen_img_list(parlistfile)
    [_, _, WB_parcel_list_masked
     ] = nodemaker.parcel_masker(roi, WB_coords, WB_parcel_list, WB_labels,
                                 dir_path, ID, perc_overlap)
    print("%s%s%s" %
          ('parcel_masker (Masking whole-brain version) --> finished: ',
           np.round(time.time() - start_time, 1), 's'))

    start_time = time.time()
    [WB_parcels_map_nifti,
     parcel_list_exp] = nodemaker.create_parcel_atlas(WB_parcel_list_masked)
    print("%s%s%s" %
          ('create_parcel_atlas (Masking whole-brain version) --> finished: ',
           np.round(time.time() - start_time, 1), 's'))

    start_time = time.time()
    [WB_net_parcels_map_nifti_unmasked, WB_coords_unmasked, _, _, _,
     dir_path] = nodemaker.node_gen(WB_coords, WB_parcel_list, WB_labels,
                                    dir_path, ID, parc, atlas, parlistfile)
    print("%s%s%s" % ('node_gen (Masking whole-brain version) --> finished: ',
                      np.round(time.time() - start_time, 1), 's'))

    start_time = time.time()
    [
        WB_net_parcels_map_nifti_masked, WB_coords_masked, WB_labels_masked, _,
        _, _
    ] = nodemaker.node_gen_masking(roi, WB_coords, WB_parcel_list, WB_labels,
                                   dir_path, ID, parc, atlas, parlistfile)

    print("%s%s%s" %
          ('node_gen_masking (Masking whole-brain version) --> finished: ',
           np.round(time.time() - start_time, 1), 's'))

    assert WB_coords is not None
    assert WB_labels is not None
    assert WB_parcel_list is not None
    assert WB_coords_masked is not None
    assert WB_labels_masked is not None
    assert WB_parcel_list_masked is not None
    assert WB_parcels_map_nifti is not None
    assert parcel_list_exp is not None
    assert WB_net_parcels_map_nifti_unmasked is not None
    assert WB_coords_unmasked is not None
    assert WB_net_parcels_map_nifti_masked is not None
    assert WB_coords_masked is not None
Exemplo n.º 9
0
def node_gen_masking(roi,
                     coords,
                     parcel_list,
                     labels,
                     dir_path,
                     ID,
                     parc,
                     atlas,
                     uatlas,
                     perc_overlap=0.75,
                     error=2):
    """
    In the case that masking was applied, this function generate nodes based on atlas definitions established by
    fetch_nodes_and_labels.

    Parameters
    ----------
    roi : str
        File path to binarized/boolean region-of-interest Nifti1Image file.
    coords : list
        List of (x, y, z) tuples in mm-space corresponding to a coordinate atlas used or
        which represent the center-of-mass of each parcellation node.
    parcel_list : list
        List of 3D boolean numpy arrays or binarized Nifti1Images corresponding to ROI masks.
    labels : list
        List of string labels corresponding to ROI nodes.
    dir_path : str
        Path to directory containing subject derivative data for given run.
    ID : str
        A subject id or other unique identifier.
    parc : bool
        Indicates whether to use parcels instead of coordinates as ROI nodes.
    atlas : str
        Name of a Nilearn-hosted coordinate or parcellation/label-based atlas supported for fetching.
        See Nilearn's datasets.atlas module for more detailed reference.
    uatlas : str
        File path to atlas parcellation Nifti1Image in MNI template space.
    perc_overlap : float
        Value 0-1 indicating a threshold of spatial overlap to use as a spatial error cushion in the case of
        evaluating mask/RSN membership from a given list of parcel masks. Default is 0.75.
    error : int
        Rounded euclidean distance, in units of voxel number, to use as a spatial error cushion in the case of
        evaluating mask/RSN membership from a given list of coordinates. Default is 4.

    Returns
    -------
    net_parcels_map_nifti : Nifti1Image
        A nibabel-based nifti image consisting of a 3D array with integer voxel intensities corresponding to ROI
        membership.
    coords : list
        List of (x, y, z) tuples in mm-space corresponding to a coordinate atlas used or
        which represent the center-of-mass of each parcellation node.
    labels : list
        List of string labels corresponding to ROI nodes.
    atlas : str
        Name of a Nilearn-hosted coordinate or parcellation/label-based atlas supported for fetching.
        See Nilearn's datasets.atlas module for more detailed reference.
    uatlas : str
        File path to atlas parcellation Nifti1Image in MNI template space.
    dir_path : str
        Path to directory containing subject derivative data for given run.
    """
    from pynets.core import nodemaker
    import os.path as op
    try:
        import cPickle as pickle
    except ImportError:
        import _pickle as pickle

    # Mask Parcels
    if parc is True:
        # For parcel masking, specify overlap thresh and error cushion in mm voxels
        [coords, labels, parcel_list_masked
         ] = nodemaker.parcel_masker(roi, coords, parcel_list, labels,
                                     dir_path, ID, perc_overlap)
        [net_parcels_map_nifti,
         _] = nodemaker.create_parcel_atlas(parcel_list_masked)
    # Mask Coordinates
    else:
        [coords, labels] = nodemaker.coords_masker(roi, coords, labels, error)
        # Save coords to pickle
        coords_path = f"{dir_path}/atlas_coords_{op.basename(roi).split('.')[0]}.pkl"
        with open(coords_path, 'wb') as f:
            pickle.dump(coords, f, protocol=2)

        net_parcels_map_nifti = None
    # Save labels to pickle
    labels_path = f"{dir_path}/atlas_labelnames_{op.basename(roi).split('.')[0]}.pkl"
    with open(labels_path, 'wb') as f:
        pickle.dump(labels, f, protocol=2)

    return net_parcels_map_nifti, coords, labels, atlas, uatlas, dir_path
Exemplo n.º 10
0
def parcel_masker(roi, coords, parcel_list, labels, dir_path, ID,
                  perc_overlap):
    """
    Evaluate the affinity of any arbitrary list of parcel nodes for a user-specified ROI mask.

    Parameters
    ----------
    roi : str
        File path to binarized/boolean region-of-interest Nifti1Image file.
    coords : list
        List of (x, y, z) tuples in mm-space corresponding to a coordinate atlas used or
        which represent the center-of-mass of each parcellation node.
    parcel_list : list
        List of 3D boolean numpy arrays or binarized Nifti1Images corresponding to ROI masks.
    labels : list
        List of string labels corresponding to ROI nodes.
    dir_path : str
        Path to directory containing subject derivative data for given run.
    ID : str
        A subject id or other unique identifier.
    perc_overlap : float
        Value 0-1 indicating a threshold of spatial overlap to use as a spatial error cushion in the case of
        evaluating ROI-mask membership from a given list of parcel masks.

    Returns
    -------
    coords_adj : list
        Filtered list of (x, y, z) tuples in mm-space with a spatial affinity for the specified ROI mask.
    labels_adj : list
        Filtered list of string labels corresponding to ROI nodes with a spatial affinity for the specified ROI mask.
    parcel_list_adj : list
        Filtered list of 3D boolean numpy arrays or binarized Nifti1Images corresponding to ROI masks with a spatial
        affinity to the specified ROI mask.
    """
    from pynets.core import nodemaker
    from nilearn.image import resample_img
    from nilearn import masking
    import os.path as op

    mask_img = nib.load(roi)
    mask_aff = mask_img.affine
    mask_data, _ = masking._load_mask_img(roi)
    mask_img.uncache()

    i = 0
    indices = []
    for parcel in parcel_list:
        parcel_vol = np.zeros(mask_data.shape, dtype=bool)
        parcel_data_reshaped = np.asarray(
            resample_img(parcel,
                         target_affine=mask_aff,
                         target_shape=mask_data.shape).dataobj)
        parcel_vol[parcel_data_reshaped == 1] = 1

        # Count number of unique voxels where overlap of parcel and mask occurs
        overlap_count = len(
            np.unique(
                np.where((mask_data.astype('uint16') == 1)
                         & (parcel_vol.astype('uint16') == 1))))

        # Count number of total unique voxels within the parcel
        total_count = len(
            np.unique(np.where((parcel_vol.astype('uint16') == 1))))

        # Calculate % overlap
        try:
            overlap = float(overlap_count / total_count)
        except:
            print(
                f"\nWarning: No overlap of parcel {labels[i]} with roi mask!\n"
            )
            overlap = float(0)

        if overlap >= perc_overlap:
            print(
                f"{(100 * overlap):.2f}{'% of parcel '}{labels[i]}{' falls within mask...'}"
            )
        else:
            indices.append(i)
        i = i + 1

    labels_adj = list(labels)
    coords_adj = list(tuple(x) for x in coords)
    parcel_list_adj = parcel_list
    try:
        for ix in sorted(indices, reverse=True):
            print(f"{'Removing: '}{labels_adj[ix]}{' at '}{coords_adj[ix]}")
            del labels_adj[ix], coords_adj[ix], parcel_list_adj[ix]
    except RuntimeError:
        print(
            'ERROR: Restrictive masking. No parcels remain after masking with brain mask/roi...'
        )

    # Create a resampled 3D atlas that can be viewed alongside mask img for QA
    resampled_parcels_nii_path = f"{dir_path}/{ID}_parcels_resampled2roimask_{op.basename(roi).split('.')[0]}.nii.gz"
    resampled_parcels_map_nifti = resample_img(
        nodemaker.create_parcel_atlas(parcel_list_adj)[0],
        target_affine=mask_aff,
        target_shape=mask_data.shape,
        interpolation='nearest')
    nib.save(resampled_parcels_map_nifti, resampled_parcels_nii_path)
    resampled_parcels_map_nifti.uncache()
    if not coords_adj:
        raise ValueError(
            '\nERROR: ROI mask was likely too restrictive and yielded < 2 remaining parcels'
        )

    return coords_adj, labels_adj, parcel_list_adj
Exemplo n.º 11
0
def parcellate(func_boot_img, local_corr, clust_type, _local_conn_mat_path,
               num_conn_comps, _clust_mask_corr_img, _standardize,
               _detrending, k, _local_conn, conf, _dir_path, _conn_comps):
    """
    API for performing any of a variety of clustering routines available
    through NiLearn.
    """
    import time
    import os
    import numpy as np
    from nilearn.regions import Parcellations
    from pynets.fmri.estimation import fill_confound_nans
    # from joblib import Memory
    import tempfile

    cache_dir = tempfile.mkdtemp()
    # memory = Memory(cache_dir, verbose=0)

    start = time.time()

    if (clust_type == "ward") and (local_corr != "allcorr"):
        if _local_conn_mat_path is not None:
            if not os.path.isfile(_local_conn_mat_path):
                raise FileNotFoundError(
                    "File containing sparse matrix of local connectivity"
                    " structure not found."
                )
        else:
            raise FileNotFoundError(
                "File containing sparse matrix of local connectivity"
                " structure not found."
            )

    if (
        clust_type == "complete"
        or clust_type == "average"
        or clust_type == "single"
        or clust_type == "ward"
        or (clust_type == "rena" and num_conn_comps == 1)
        or (clust_type == "kmeans" and num_conn_comps == 1)
    ):
        _clust_est = Parcellations(
            method=clust_type,
            standardize=_standardize,
            detrend=_detrending,
            n_parcels=k,
            mask=_clust_mask_corr_img,
            connectivity=_local_conn,
            mask_strategy="background",
            random_state=42
        )

        if conf is not None:
            import pandas as pd
            import random
            from nipype.utils.filemanip import fname_presuffix, copyfile

            out_name_conf = fname_presuffix(
                conf, suffix=f"_tmp{random.randint(1, 1000)}",
                newpath=cache_dir
            )
            copyfile(
                conf,
                out_name_conf,
                copy=True,
                use_hardlink=False)

            confounds = pd.read_csv(out_name_conf, sep="\t")
            if confounds.isnull().values.any():
                conf_corr = fill_confound_nans(confounds, _dir_path)
                try:
                    _clust_est.fit(func_boot_img, confounds=conf_corr)
                except UserWarning:
                    return None
                os.remove(conf_corr)
            else:
                try:
                    _clust_est.fit(func_boot_img, confounds=out_name_conf)
                except UserWarning:
                    return None
            os.remove(out_name_conf)
        else:
            try:
                _clust_est.fit(func_boot_img)
            except UserWarning:
                return None
        _clust_est.labels_img_.set_data_dtype(np.uint16)
        print(
            f"{clust_type}{k}"
            f"{(' clusters: %.2fs' % (time.time() - start))}"
        )

        return _clust_est.labels_img_

    elif clust_type == "ncut":
        out_img = parcellate_ncut(
            _local_conn, k, _clust_mask_corr_img
        )
        out_img.set_data_dtype(np.uint16)
        print(
            f"{clust_type}{k}"
            f"{(' clusters: %.2fs' % (time.time() - start))}"
        )
        return out_img

    elif (
        clust_type == "rena"
        or clust_type == "kmeans"
        and num_conn_comps > 1
    ):
        from pynets.core import nodemaker
        from nilearn.regions import connected_regions, Parcellations
        from nilearn.image import iter_img, new_img_like
        from pynets.core.utils import flatten, proportional

        mask_img_list = []
        mask_voxels_dict = dict()
        for i, mask_img in enumerate(iter_img(_conn_comps)):
            mask_voxels_dict[i] = np.int(
                np.sum(np.asarray(mask_img.dataobj)))
            mask_img_list.append(mask_img)

        # Allocate k across connected components using Hagenbach-Bischoff
        # Quota based on number of voxels
        k_list = proportional(k, list(mask_voxels_dict.values()))

        conn_comp_atlases = []
        print(
            f"Building {len(mask_img_list)} separate atlases with "
            f"voxel-proportional k clusters for each "
            f"connected component...")
        for i, mask_img in enumerate(iter_img(mask_img_list)):
            if k_list[i] < 5:
                print(f"Only {k_list[i]} voxels in component. Discarding...")
                continue
            _clust_est = Parcellations(
                method=clust_type,
                standardize=_standardize,
                detrend=_detrending,
                n_parcels=k_list[i],
                mask=mask_img,
                mask_strategy="background",
                random_state=i
            )
            if conf is not None:
                import pandas as pd
                import random
                from nipype.utils.filemanip import fname_presuffix, copyfile

                out_name_conf = fname_presuffix(
                    conf, suffix=f"_tmp{random.randint(1, 1000)}",
                    newpath=cache_dir
                )
                copyfile(
                    conf,
                    out_name_conf,
                    copy=True,
                    use_hardlink=False)

                confounds = pd.read_csv(out_name_conf, sep="\t")
                if confounds.isnull().values.any():
                    conf_corr = fill_confound_nans(
                        confounds, _dir_path)
                    try:
                        _clust_est.fit(func_boot_img, confounds=conf_corr)
                    except UserWarning:
                        continue
                else:
                    try:
                        _clust_est.fit(func_boot_img, confounds=conf)
                    except UserWarning:
                        continue
            else:
                try:
                    _clust_est.fit(func_boot_img)
                except UserWarning:
                    continue
            conn_comp_atlases.append(_clust_est.labels_img_)

        # Then combine the multiple atlases, corresponding to each
        # connected component, into a single atlas
        atlas_of_atlases = []
        for atlas in iter_img(conn_comp_atlases):
            bna_data = np.around(
                np.asarray(
                    atlas.dataobj)).astype("uint16")

            # Get an array of unique parcels
            bna_data_for_coords_uniq = np.unique(bna_data)

            # Number of parcels:
            par_max = len(bna_data_for_coords_uniq) - 1
            img_stack = []
            for idx in range(1, par_max + 1):
                roi_img = bna_data == bna_data_for_coords_uniq[idx].astype(
                    "uint16")
                img_stack.append(roi_img.astype("uint16"))
            img_stack = np.array(img_stack)

            img_list = []
            for idy in range(par_max):
                img_list.append(new_img_like(atlas, img_stack[idy]))
            atlas_of_atlases.append(img_list)
            del img_list, img_stack, bna_data

        atlas_of_atlases = list(flatten(atlas_of_atlases))

        [super_atlas_ward, _] = nodemaker.create_parcel_atlas(
            atlas_of_atlases)
        super_atlas_ward.set_data_dtype(np.uint16)
        del atlas_of_atlases, conn_comp_atlases, mask_img_list, \
            mask_voxels_dict

        print(
            f"{clust_type}{k}"
            f"{(' clusters: %.2fs' % (time.time() - start))}"
        )

        # memory.clear(warn=False)

        return super_atlas_ward
Exemplo n.º 12
0
def test_nodemaker_tools_parlistfile_RSN():
    """
    Test nodemaker_tools_parlistfile_RSN functionality
    """
    # Set example inputs
    template = pkg_resources.resource_filename(
        "pynets", f"templates/standard/MNI152_T1_brain_2mm.nii.gz")
    dir_path = str(tempfile.TemporaryDirectory().name)
    parlistfile = pkg_resources.resource_filename(
        "pynets", "templates/atlases/whole_brain_cluster_labels_PCA200.nii.gz")
    os.makedirs(dir_path, exist_ok=True)
    shutil.copy2(parlistfile, f"{dir_path}/{os.path.basename(parlistfile)}")
    parlistfile = f"{dir_path}/{os.path.basename(parlistfile)}"
    subnet = "Default"
    parc = True

    start_time = time.time()
    coords = nodemaker.get_names_and_coords_of_parcels(parlistfile)[0]
    print("%s%s%s" % (
        "get_names_and_coords_of_parcels --> finished: ",
        str(np.round(time.time() - start_time, 1)),
        "s",
    ))

    labels = np.arange(len(coords) +
                       1)[np.arange(len(coords) + 1) != 0].tolist()

    start_time = time.time()

    parcels_4d_img = nodemaker.three_to_four_parcellation(parlistfile)

    [net_coords, net_parcels_4d_img, net_labels, subnet] = \
        nodemaker.get_node_membership(subnet, template, coords, labels,
                                      parc, parcels_4d_img
    )
    print("%s%s%s" % (
        "get_node_membership --> finished: ",
        str(np.round(time.time() - start_time, 1)),
        "s",
    ))

    start_time = time.time()
    [net_parcels_map_nifti,
     parcel_list_exp] = nodemaker.create_parcel_atlas(net_parcels_4d_img)
    print("%s%s%s" % (
        "create_parcel_atlas --> finished: ",
        str(np.round(time.time() - start_time, 1)),
        "s",
    ))

    start_time = time.time()
    out_path = nodemaker.gen_network_parcels(parlistfile, subnet, net_labels,
                                             dir_path)
    print("%s%s%s" % (
        "gen_network_parcels --> finished: ",
        str(np.round(time.time() - start_time, 1)),
        "s",
    ))

    assert coords is not None
    assert net_coords is not None
    assert net_labels is not None
    assert net_parcels_4d_img is not None
    assert out_path is not None
    assert net_parcels_map_nifti is not None
    assert parcel_list_exp is not None
    assert subnet is not None
Exemplo n.º 13
0
def test_nodemaker_tools_masking_parlistfile_WB():
    """
    Test nodemaker_tools_masking_parlistfile_WB functionality
    """
    # Set example inputs
    parlistfile = pkg_resources.resource_filename(
        "pynets", "templates/atlases/whole_brain_cluster_labels_PCA200.nii.gz")
    dir_path = str(tempfile.TemporaryDirectory().name)
    os.makedirs(dir_path, exist_ok=True)
    shutil.copy2(parlistfile, f"{dir_path}/{os.path.basename(parlistfile)}")
    parlistfile = f"{dir_path}/{os.path.basename(parlistfile)}"

    atlas = "whole_brain_cluster_labels_PCA200"
    roi = tempfile.NamedTemporaryFile(mode="w+", suffix=".nii.gz").name
    data_gen.generate_mni_space_img()[1].to_filename(roi)
    ID = "002"
    parc = True
    perc_overlap = 0.10

    start_time = time.time()
    [WB_coords, _, _,
     _] = nodemaker.get_names_and_coords_of_parcels(parlistfile)
    print("%s%s%s" % (
        "get_names_and_coords_of_parcels (Masking whole-brain "
        "version) --> finished: ",
        str(np.round(time.time() - start_time, 1)),
        "s",
    ))

    WB_labels = np.arange(len(WB_coords) +
                          1)[np.arange(len(WB_coords) + 1) != 0].tolist()

    start_time = time.time()

    WB_parcel_list = nodemaker.three_to_four_parcellation(parlistfile)

    start_time = time.time()
    [
        WB_net_parcels_map_nifti_unmasked,
        WB_coords_unmasked,
        _,
        _,
        _,
        dir_path,
    ] = nodemaker.node_gen(WB_coords, WB_parcel_list, WB_labels, dir_path, ID,
                           parc, atlas, parlistfile)
    print("%s%s%s" % (
        "node_gen (Masking whole-brain version) --> finished: ",
        np.round(time.time() - start_time, 1),
        "s",
    ))

    start_time = time.time()
    WB_parcel_list = nodemaker.three_to_four_parcellation(parlistfile)
    [WB_parcels_map_nifti,
     parcel_list_exp] = nodemaker.create_parcel_atlas(WB_parcel_list)
    print("%s%s%s" % (
        "create_parcel_atlas (Masking whole-brain version) --> finished: ",
        np.round(time.time() - start_time, 1),
        "s",
    ))

    start_time = time.time()
    WB_parcel_list = nodemaker.three_to_four_parcellation(parlistfile)
    [
        WB_net_parcels_map_nifti_masked,
        WB_coords_masked,
        WB_labels_masked,
        _,
        _,
        _,
    ] = nodemaker.node_gen_masking(
        roi,
        WB_coords,
        WB_parcel_list,
        WB_labels,
        dir_path,
        ID,
        parc,
        atlas,
        parlistfile,
        vox_size="2mm",
    )

    WB_parcel_list = nodemaker.three_to_four_parcellation(parlistfile)
    WB_parcel_list_masked = nodemaker.parcel_masker(
        roi,
        WB_coords,
        WB_parcel_list,
        WB_labels,
        dir_path,
        ID,
        perc_overlap,
        vox_size="2mm",
    )[2]
    print("%s%s%s" % (
        "parcel_masker (Masking whole-brain version) --> "
        "finished: ",
        np.round(time.time() - start_time, 1),
        "s",
    ))

    print("%s%s%s" % (
        "node_gen_masking (Masking whole-brain version) --> "
        "finished: ",
        np.round(time.time() - start_time, 1),
        "s",
    ))

    assert WB_coords is not None
    assert WB_labels is not None
    assert WB_parcel_list is not None
    assert WB_coords_masked is not None
    assert WB_labels_masked is not None
    assert WB_parcel_list_masked is not None
    assert WB_parcels_map_nifti is not None
    assert parcel_list_exp is not None
    assert WB_net_parcels_map_nifti_unmasked is not None
    assert WB_coords_unmasked is not None
    assert WB_net_parcels_map_nifti_masked is not None
    assert WB_coords_masked is not None
Exemplo n.º 14
0
def test_nodemaker_tools_masking_parlistfile_RSN():
    """
    Test nodemaker_tools_masking_parlistfile_RSN functionality
    """
    # Set example inputs

    template = pkg_resources.resource_filename(
        "pynets", f"templates/standard/MNI152_T1_brain_2mm.nii.gz")

    tmp = tempfile.TemporaryDirectory()
    dir_path = str(tmp.name)
    os.makedirs(dir_path, exist_ok=True)
    parlistfile = pkg_resources.resource_filename(
        "pynets", "templates/atlases/whole_brain_cluster_labels_PCA200.nii.gz")
    shutil.copy2(parlistfile, f"{dir_path}/{os.path.basename(parlistfile)}")
    parlistfile = f"{dir_path}/{os.path.basename(parlistfile)}"

    roi = tempfile.NamedTemporaryFile(mode="w+", suffix=".nii.gz").name
    data_gen.generate_mni_space_img()[1].to_filename(roi)

    subnet = "Default"
    ID = "002"
    perc_overlap = 0.75
    parc = True

    start_time = time.time()
    coords = nodemaker.get_names_and_coords_of_parcels(parlistfile)[0]
    print("%s%s%s" % (
        "get_names_and_coords_of_parcels --> finished: ",
        str(np.round(time.time() - start_time, 1)),
        "s",
    ))

    labels = np.arange(len(coords) +
                       1)[np.arange(len(coords) + 1) != 0].tolist()

    start_time = time.time()
    parcels_4d_img = nodemaker.three_to_four_parcellation(parlistfile)
    [net_coords, net_parcels_4d_img, net_labels, subnet] = \
        nodemaker.get_node_membership(
        subnet, template, coords, labels, parc, parcels_4d_img
    )
    print("%s%s%s" % (
        "get_node_membership --> finished: ",
        str(np.round(time.time() - start_time, 1)),
        "s",
    ))

    start_time = time.time()
    [
        net_coords_masked,
        net_labels_masked,
        net_parcels_4d_img_masked,
    ] = nodemaker.parcel_masker(
        roi,
        net_coords,
        net_parcels_4d_img,
        net_labels,
        dir_path,
        ID,
        perc_overlap,
        vox_size="2mm",
    )
    print("%s%s%s" % (
        "parcel_masker --> finished: ",
        str(np.round(time.time() - start_time, 1)),
        "s",
    ))

    start_time = time.time()
    [net_parcels_map_nifti, parcel_list_exp
     ] = nodemaker.create_parcel_atlas(net_parcels_4d_img_masked)
    print("%s%s%s" % (
        "create_parcel_atlas --> finished: ",
        str(np.round(time.time() - start_time, 1)),
        "s",
    ))

    start_time = time.time()
    out_path = nodemaker.gen_network_parcels(parlistfile, subnet,
                                             net_labels_masked, dir_path)
    print("%s%s%s" % (
        "gen_network_parcels --> finished: ",
        str(np.round(time.time() - start_time, 1)),
        "s",
    ))

    assert coords is not None
    assert net_coords is not None
    assert net_labels is not None
    assert net_parcels_4d_img is not None
    assert net_coords_masked is not None
    assert net_labels_masked is not None
    assert net_parcels_4d_img_masked is not None
    assert out_path is not None
    assert net_parcels_map_nifti is not None
    assert parcel_list_exp is not None
    assert subnet is not None
    tmp.cleanup()
Exemplo n.º 15
0
    def parcellate(self, func_boot_img):
        """
        API for performing any of a variety of clustering routines available
        through NiLearn.
        """
        import time
        import os
        from nilearn.regions import Parcellations
        from pynets.fmri.estimation import fill_confound_nans

        start = time.time()

        if (self.clust_type == "ward") and (self.local_corr != "allcorr"):
            if self._local_conn_mat_path is not None:
                if not os.path.isfile(self._local_conn_mat_path):
                    raise FileNotFoundError(
                        "File containing sparse matrix of local connectivity"
                        " structure not found.")
            else:
                raise FileNotFoundError(
                    "File containing sparse matrix of local connectivity"
                    " structure not found.")

        if (self.clust_type == "complete" or self.clust_type == "average"
                or self.clust_type == "single" or self.clust_type == "ward"
                or (self.clust_type == "rena" and self.num_conn_comps == 1)
                or (self.clust_type == "kmeans" and self.num_conn_comps == 1)):
            _clust_est = Parcellations(
                method=self.clust_type,
                standardize=self._standardize,
                detrend=self._detrending,
                n_parcels=self.k,
                mask=self._clust_mask_corr_img,
                connectivity=self._local_conn,
                mask_strategy="background",
                memory_level=2,
                random_state=42,
            )

            if self.conf is not None:
                import pandas as pd

                confounds = pd.read_csv(self.conf, sep="\t")
                if confounds.isnull().values.any():
                    conf_corr = fill_confound_nans(confounds, self._dir_path)
                    _clust_est.fit(func_boot_img, confounds=conf_corr)
                else:
                    _clust_est.fit(func_boot_img, confounds=self.conf)
            else:
                _clust_est.fit(func_boot_img)

            _clust_est.labels_img_.set_data_dtype(np.uint16)
            print(f"{self.clust_type}{self.k}"
                  f"{(' clusters: %.2fs' % (time.time() - start))}")
            return _clust_est.labels_img_

        elif self.clust_type == "ncut":
            out_img = parcellate_ncut(self._local_conn, self.k,
                                      self._clust_mask_corr_img)
            out_img.set_data_dtype(np.uint16)
            print(f"{self.clust_type}{self.k}"
                  f"{(' clusters: %.2fs' % (time.time() - start))}")
            return out_img

        elif (self.clust_type == "rena"
              or self.clust_type == "kmeans" and self.num_conn_comps > 1):
            from pynets.core import nodemaker
            from nilearn.regions import connected_regions, Parcellations
            from nilearn.image import iter_img, new_img_like
            from pynets.core.utils import flatten, proportional

            mask_img_list = []
            mask_voxels_dict = dict()
            for i, mask_img in enumerate(list(iter_img(self._conn_comps))):
                mask_voxels_dict[i] = np.int(
                    np.sum(np.asarray(mask_img.dataobj)))
                mask_img_list.append(mask_img)

            # Allocate k across connected components using Hagenbach-Bischoff
            # Quota based on number of voxels
            k_list = proportional(self.k, list(mask_voxels_dict.values()))

            conn_comp_atlases = []
            print(f"Building {len(mask_img_list)} separate atlases with "
                  f"voxel-proportional k clusters for each "
                  f"connected component...")
            for i, mask_img in enumerate(mask_img_list):
                if k_list[i] == 0:
                    # print('0 voxels in component. Discarding...')
                    continue
                _clust_est = Parcellations(
                    method=self.clust_type,
                    standardize=self._standardize,
                    detrend=self._detrending,
                    n_parcels=k_list[i],
                    mask=mask_img,
                    mask_strategy="background",
                    memory_level=2,
                    random_state=42,
                )
                if self.conf is not None:
                    import pandas as pd

                    confounds = pd.read_csv(self.conf, sep="\t")
                    if confounds.isnull().values.any():
                        conf_corr = fill_confound_nans(confounds,
                                                       self._dir_path)
                        _clust_est.fit(func_boot_img, confounds=conf_corr)
                    else:
                        _clust_est.fit(func_boot_img, confounds=self.conf)
                else:
                    _clust_est.fit(func_boot_img)
                conn_comp_atlases.append(_clust_est.labels_img_)

            # Then combine the multiple atlases, corresponding to each
            # connected component, into a single atlas
            atlas_of_atlases = []
            for atlas in conn_comp_atlases:
                bna_data = np.around(np.asarray(
                    atlas.dataobj)).astype("uint16")

                # Get an array of unique parcels
                bna_data_for_coords_uniq = np.unique(bna_data)

                # Number of parcels:
                par_max = len(bna_data_for_coords_uniq) - 1
                img_stack = []
                for idx in range(1, par_max + 1):
                    roi_img = bna_data == bna_data_for_coords_uniq[idx].astype(
                        "uint16")
                    img_stack.append(roi_img.astype("uint16"))
                img_stack = np.array(img_stack)

                img_list = []
                for idy in range(par_max):
                    img_list.append(new_img_like(atlas, img_stack[idy]))
                atlas_of_atlases.append(img_list)
                del img_list, img_stack, bna_data

            atlas_of_atlases = list(flatten(atlas_of_atlases))

            [super_atlas_ward,
             _] = nodemaker.create_parcel_atlas(atlas_of_atlases)
            super_atlas_ward.set_data_dtype(np.uint16)
            del atlas_of_atlases, conn_comp_atlases, mask_img_list, \
                mask_voxels_dict

            print(f"{self.clust_type}{self.k}"
                  f"{(' clusters: %.2fs' % (time.time() - start))}")
            return super_atlas_ward