logo

pyleida.clustering.rsnets_overlap

Compute overlap between phase-locking states and Yeo resting-state networks

Expand source code
"""Compute overlap between phase-locking states and Yeo resting-state networks"""

import numpy as np
import pandas as pd
from scipy.stats import pearsonr
import nibabel as nib
import matplotlib.pyplot as plt
import seaborn as sns
import os

def compute_overlap(centroids,parcellation=None,n_areas=None):
    """
    Compute the overlap between the 7 resting-state networks
    defined in Yeo et al. (2011) and the brain cortical
    regions/parcels of the phase-locking states that were
    identified with K-Means clustering.

    Params:
    --------
    centroids : pd.dataframe with shape (209,n_rois+2)
        Contains the clusters centroids of
        each k partition. 
        1st column ('k') specifies the partition,
        2nd column the 'state', and rest of columns
        each brain region/parcel value.

    parcellation : str
        Specify path to your parcellation .nii file.
        Note: the parcellation must be of 2mm resolution.

    n_areas : None | int
        Analyze only the first n areas from the provided
        parcellation. 
        Usefull when the parcellation contains subcortical
        regions that must be ignored when computing the overlap
        with Yeo's cortical networks.

    Returns:
    --------
    correlations : ndarray with shape (rangeK, K_Max, 7networks).
        Contains the correlation coefficient
        between each phase-locking state and
        Yeo's 7 RSNs across the K range explored.

    pvalues : ndarray with shape (rangeK, K_Max, 7networks).
        Contains the p-values of the correlation
        coefficient between each phase-locking state
        and Yeo's 7 RSNs across the K range explored.
    """
    #validation of input data
    if isinstance(parcellation,str):
        if not parcellation.endswith(('.nii','.nii.gz')):
            raise ValueError("The parcellation must be either a .nii or .nii.gz file.")
    elif parcellation is None:
        raise ValueError("You must provide the path to the parcellation file.")
    else:
        raise TypeError("'parcellation' must be a string!")
        
    if n_areas is not None:
        if not isinstance(n_areas,int):
            raise TypeError("'n_areas' must be None or an integer!")

    #Step 1. Define the Yeo networks in the new parcellation

    #load our parcellation mask in MNI152 2mm space
    parc_user = nib.load(parcellation).get_fdata()

    if n_areas is None:
        n_areas = np.max(parc_user)
    else:
        parc_user[parc_user>n_areas] = 0 

    #load Yeo 7Networks parcellation mask in MNI152 2mm space
    yeo_path = os.path.dirname(__file__)
    parc_yeo = np.load(f'{yeo_path}/parc_MNI2mm.npz')['V_Yeo7']
    parc_yeo[parc_yeo>7] = 0 #delete cerebellum and subctx labels

    N_Yeo = np.max(parc_yeo) #number of Yeo networks
    yeo_in_user_parc = np.zeros((N_Yeo,n_areas))

    #create 7 vectors representing the 
    #7 Yeo RSNs in new parcellation scheme
    for n in range(n_areas):
        idx_n = parc_user==n+1
        for net in range(7):
            yeo_in_user_parc[net,n] = np.flatnonzero(parc_yeo[idx_n] == net+1).size / np.sum(idx_n)

    #Step 2. Compare with the LEiDA results
    kmax = 20
    krange = 19

    #create vector to store the correlation coefficients
    correlations = np.zeros((krange,kmax,N_Yeo))

    #create vector to store the coefficients' p-values
    pvalues = np.ones((krange,kmax,N_Yeo))

    for k in range(krange):
        #keep centroids for current K and
        #keep only the selected n areas
        centroids_ = centroids[centroids.k==k+2].iloc[:,2:n_areas+2].values
        centroids_[centroids_<0] = 0 #set negative values to 0

        n_centroids = centroids_.shape[0]

        for centroid_idx in range(n_centroids):
            #get current centroid
            centroid = centroids_[centroid_idx,:] 

            for yeo_net in range(N_Yeo):
                coef, pval = pearsonr(centroid,yeo_in_user_parc[yeo_net,:])

                correlations[k,centroid_idx,yeo_net] = coef
                pvalues[k,centroid_idx,yeo_net] = pval

    return correlations,pvalues

