Source code for sekupy.utils.atlas

import numpy as np
import nibabel as ni
import os
import seaborn as sns

from mne.viz import circular_layout

import logging
logger = logging.getLogger(__name__)


currdir = os.path.dirname(os.path.abspath(__file__))
currdir = os.path.abspath(os.path.join(currdir, os.pardir))
atlasdir = os.path.join(currdir, 'io', 'data', 'atlas')


[docs] def find_roi_center(img, roi_value): """ This function gives the x,y,z coordinates of a particular ROI using the given segmented image and the image level value used to select the ROI. Parameters ---------- img : nibabel Nifti1Image instance The Nifti1Image instance of the segmented image. roi_value : int The value of the ROI as represented in the segmented image Returns ------- xyz : tuple A triplets representing the xyz coordinate of the selected ROI. """ affine = img.affine mask_ = np.int_(img.get_fdata()) == roi_value ijk_coords = np.array(np.nonzero(mask_)).mean(1) xyz_coords = ijk_coords * affine.diagonal()[:-1] + affine[:-1,-1] return xyz_coords
[docs] def get_aal_coords(fname): """Function used to obtain coordinates of the ROIs contained in the AAL90 atlas. The atlas used is the 2mm nifti version of the atlas. Parameters ---------- fname : string The path of the atlas to be used. Returns ------- coords : n x 3 numpy array The array containing n xyz coordinates in MNI space, one for each unique value of the atlas """ atlas90 = ni.load(fname) coords = [find_roi_center(atlas90, roi_value=i) for i in np.unique(atlas90.get_fdata())[:]] return np.array(coords)
[docs] def get_findlab_coords(): """ Function used to obtain coordinates of the networks contained in the findlab atlas. The atlas used is the 2mm nifti version of the atlas. Returns ------- coords : n x 3 numpy array The array containing n xyz coordinates in MNI space, one for each unique value of the atlas """ atlas_dir = os.path.join(atlasdir, 'findlab') roi_list = os.listdir(atlas_dir) roi_list.sort() findlab = [ni.load(os.path.join(atlas_dir, roi)) for roi in roi_list if roi.find("nii") != -1] f_coords = [] for img_ in findlab: centers = [find_roi_center(img_, roi_value=int(i)) for i in np.unique(img_.get_fdata())[1:]] f_coords.append(np.array(centers)) return np.vstack(f_coords)
[docs] def get_atlas90_info(background='black'): """ Utility function used to load informations about the atlas used Parameters ---------- background : string | {'black', 'white'} A string used to build colors for plots. Returns ------- names : list of string The list of ROI names. colors : list of string The list of colors used in other functions index_ : list of int How node values should be ordered if the atlas has another order (used to separate left/right in the atlas90) coords : list of tuple (x,y,z) Coordinates of the ROI center (used in plot_connectomics) networks : list of string The list of network names. """ atlas_dir = os.path.join(atlasdir, 'aal') coords = get_aal_coords(os.path.join(atlas_dir, "atlas90_mni_2mm.nii.gz")) roi_list = np.loadtxt(os.path.join(atlas_dir, "atlas90.cod"), delimiter='=', dtype=str) names = roi_list.T[1] names_inv = np.array([n[::-1] for n in names]) index_ = np.argsort(names_inv) names_lr = names[index_] names = np.array([n.replace('_', ' ') for n in names]) dict_ = {'L':'#89CC74', 'R':'#7A84CC'} colors_lr = np.array([dict_[n[:1]] for n in names_inv]) colors_lr = sns.husl_palette(2) networks = names node_angles = circular_layout(names.tolist(), names[index_].tolist(), start_pos=90, group_boundaries=[0, len(names) / 2.+1], group_sep=0.) return names, colors_lr, index_, coords, networks, node_angles
[docs] def get_findlab_info(background='black'): coords = get_findlab_coords() roi_file = os.path.join(atlasdir, 'findlab', 'findlab_rois.txt') roi_list = np.loadtxt(roi_file, delimiter=',', dtype=str) networks = roi_list.T[-2] names = roi_list.T[2] dict_ = { 'Auditory' :'lightgray', 'Basal_Ganglia' :'lavender', #'Basal_Ganglia' :'honeydew', 'LECN' :'tomato', 'Language' :'darkgrey', 'Precuneus' :'teal', 'RECN' :'lightsalmon', 'Sensorimotor' :'plum', 'Visuospatial' :'slateblue', 'anterior_Salience' :'yellowgreen', #'dorsal_DMN' :'lightsteelblue', 'dorsal_DMN' :'cadetblue', 'high_Visual' :'khaki', 'post_Salience' :'mediumseagreen', 'prim_Visual' :'gold', 'ventral_DMN' :'lightblue' } if background == 'white': dict_['anterior_Salience'] = 'gray' dict_['Basal_Ganglia'] = 'black' colors_lr = np.array([dict_[r.T[-2]] for r in roi_list]) index_ = np.arange(90) _, count_ = np.unique(networks, return_counts=True) boundaries = np.cumsum(np.hstack(([0], count_)))[:-1] node_angles = circular_layout(names.tolist(), names.tolist(), start_pos=90, group_boundaries=boundaries.tolist(), group_sep=3.5) return names, colors_lr, index_, coords, networks, node_angles
[docs] def get_aalmeg_info(background='black', grouping='LR'): """[summary] Parameters ---------- background : str, optional [description], by default 'black' grouping : str, optional [description], by default 'LR' or 'lobes' Returns ------- [type] [description] """ atlas_fname = os.path.join(atlasdir, 'aal', 'ROI_MNI_V4.nii') labels_fname = os.path.join(atlasdir, 'aal', 'ROI_MNI_V4.csv') coords = get_aal_coords(atlas_fname) labels = np.loadtxt(labels_fname, dtype=str, delimiter=',') node_names = labels.T[1][:99] if grouping == 'LR': node_idx = np.argsort(np.array([node[-1] for node in node_names])) group_boundaries = [0, len(node_names) / 2.+1] colors = sns.husl_palette(2) networks = node_names.copy() else: node_network = labels.T[3][:99] node_idx = np.argsort(node_network) networks, count = np.unique(node_network, return_counts=True) group_boundaries = np.cumsum(np.hstack(([0], count)))[:-1] color_network = sns.color_palette("Paired", len(networks)+1) colors_ = dict(zip(networks, color_network[1:])) colors = [colors_[n] for n in node_network] order = node_names[node_idx].tolist() node_angles = circular_layout(node_names.tolist(), order, start_pos=90, group_boundaries=group_boundaries, group_sep=3. ) return labels, colors, node_idx, coords, networks, node_angles
[docs] def get_eeg_channels(n_channels=159): index_ = range(n_channels) names = list() colors_lr = list() coords = list() networks = list() for i in index_: names.append("ch-%03d" % (i+1)) colors_lr.append("green") coords.append([0, 0, i]) networks.append("Brain") node_angles = circular_layout(index_, index_, start_pos=90, group_sep=3. ) return names, colors_lr, index_, coords, names, node_angles
[docs] def get_viviana_info(): network = ['DAN','VAN','SMN','VIS','AUD','LAN','DMN'] number = [6, 5, 8, 10, 4, 5, 7] color = ['lightgray', 'lavender', 'honeydew', 'tomato', 'darkgrey', 'teal', 'lightsalmon'] labels = ["%s_%02d" % (network[x], i+1) for x in range(len(network)) for i in range(number[x])] colors = [color[x] for x in range(len(network)) for i in range(number[x])] node_idx = np.arange(len(labels)) coords = np.random.randint(-20, 20, (3, len(labels))) networks = [network[x] for x in range(len(network)) for i in range(number[x])] group_boundaries = np.cumsum(np.hstack(([0], number)))[:-1] node_angles = circular_layout(labels, labels, start_pos=90, group_boundaries=group_boundaries, group_sep=3. ) return labels, colors, node_idx, coords, networks, node_angles
[docs] def get_atlas_info(atlas_name='findlab'): """This function is used to obtain information on different atlases. Parameters ---------- atlas_name : str, optional ('findlab', 'aal_meg', 'atlas90') atlas name to get information Returns ------- List of informations of the atlas: labels : names of nodes (n_nodes, string array) colors : colors of each node representing some classification node_idx : order of nodes for plot purposes coords : MNI coordinates of nodes networks : name of networks the node belongs to node_angles : angles for circular plot """ mapper = { 'findlab': get_findlab_info, 'atlas90': get_atlas90_info, 'aal_meg': get_aalmeg_info, 'viviana': get_viviana_info, 'eeg_channels': get_eeg_channels, } return mapper[atlas_name]()
[docs] def where_am_i(fname): """This function is used to find the ROI name in a mask file using AFNI whereami. Parameters ---------- fname : string, The complete filename of the mask. Returns ------- table : list The list has a lenght equal to the number of ROIs contained in the file Elements of the list: (x, y, z): coordinates of ROI's center of mass. label: name of the brain area closest to the center of mass num: number of voxels included in the ROI value: value of the ROI in the input file """ logger.info("Looking for ROI names in "+fname) img = ni.load(fname) center_711 = np.array([-70.5, -105, -60.]) data = img.get_fdata().squeeze() table = [] for f in np.unique(data)[1:]: mask_roi = data == f center_mass = np.mean(np.nonzero(mask_roi), axis=1) x,y,z = np.rint([3,3,3]*center_mass+center_711) command = "whereami %s %s %s -lpi -space TLRC -tab" %(str(x+2.), str(y+2), str(z+2)) var = os.popen(command).read() lines = var.split("\n") index = [i for i, l in enumerate(lines) if l[:5] == 'Atlas'] label1 = lines[index[0]+1] label2 = lines[index[0]+2] if label1[0] == '*': area1 = area2 = "None" else: area1 = label1.split("\t")[2] area2 = label2.split("\t")[2] table.append([x, y, z, area1, np.count_nonzero(mask_roi), f]) return table
[docs] def get_rois_names(path): import glob big_table = {} rois = glob.glob(path+"*mask.nii.gz") for fname in rois: table = where_am_i(fname) key = fname.split('/')[-1].split('.')[0][:-5] big_table[key] = table return big_table