def build_masetome(est_path_iterlist, ID): """ Embeds structural-functional graph pairs into a common invariant subspace. Parameters ---------- est_path_iterlist : list List of list of pairs of file paths (.npy) corresponding to structural and functional connectomes matched at a given node resolution. ID : str A subject id or other unique identifier. References ---------- .. [1] Rosenthal, G., Váša, F., Griffa, A., Hagmann, P., Amico, E., Goñi, J., Sporns, O. (2018). Mapping higher-order relations between brain structure and function with embedded vector representations of connectomes. Nature Communications. https://doi.org/10.1038/s41467-018-04614-w """ import numpy as np from pynets.core.utils import prune_suffices from pynets.stats.embeddings import _mase_embed from pynets.core.utils import load_runconfig # Available functional and structural connectivity models hardcoded_params = load_runconfig() try: n_components = hardcoded_params["gradients"]["n_components"][0] except KeyError: import sys print("ERROR: available gradient dimensionality presets not " "sucessfully extracted from runconfig.yaml") sys.exit(1) out_paths = [] for pairs in est_path_iterlist: pop_list = [] for _file in pairs: pop_list.append(np.load(_file)) atlas = prune_suffices(pairs[0].split("/")[-3]) res = prune_suffices("_".join(pairs[0].split("/")[-1].split("modality") [1].split("_")[1:]).split("_est")[0]) if "rsn" in res: subgraph = res.split("rsn-")[1].split('_')[0] else: subgraph = "all_nodes" out_path = _mase_embed(pop_list, atlas, pairs[0], ID, subgraph_name=subgraph, n_components=n_components) out_paths.append(out_path) return out_paths
def build_masetome(est_path_iterlist, ID): """ Embeds structural-functional graph pairs into a common invariant subspace. Parameters ---------- est_path_iterlist : list List of list of pairs of file paths (.npy) corresponding to structural and functional connectomes matched at a given node resolution. ID : str A subject id or other unique identifier. References ---------- .. [1] Rosenthal, G., Váša, F., Griffa, A., Hagmann, P., Amico, E., Goñi, J., Sporns, O. (2018). Mapping higher-order relations between brain structure and function with embedded vector representations of connectomes. Nature Communications. https://doi.org/10.1038/s41467-018-04614-w """ import numpy as np from pynets.core.utils import prune_suffices from pynets.stats.embeddings import _mase_embed out_paths = [] for pairs in est_path_iterlist: pop_list = [] for _file in pairs: pop_list.append(np.load(_file)) atlas = prune_suffices(pairs[0].split("/")[-3]) res = prune_suffices("_".join(pairs[0].split("/")[-1].split("modality") [1].split("_")[1:]).split("_est")[0]) if "rsn" in res: subgraph = res.split("rsn-")[1] else: subgraph = "whole_brain" out_path = _mase_embed(pop_list, atlas, pairs[0], ID, subgraph_name=subgraph) out_paths.append(out_path) return out_paths
def build_masetome(est_path_iterlist, ID): """ Embeds structural-functional graph pairs into a common invariant subspace. Parameters ---------- est_path_iterlist : list List of list of pairs of file paths (.npy) corresponding to structural and functional connectomes matched at a given node resolution. ID : str A subject id or other unique identifier. References ---------- .. [1] Rosenthal, G., Váša, F., Griffa, A., Hagmann, P., Amico, E., Goñi, J., Sporns, O. (2018). Mapping higher-order relations between brain structure and function with embedded vector representations of connectomes. Nature Communications. https://doi.org/10.1038/s41467-018-04614-w """ from pathlib import Path import os import numpy as np from pynets.core.utils import prune_suffices from pynets.stats.embeddings import _mase_embed from pynets.core.utils import load_runconfig # Available functional and structural connectivity models hardcoded_params = load_runconfig() try: n_components = hardcoded_params["gradients"][ "n_components"][0] except KeyError: import sys print( "ERROR: available gradient dimensionality presets not " "sucessfully extracted from runconfig.yaml" ) sys.exit(1) out_paths = [] for pairs in est_path_iterlist: pop_list = [] for _file in pairs: mat = np.load(_file) if np.isfinite(mat).all(): pop_list.append(mat) if len(pop_list) != len(pairs): continue atlas = prune_suffices(pairs[0].split("/")[-3]) res = prune_suffices("_".join(pairs[0].split( "/")[-1].split("modality")[1].split("_")[1:]).split("_est")[0]) if "rsn" in res: subgraph = res.split("rsn-")[1].split('_')[0] else: subgraph = "all_nodes" out_path = _mase_embed( pop_list, atlas, pairs[0], ID, subgraph_name=subgraph, n_components=n_components) if out_path is not None: out_paths.append(out_path) else: # Add a null tmp file to prevent pool from breaking dir_path = str(Path(os.path.dirname(pairs[0]))) namer_dir = f"{dir_path}/mplx_embeddings" if os.path.isdir(namer_dir) is False: os.makedirs(namer_dir, exist_ok=True) out_path = ( f"{namer_dir}/gradient-MASE_{atlas}_{subgraph}" f"_{os.path.basename(pairs[0])}_NULL" ) if not os.path.exists(out_path): os.mknod(out_path) out_paths.append(out_path) return out_paths
def build_embedded_connectome(est_path_iterlist, ID, multimodal, embed): """ Embeds ensemble population of graphs into an embedded ensemble feature vector. Parameters ---------- est_path_iterlist : list List of file paths to .npy file containing graph with thresholding applied. ID : str A subject id or other unique identifier. multimodal : list List of booleans indicating whether multiple modalities of input data have been specified. embed : str Specifies which type of ensemble embedding will be performed. Options include `omni` and `mase`. """ import yaml from pathlib import Path from pynets.stats.embeddings import _mase_embed, _omni_embed # Available functional and structural connectivity models with open("%s%s" % (str(Path(__file__).parent.parent), '/runconfig.yaml'), 'r') as stream: hardcoded_params = yaml.load(stream) try: func_models = hardcoded_params['available_models']['func_models'] except KeyError: print( 'ERROR: available functional models not sucessfully extracted from runconfig.yaml' ) try: struct_models = hardcoded_params['available_models'][ 'struct_models'] except KeyError: print( 'ERROR: available structural models not sucessfully extracted from runconfig.yaml' ) if multimodal is True: out_path = None atlases = list( set([x.split('/')[-3].split('/')[0] for x in est_path_iterlist])) parcel_dict_func = dict.fromkeys(atlases) parcel_dict_dwi = dict.fromkeys(atlases) est_path_iterlist_dwi = list( set([ i for i in est_path_iterlist if i.split('est-')[1].split('_')[0] in struct_models ])) est_path_iterlist_func = list( set([ i for i in est_path_iterlist if i.split('est-')[1].split('_')[0] in func_models ])) func_subnets = list( set([ i.split('_est')[0].split('/')[-1] for i in est_path_iterlist_func ])) dwi_subnets = list( set([ i.split('_est')[0].split('/')[-1] for i in est_path_iterlist_dwi ])) for atlas in atlases: if len(func_subnets) > 1: parcel_dict_func[atlas] = {} for sub_net in func_subnets: parcel_dict_func[atlas][sub_net] = [] else: parcel_dict_func[atlas] = [] if len(dwi_subnets) > 1: parcel_dict_dwi[atlas] = {} for sub_net in dwi_subnets: parcel_dict_dwi[atlas][sub_net] = [] else: parcel_dict_dwi[atlas] = [] for graph_path in est_path_iterlist_dwi: if atlas in graph_path: if len(dwi_subnets) > 1: for sub_net in dwi_subnets: if sub_net in graph_path: parcel_dict_dwi[atlas][sub_net].append( graph_path) else: parcel_dict_dwi[atlas].append(graph_path) for graph_path in est_path_iterlist_func: if atlas in graph_path: if len(func_subnets) > 1: for sub_net in func_subnets: if sub_net in graph_path: parcel_dict_func[atlas][sub_net].append( graph_path) else: parcel_dict_func[atlas].append(graph_path) pop_list = [] for pop_ref in parcel_dict_func[atlas]: # RSN case if isinstance(pop_ref, dict): rsns = [i.split('_')[1] for i in list(pop_ref.keys())] i = 0 for rsn in rsns: pop_rsn_list = [] for graph in pop_ref[rsn]: pop_list.append(np.load(graph)) if len(pop_rsn_list) > 1: if len(list(set([i.shape for i in pop_rsn_list]))) > 1: raise RuntimeWarning( 'ERROR: Inconsistent number of vertices in graph population ' 'that precludes embedding') if embed == 'omni': out_path = _omni_embed(pop_list, atlas, graph_path, ID, rsns[i]) elif embed == 'mase': out_path = _mase_embed(pop_list, atlas, graph_path, ID, rsns[i]) else: raise ValueError( 'Embedding type not recognized. Presently supported options include: ' 'omni or mase') else: print( 'WARNING: Only one graph sampled, omnibus embedding not appropriate.' ) pass i = i + 1 else: pop_list.append(np.load(pop_ref)) if len(pop_list) > 1: if len(list(set([i.shape for i in pop_list]))) > 1: raise RuntimeWarning( 'ERROR: Inconsistent number of vertices in graph population that ' 'precludes embedding') if embed == 'omni': out_path = _omni_embed(pop_list, atlas, graph_path, ID) elif embed == 'mase': out_path = _mase_embed(pop_list, atlas, graph_path, ID) else: raise ValueError( 'Embedding type not recognized. Presently supported options include: ' 'omni or mase') else: print( 'WARNING: Only one graph sampled, omnibus embedding not appropriate.' ) pass pop_list = [] for pop_ref in parcel_dict_dwi[atlas]: # RSN case if isinstance(pop_ref, dict): rsns = [i.split('_')[1] for i in list(pop_ref.keys())] i = 0 for rsn in rsns: pop_rsn_list = [] for graph in pop_ref[rsn]: pop_list.append(np.load(graph)) if len(pop_rsn_list) > 1: if len(list(set([i.shape for i in pop_rsn_list]))) > 1: raise RuntimeWarning( 'ERROR: Inconsistent number of vertices in graph population ' 'that precludes embedding') if embed == 'omni': out_path = _omni_embed(pop_list, atlas, graph_path, ID, rsns[i]) elif embed == 'mase': out_path = _mase_embed(pop_list, atlas, graph_path, ID, rsns[i]) else: raise ValueError( 'Embedding type not recognized. Presently supported options include: ' 'omni or mase') else: print( 'WARNING: Only one graph sampled, omnibus embedding not appropriate.' ) pass i = i + 1 else: pop_list.append(np.load(pop_ref)) if len(pop_list) > 1: if len(list(set([i.shape for i in pop_list]))) > 1: raise RuntimeWarning( 'ERROR: Inconsistent number of vertices in graph population that ' 'precludes embedding') if embed == 'omni': out_path = _omni_embed(pop_list, atlas, graph_path, ID) elif embed == 'mase': out_path = _mase_embed(pop_list, atlas, graph_path, ID) else: raise ValueError( 'Embedding type not recognized. Presently supported options include: ' 'omni or mase') else: print( 'WARNING: Only one graph sampled, omnibus embedding not appropriate.' ) pass elif (multimodal is False) and (len(est_path_iterlist) > 1): atlases = list( set([x.split('/')[-3].split('/')[0] for x in est_path_iterlist])) parcel_dict = dict.fromkeys(atlases) subnets = list( set([ i.split('_est')[0].split('/')[-1] for i in est_path_iterlist if i.split('_est')[0].split('/')[-1] != ID ])) out_path = None for atlas in atlases: if len(subnets) > 1: parcel_dict[atlas] = {} for sub_net in subnets: parcel_dict[atlas][sub_net] = [] else: parcel_dict[atlas] = [] for graph_path in est_path_iterlist: if atlas in graph_path: if len(subnets) > 1: for sub_net in subnets: if sub_net in graph_path: parcel_dict[atlas][sub_net].append(graph_path) else: parcel_dict[atlas].append(graph_path) pop_list = [] for pop_ref in parcel_dict[atlas]: # RSN case if isinstance(pop_ref, dict): rsns = [i.split('_')[1] for i in list(pop_ref.keys())] i = 0 for rsn in rsns: pop_rsn_list = [] for graph in pop_ref[rsn]: pop_list.append(np.load(graph)) if len(pop_rsn_list) > 1: if len(list(set([i.shape for i in pop_rsn_list]))) > 1: raise RuntimeWarning( 'ERROR: Inconsistent number of vertices in graph population ' 'that precludes embedding') out_path = _omni_embed(pop_rsn_list, rsns[i]) else: print( 'WARNING: Only one graph sampled, omnibus embedding not appropriate.' ) pass i = i + 1 else: pop_list.append(np.load(pop_ref)) if len(pop_list) > 1: if len(list(set([i.shape for i in pop_list]))) > 1: raise RuntimeWarning( 'ERROR: Inconsistent number of vertices in graph population that ' 'precludes embedding') if embed == 'omni': out_path = _omni_embed(pop_list, atlas, graph_path, ID) elif embed == 'mase': out_path = _mase_embed(pop_list, atlas, graph_path, ID) else: raise ValueError( 'Embedding type not recognized. Presently supported options include: ' 'omni or mase') else: print( 'WARNING: Only one graph sampled, omnibus embedding not appropriate.' ) pass else: raise RuntimeWarning( 'ERROR: Only one graph sampled, omnibus embedding not appropriate.' ) return out_path