def state_overlap(correlations,pvalues,k=2,state=1,plot=True,darkstyle=False):
    """
    Return a dataframe with the correlation coefficients and 
    p-values of a particular phase-locking state with Yeo 7 
    resting-state networks.
    If plot is set to True, create a barplot showing the 
    correlation coefficient of each resting-state network.

    Params:
    -------
    correlations : ndarray with shape (rangeK, K_Max, 7networks).
        Contains the correlation coefficient between
        each phase-locking state and Yeo's 7 RSNs across
        the K range explored.

    pvalues : ndarray with shape (rangeK, K_Max, 7networks).
        Contains the p-values of the correlation
        coefficient between each phase-locking state
        and Yeo's 7 RSNs across the K range explored.

    k : int.
        Select the K-Means partition of interest.

    state : int.
        Select the phase-locking state of interest.

    plot : bool.
        Whether to create a barplot showing the correlation
        between the selected phase-locking state and the 7
        resting-state networks.

    darkstyle : bool.
        Whether to use a darkstyle for the barplot.

    Returns:
    --------
    state_data : pandas.dataframe with shape (7networks,3).
        Contains the correlation coefficient and p-value
        between the selected phase-locking state and each
        of the 7 resting-state networks from Yeo (2011).
    """
    nets = ['VIS','SMN','DAN','VAN','LIMB','CONTROL','DMN']
    colors = ['purple','royalblue','green','plum','khaki','orange','firebrick']

    state_data = pd.DataFrame(
        {
        'network':nets,
        'pcc':correlations[k-2,state-1,:7],
        'pval':pvalues[k-2,state-1,:7]
            }
        )

    if plot:
        idx = state_data['pcc']<0
        state_data['pval'][idx] = 1
        plt.ion()

        with plt.style.context("dark_background" if darkstyle else "default"):
            plt.figure(figsize=(7,3))
            sns.barplot(data=state_data,x='network',y='pcc',palette=colors)
            plt.xlabel('resting-state\nnetwork (Yeo 2011)',fontsize=16,labelpad=10)
            plt.ylabel('Pearson\ncorrelation',fontsize=16,labelpad=10)
            plt.ylim(top=1)
            plt.axhline(0,color='black' if not darkstyle else 'white')
            #add significance *
            for row_idx in range(state_data.shape[0]):
                if state_data.iloc[row_idx,-1]<0.05:
                    plt.text(x=row_idx,y=state_data.iloc[row_idx,1]+.01,s='*',fontweight='bold')
            plt.tight_layout()

    return state_data
    
def plot_yeo_pvalues(pvalues,k=2,state=1):
    """
    Create a scatter plot showing the p-values of
    correlation coefficients between the regions of
    the selected phase-locking state and the 7 RSNs
    from Yeo et al. (2011).
    
    Params:
    -------
    pvalues : ndarray with shape (rangeK, K_Max, 7networks).
        Contains the p-values of the correlation coefficient
        between each phase-locking state and Yeo's 7 RSNs across
        the K range explored.

    k : int.
        Select the 'k' partition of interest.

    state : int.
        Select the phase-locking state of interest.
    """
    nets = ['VIS','SMN','DAN','VAN','LIMB','CONTROL','DMN']
    colors = ['purple','royalblue','green','plum','khaki','orange','firebrick']
    data = pd.DataFrame({'network':nets,'pval':pvalues[k-2,state-1,:7]})
    plt.figure(figsize=(7,3))
    
    plt.scatter(np.arange(7),data.pval,c=colors)
    plt.xticks(np.arange(7),nets)
    plt.axhline(0.05,linestyle="dashed",c='firebrick',label=r'$\alpha^{1}$ = 0.05')
    plt.yscale('log')
    
    plt.xlabel('Yeo (2011) network',fontsize=16,labelpad=10)
    plt.ylabel('p-value',fontsize=16,labelpad=10)
    plt.ylim(top=1)
    plt.axhline(0,color='black')
    plt.legend(loc='best',frameon=False)
    plt.tight_layout()
    plt.show()

    return data

Functions

def compute_overlap(centroids, parcellation=None, n_areas=None)

Compute the overlap between the 7 resting-state networks defined in Yeo et al. (2011) and the brain cortical regions/parcels of the phase-locking states that were identified with K-Means clustering.

Params:

centroids : pd.dataframe with shape (209,n_rois+2) Contains the clusters centroids of each k partition. 1st column ('k') specifies the partition, 2nd column the 'state', and rest of columns each brain region/parcel value.

parcellation : str Specify path to your parcellation .nii file. Note: the parcellation must be of 2mm resolution.

n_areas : None | int Analyze only the first n areas from the provided parcellation. Usefull when the parcellation contains subcortical regions that must be ignored when computing the overlap with Yeo's cortical networks.

Returns:

correlations : ndarray with shape (rangeK, K_Max, 7networks). Contains the correlation coefficient between each phase-locking state and Yeo's 7 RSNs across the K range explored.

pvalues : ndarray with shape (rangeK, K_Max, 7networks). Contains the p-values of the correlation coefficient between each phase-locking state and Yeo's 7 RSNs across the K range explored.

