Source code for mcot.core._scripts.parcel.cluster

#!/usr/bin/env python
"""Clusters the surface based on provided features"""
from loguru import logger
from ..surface import gradient
from mcot.core.surface import CorticalMesh
from mcot.core import write_gifti
import numpy as np
from sklearn import cluster as skcluster
from mcot.core.greyordinate import GreyOrdinates


[docs]def cluster(similarity, method='spectral', n_clusters=10, **kwargs): """ Cluster based on a similarity graph :param similarity: (N, N) sparse similarity matrix :param method: clustering method ('spectral', 'affinity', or 'DBSCAN') :param n_clusters: number of clusters :return: (N, ) integer array of labels """ logger.info("Starting to cluster %s array using %s clustering", similarity.shape, method) if method.lower() == 'spectral': algorithm = skcluster.SpectralClustering(n_clusters=n_clusters, affinity='precomputed', **kwargs) elif method.lower() == 'affinity': algorithm = skcluster.AffinityPropagation(affinity='precomputed', preference=np.mean(similarity), **kwargs) elif method.lower() == 'dbscan': algorithm = skcluster.DBSCAN(metric='precomputed', n_clusters=n_clusters, **kwargs) return algorithm.fit_predict(similarity)
[docs]def run(surface, features, metric='spearman', method='spectral', n_clusters=10): """ Clusters the surface based on the provided features :param surface: anatomical surface with N vertices :param features: (M, N) array of surface features :param metric: which metric to use for the similarity between neighbouring vertices :param method: clustering method ('spectral', 'affinity', or 'DBSCAN') :param n_clusters: number of clusters :return: (N, ) integer array of labels """ sim_graph = gradient.distance(surface.graph_point_point(include_diagonal=False), features, metric=metric) return cluster(sim_graph.tocsr(), method=method, n_clusters=n_clusters)
[docs]def run_from_args(args): """ Runs the script based on a Namespace containing the command line arguments """ surface = CorticalMesh.read(args.surface) go = GreyOrdinates.from_filename(args.features) features = go.surface(surface.anatomy) mask = np.isfinite(features) labels = run( surface[mask], features[..., mask], metric=args.metric, method=args.cluster, n_clusters=args.n_clusters, ) full_labels = -np.ones(surface.nvertices, dtype=labels.dtype) full_labels[mask] = labels write_gifti(args.output, [full_labels], brain_structure=surface.anatomy, color_map={-1: ('???', (0, 0, 0, 0))})
[docs]def add_to_parser(parser): """ Creates the parser of the command line arguments """ parser.add_argument("surface", help='.surf.gii file describing the surface (WM/GM boundary, mid, or pial)') parser.add_argument("features", help='GIFTI/CIFTI file with the features of interest') parser.add_argument("output", help='.label.gii GIFTI file with the cluster labels') parser.add_argument("-m", '--metric', choices=gradient.dist_options, default='euclidean', help='how to compute the similarity with the neighbours (default: euclidean)') parser.add_argument("-c", '--cluster', choices=('spectral', 'affinity', 'dbscan'), default='spectral', help='Clustering algorithm to use') parser.add_argument("-n", "--n_clusters", type=int, default=10, help='number of clusters to fit (ignored by affinity)')