Expand source code
def compute_overlap(centroids,parcellation=None,n_areas=None):
    """
    Compute the overlap between the 7 resting-state networks
    defined in Yeo et al. (2011) and the brain cortical
    regions/parcels of the phase-locking states that were
    identified with K-Means clustering.

    Params:
    --------
    centroids : pd.dataframe with shape (209,n_rois+2)
        Contains the clusters centroids of
        each k partition. 
        1st column ('k') specifies the partition,
        2nd column the 'state', and rest of columns
        each brain region/parcel value.

    parcellation : str
        Specify path to your parcellation .nii file.
        Note: the parcellation must be of 2mm resolution.

    n_areas : None | int
        Analyze only the first n areas from the provided
        parcellation. 
        Usefull when the parcellation contains subcortical
        regions that must be ignored when computing the overlap
        with Yeo's cortical networks.

    Returns:
    --------
    correlations : ndarray with shape (rangeK, K_Max, 7networks).
        Contains the correlation coefficient
        between each phase-locking state and
        Yeo's 7 RSNs across the K range explored.

    pvalues : ndarray with shape (rangeK, K_Max, 7networks).
        Contains the p-values of the correlation
        coefficient between each phase-locking state
        and Yeo's 7 RSNs across the K range explored.
    """
    #validation of input data
    if isinstance(parcellation,str):
        if not parcellation.endswith(('.nii','.nii.gz')):
            raise ValueError("The parcellation must be either a .nii or .nii.gz file.")
    elif parcellation is None:
        raise ValueError("You must provide the path to the parcellation file.")
    else:
        raise TypeError("'parcellation' must be a string!")
        
    if n_areas is not None:
        if not isinstance(n_areas,int):
            raise TypeError("'n_areas' must be None or an integer!")

    #Step 1. Define the Yeo networks in the new parcellation

    #load our parcellation mask in MNI152 2mm space
    parc_user = nib.load(parcellation).get_fdata()

    if n_areas is None:
        n_areas = np.max(parc_user)
    else:
        parc_user[parc_user>n_areas] = 0 

    #load Yeo 7Networks parcellation mask in MNI152 2mm space
    yeo_path = os.path.dirname(__file__)
    parc_yeo = np.load(f'{yeo_path}/parc_MNI2mm.npz')['V_Yeo7']
    parc_yeo[parc_yeo>7] = 0 #delete cerebellum and subctx labels

    N_Yeo = np.max(parc_yeo) #number of Yeo networks
    yeo_in_user_parc = np.zeros((N_Yeo,n_areas))

    #create 7 vectors representing the 
    #7 Yeo RSNs in new parcellation scheme
    for n in range(n_areas):
        idx_n = parc_user==n+1
        for net in range(7):
            yeo_in_user_parc[net,n] = np.flatnonzero(parc_yeo[idx_n] == net+1).size / np.sum(idx_n)

    #Step 2. Compare with the LEiDA results
    kmax = 20
    krange = 19

    #create vector to store the correlation coefficients
    correlations = np.zeros((krange,kmax,N_Yeo))

    #create vector to store the coefficients' p-values
    pvalues = np.ones((krange,kmax,N_Yeo))

    for k in range(krange):
        #keep centroids for current K and
        #keep only the selected n areas
        centroids_ = centroids[centroids.k==k+2].iloc[:,2:n_areas+2].values
        centroids_[centroids_<0] = 0 #set negative values to 0

        n_centroids = centroids_.shape[0]

        for centroid_idx in range(n_centroids):
            #get current centroid
            centroid = centroids_[centroid_idx,:] 

            for yeo_net in range(N_Yeo):
                coef, pval = pearsonr(centroid,yeo_in_user_parc[yeo_net,:])

                correlations[k,centroid_idx,yeo_net] = coef
                pvalues[k,centroid_idx,yeo_net] = pval

    return correlations,pvalues
def plot_yeo_pvalues(pvalues, k=2, state=1)

Create a scatter plot showing the p-values of correlation coefficients between the regions of the selected phase-locking state and the 7 RSNs from Yeo et al. (2011).

Params:

pvalues : ndarray with shape (rangeK, K_Max, 7networks). Contains the p-values of the correlation coefficient between each phase-locking state and Yeo's 7 RSNs across the K range explored.

k : int. Select the 'k' partition of interest.

state : int. Select the phase-locking state of interest.

Expand source code
def plot_yeo_pvalues(pvalues,k=2,state=1):
    """
    Create a scatter plot showing the p-values of
    correlation coefficients between the regions of
    the selected phase-locking state and the 7 RSNs
    from Yeo et al. (2011).
    
    Params:
    -------
    pvalues : ndarray with shape (rangeK, K_Max, 7networks).
        Contains the p-values of the correlation coefficient
        between each phase-locking state and Yeo's 7 RSNs across
        the K range explored.

    k : int.
        Select the 'k' partition of interest.

    state : int.
        Select the phase-locking state of interest.
    """
    nets = ['VIS','SMN','DAN','VAN','LIMB','CONTROL','DMN']
    colors = ['purple','royalblue','green','plum','khaki','orange','firebrick']
    data = pd.DataFrame({'network':nets,'pval':pvalues[k-2,state-1,:7]})
    plt.figure(figsize=(7,3))
    
    plt.scatter(np.arange(7),data.pval,c=colors)
    plt.xticks(np.arange(7),nets)
    plt.axhline(0.05,linestyle="dashed",c='firebrick',label=r'$\alpha^{1}$ = 0.05')
    plt.yscale('log')
    
    plt.xlabel('Yeo (2011) network',fontsize=16,labelpad=10)
    plt.ylabel('p-value',fontsize=16,labelpad=10)
    plt.ylim(top=1)
    plt.axhline(0,color='black')
    plt.legend(loc='best',frameon=False)
    plt.tight_layout()
    plt.show()

    return data
def state_overlap(correlations, pvalues, k=2, state=1, plot=True, darkstyle=False)

Return a dataframe with the correlation coefficients and p-values of a particular phase-locking state with Yeo 7 resting-state networks. If plot is set to True, create a barplot showing the correlation coefficient of each resting-state network.

Params:

correlations : ndarray with shape (rangeK, K_Max, 7networks). Contains the correlation coefficient between each phase-locking state and Yeo's 7 RSNs across the K range explored.

pvalues : ndarray with shape (rangeK, K_Max, 7networks). Contains the p-values of the correlation coefficient between each phase-locking state and Yeo's 7 RSNs across the K range explored.

k : int. Select the K-Means partition of interest.

state : int. Select the phase-locking state of interest.

plot : bool. Whether to create a barplot showing the correlation between the selected phase-locking state and the 7 resting-state networks.

darkstyle : bool. Whether to use a darkstyle for the barplot.

Returns:

state_data : pandas.dataframe with shape (7networks,3). Contains the correlation coefficient and p-value between the selected phase-locking state and each of the 7 resting-state networks from Yeo (2011).

Expand source code
def state_overlap(correlations,pvalues,k=2,state=1,plot=True,darkstyle=False):
    """
    Return a dataframe with the correlation coefficients and 
    p-values of a particular phase-locking state with Yeo 7 
    resting-state networks.
    If plot is set to True, create a barplot showing the 
    correlation coefficient of each resting-state network.

    Params:
    -------
    correlations : ndarray with shape (rangeK, K_Max, 7networks).
        Contains the correlation coefficient between
        each phase-locking state and Yeo's 7 RSNs across
        the K range explored.

    pvalues : ndarray with shape (rangeK, K_Max, 7networks).
        Contains the p-values of the correlation
        coefficient between each phase-locking state
        and Yeo's 7 RSNs across the K range explored.

    k : int.
        Select the K-Means partition of interest.

    state : int.
        Select the phase-locking state of interest.

    plot : bool.
        Whether to create a barplot showing the correlation
        between the selected phase-locking state and the 7
        resting-state networks.

    darkstyle : bool.
        Whether to use a darkstyle for the barplot.

    Returns:
    --------
    state_data : pandas.dataframe with shape (7networks,3).
        Contains the correlation coefficient and p-value
        between the selected phase-locking state and each
        of the 7 resting-state networks from Yeo (2011).
    """
    nets = ['VIS','SMN','DAN','VAN','LIMB','CONTROL','DMN']
    colors = ['purple','royalblue','green','plum','khaki','orange','firebrick']

    state_data = pd.DataFrame(
        {
        'network':nets,
        'pcc':correlations[k-2,state-1,:7],
        'pval':pvalues[k-2,state-1,:7]
            }
        )

    if plot:
        idx = state_data['pcc']<0
        state_data['pval'][idx] = 1
        plt.ion()

        with plt.style.context("dark_background" if darkstyle else "default"):
            plt.figure(figsize=(7,3))
            sns.barplot(data=state_data,x='network',y='pcc',palette=colors)
            plt.xlabel('resting-state\nnetwork (Yeo 2011)',fontsize=16,labelpad=10)
            plt.ylabel('Pearson\ncorrelation',fontsize=16,labelpad=10)
            plt.ylim(top=1)
            plt.axhline(0,color='black' if not darkstyle else 'white')
            #add significance *
            for row_idx in range(state_data.shape[0]):
                if state_data.iloc[row_idx,-1]<0.05:
                    plt.text(x=row_idx,y=state_data.iloc[row_idx,1]+.01,s='*',fontweight='bold')
            plt.tight_layout()

    return state_data