def normalize_graph(self): import graspologic.utils as gu # By maximum edge weight if self.norm == 1: self.in_mat = thresholding.normalize(np.nan_to_num(self.in_mat)) # Apply log10 elif self.norm == 2: self.in_mat = np.log10(np.nan_to_num(self.in_mat)) # Apply PTR simple-nonzero elif self.norm == 3: self.in_mat = gu.ptr.pass_to_ranks(np.nan_to_num(self.in_mat), method="simple-nonzero") # Apply PTR simple-all elif self.norm == 4: self.in_mat = gu.ptr.pass_to_ranks(np.nan_to_num(self.in_mat), method="simple-all") # Apply PTR zero-boost elif self.norm == 5: self.in_mat = gu.ptr.pass_to_ranks(np.nan_to_num(self.in_mat), method="zero-boost") # Apply standardization [0, 1] elif self.norm == 6: self.in_mat = thresholding.standardize(np.nan_to_num(self.in_mat)) elif self.norm == 7: # Get hyperbolic tangent (i.e. fischer r-to-z transform) of matrix # if non-covariance self.in_mat = np.arctanh(self.in_mat) else: pass self.in_mat = thresholding.autofix(self.in_mat) self.G = nx.from_numpy_array(self.in_mat) return self.G
def __init__(self, est_path, prune, norm, out_fmt="gpickle", remove_self_loops=True): import graspologic.utils as gu self.est_path = est_path self.prune = prune self.norm = norm self.out_fmt = out_fmt self.in_mat = None # Load and threshold matrix self.in_mat_raw = utils.load_mat(self.est_path) # De-diagnal and remove nan's and inf's, ensure edge weights are # positive self.in_mat = np.array( np.array(thresholding.autofix(np.array(np.abs(self.in_mat_raw))))) # Remove self-loops and ensure symmetry if remove_self_loops is True: self.in_mat = gu.remove_loops(gu.symmetrize(self.in_mat)) else: self.in_mat = gu.symmetrize(self.in_mat) self.in_mat[np.where(np.isnan(self.in_mat) | np.isinf(self.in_mat))] = 0 # Create nx graph self.G = nx.from_numpy_array(self.in_mat)
def plot_all_struct(conn_matrix, conn_model, atlas, dir_path, ID, network, labels, roi, coords, thr, node_size, edge_threshold, prune, uatlas, target_samples, norm, binary, track_type, directget, max_length): """ Plot adjacency matrix, connectogram, and glass brain for functional connectome. Parameters ---------- conn_matrix : array NxN matrix. conn_model : str Connectivity estimation model (e.g. corr for correlation, cov for covariance, sps for precision covariance, partcorr for partial correlation). sps type is used by default. atlas : str Name of atlas parcellation used. dir_path : str Path to directory containing subject derivative data for given run. ID : str A subject id or other unique identifier. network : str Resting-state network based on Yeo-7 and Yeo-17 naming (e.g. 'Default') used to filter nodes in the study of brain subgraphs. labels : list List of string labels corresponding to ROI nodes. roi : str File path to binarized/boolean region-of-interest Nifti1Image file. coords : list List of (x, y, z) tuples corresponding to an a-priori defined set (e.g. a coordinate atlas). thr : float A value, between 0 and 1, to threshold the graph using any variety of methods triggered through other options. node_size : int Spherical centroid node size in the case that coordinate-based centroids are used as ROI's. edge_threshold : float The actual value, between 0 and 1, that the graph was thresholded (can differ from thr if target was not successfully obtained. prune : bool Indicates whether to prune final graph of disconnected nodes/isolates. uatlas : str File path to atlas parcellation Nifti1Image in MNI template space. target_samples : int Total number of streamline samples specified to generate streams. norm : int Indicates method of normalizing resulting graph. binary : bool Indicates whether to binarize resulting graph edges to form an unweighted graph. track_type : str Tracking algorithm used (e.g. 'local' or 'particle'). directget : str The statistical approach to tracking. Options are: det (deterministic), closest (clos), boot (bootstrapped), and prob (probabilistic). max_length : int Maximum fiber length threshold in mm to restrict tracking. """ import matplotlib matplotlib.use('agg') import os import os.path as op from matplotlib import pyplot as plt from nilearn import plotting as niplot import pkg_resources import networkx as nx from matplotlib import colors import seaborn as sns from pynets.core import thresholding from pynets.plotting import plot_gen, plot_graphs from pynets.stats.netstats import most_important, prune_disconnected try: import cPickle as pickle except ImportError: import _pickle as pickle ch2better_loc = pkg_resources.resource_filename("pynets", "templates/ch2better.nii.gz") coords = list(coords) labels = list(labels) if len(coords) > 0: dpi_resolution = 500 if '\'b' in atlas: atlas = atlas.decode('utf-8') if (prune == 1 or prune == 2) and len(coords) == conn_matrix.shape[0]: G_pre = nx.from_numpy_matrix(np.abs(conn_matrix)) if prune == 1: [G, pruned_nodes] = prune_disconnected(G_pre) elif prune == 2: [G, pruned_nodes] = most_important(G_pre) else: G = G_pre pruned_nodes = [] pruned_nodes.sort(reverse=True) coords_pre = list(coords) labels_pre = list(labels) if len(pruned_nodes) > 0: for j in pruned_nodes: labels_pre.pop(j) coords_pre.pop(j) conn_matrix = nx.to_numpy_array(G) labels = labels_pre coords = coords_pre else: print('No nodes to prune for plot...') coords = list(tuple(x) for x in coords) namer_dir = dir_path + '/figures' if not os.path.isdir(namer_dir): os.makedirs(namer_dir, exist_ok=True) # Plot connectogram if len(conn_matrix) > 20: try: plot_gen.plot_connectogram(conn_matrix, conn_model, atlas, namer_dir, ID, network, labels) except RuntimeWarning: print('\n\n\nWarning: Connectogram plotting failed!') else: print('Warning: Cannot plot connectogram for graphs smaller than 20 x 20!') # Plot adj. matrix based on determined inputs if not node_size or node_size == 'None': node_size = 'parc' plot_graphs.plot_conn_mat_struct(conn_matrix, conn_model, atlas, namer_dir, ID, network, labels, roi, thr, node_size, target_samples, track_type, directget, max_length) # Plot connectome out_path_fig = "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s" % (namer_dir, '/', ID, '_modality-dwi_', '%s' % ("%s%s%s" % ('rsn-', network, '_') if network is not None else ''), '%s' % ("%s%s%s" % ('roi-', op.basename(roi).split( '.')[0], '_') if roi is not None else ''), 'est-', conn_model, '_', '%s' % ( "%s%s%s" % ('nodetype-spheres-', node_size, 'mm_') if ((node_size != 'parc') and (node_size is not None)) else 'nodetype-parc_'), "%s" % ("%s%s%s" % ( 'samples-', int(target_samples), 'streams_') if float(target_samples) > 0 else '_'), 'tt-', track_type, '_dg-', directget, '_ml-', max_length, '_thr-', thr, '_glass_viz.png') if roi: # Save coords to pickle coord_path = "%s%s%s%s" % (namer_dir, '/coords_', op.basename(roi).split('.')[0], '_plotting.pkl') with open(coord_path, 'wb') as f: pickle.dump(coords, f, protocol=2) # Save labels to pickle labels_path = "%s%s%s%s" % (namer_dir, '/labelnames_', op.basename(roi).split('.')[0], '_plotting.pkl') with open(labels_path, 'wb') as f: pickle.dump(labels, f, protocol=2) else: # Save coords to pickle coord_path = "%s%s" % (namer_dir, '/coords_plotting.pkl') with open(coord_path, 'wb') as f: pickle.dump(coords, f, protocol=2) # Save labels to pickle labels_path = "%s%s" % (namer_dir, '/labelnames_plotting.pkl') with open(labels_path, 'wb') as f: pickle.dump(labels, f, protocol=2) connectome = niplot.plot_connectome(np.zeros(shape=(1, 1)), [(0, 0, 0)], node_size=0.0001, black_bg=True) connectome.add_overlay(ch2better_loc, alpha=0.45, cmap=plt.cm.gray) #connectome.add_overlay(ch2better_loc, alpha=0.35, cmap=plt.cm.gray) conn_matrix = np.array(np.array(thresholding.autofix(conn_matrix))) [z_min, z_max] = -np.abs(conn_matrix).max(), np.abs(conn_matrix).max() if node_size == 'parc': node_size_plot = int(6) else: node_size_plot = int(node_size) if len(coords) != conn_matrix.shape[0]: raise RuntimeWarning('\nWARNING: Number of coordinates does not match conn_matrix dimensions.') else: norm = colors.Normalize(vmin=-1, vmax=1) clust_pal = sns.color_palette("Blues_r", conn_matrix.shape[0]) clust_colors = colors.to_rgba_array(clust_pal) fa_path = dir_path + '/../reg_dmri/dmri_tmp/DSN/Warped.nii.gz' if os.path.isfile(fa_path): connectome.add_overlay(img=fa_path, threshold=0.01, alpha=0.25, cmap=plt.cm.copper) connectome.add_graph(conn_matrix, coords, edge_threshold=edge_threshold, edge_cmap=plt.cm.binary, edge_vmax=float(z_max), edge_vmin=float(z_min), node_size=node_size_plot, node_color=clust_colors) connectome.savefig(out_path_fig, dpi=dpi_resolution) else: raise RuntimeError('\nERROR: no coordinates to plot! Are you running plotting outside of pynets\'s internal ' 'estimation schemes?') plt.close('all') return
def plot_all_func(conn_matrix, conn_model, atlas, dir_path, ID, network, labels, roi, coords, thr, node_size, edge_threshold, smooth, prune, uatlas, c_boot, norm, binary, hpass): """ Plot adjacency matrix, connectogram, and glass brain for functional connectome. Parameters ---------- conn_matrix : array NxN matrix. conn_model : str Connectivity estimation model (e.g. corr for correlation, cov for covariance, sps for precision covariance, partcorr for partial correlation). sps type is used by default. atlas : str Name of atlas parcellation used. dir_path : str Path to directory containing subject derivative data for given run. ID : str A subject id or other unique identifier. network : str Resting-state network based on Yeo-7 and Yeo-17 naming (e.g. 'Default') used to filter nodes in the study of brain subgraphs. labels : list List of string labels corresponding to ROI nodes. roi : str File path to binarized/boolean region-of-interest Nifti1Image file. coords : list List of (x, y, z) tuples corresponding to an a-priori defined set (e.g. a coordinate atlas). thr : float A value, between 0 and 1, to threshold the graph using any variety of methods triggered through other options. node_size : int Spherical centroid node size in the case that coordinate-based centroids are used as ROI's. edge_threshold : float The actual value, between 0 and 1, that the graph was thresholded (can differ from thr if target was not successfully obtained. smooth : int Smoothing width (mm fwhm) to apply to time-series when extracting signal from ROI's. prune : bool Indicates whether to prune final graph of disconnected nodes/isolates. uatlas : str File path to atlas parcellation Nifti1Image in MNI template space. c_boot : int Number of bootstraps if user specified circular-block bootstrapped resampling of the node-extracted time-series. norm : int Indicates method of normalizing resulting graph. binary : bool Indicates whether to binarize resulting graph edges to form an unweighted graph. hpass : bool High-pass filter values (Hz) to apply to node-extracted time-series. """ import os import os.path as op import matplotlib matplotlib.use('agg') from matplotlib import pyplot as plt from nilearn import plotting as niplot import pkg_resources import networkx as nx from pynets.core import thresholding from pynets.plotting import plot_gen, plot_graphs from pynets.stats.netstats import most_important, prune_disconnected try: import cPickle as pickle except ImportError: import _pickle as pickle ch2better_loc = pkg_resources.resource_filename("pynets", "templates/ch2better.nii.gz") coords = list(coords) labels = list(labels) if len(coords) > 0: dpi_resolution = 500 if '\'b' in atlas: atlas = atlas.decode('utf-8') if (prune == 1 or prune == 2) and len(coords) == conn_matrix.shape[0]: G_pre = nx.from_numpy_matrix(np.abs(conn_matrix)) if prune == 1: [G, pruned_nodes] = prune_disconnected(G_pre) elif prune == 2: [G, pruned_nodes] = most_important(G_pre) else: G = G_pre pruned_nodes = [] pruned_nodes.sort(reverse=True) print('(Display)') coords_pre = list(coords) labels_pre = list(labels) if len(pruned_nodes) > 0: for j in pruned_nodes: labels_pre.pop(j) coords_pre.pop(j) conn_matrix = nx.to_numpy_array(G) labels = labels_pre coords = coords_pre else: print('No nodes to prune for plot...') coords = list(tuple(x) for x in coords) namer_dir = dir_path + '/figures' if not os.path.isdir(namer_dir): os.makedirs(namer_dir, exist_ok=True) # Plot connectogram if len(conn_matrix) > 20: try: plot_gen.plot_connectogram(conn_matrix, conn_model, atlas, namer_dir, ID, network, labels) except RuntimeWarning: print('\n\n\nWarning: Connectogram plotting failed!') else: print('Warning: Cannot plot connectogram for graphs smaller than 20 x 20!') # Plot adj. matrix based on determined inputs if not node_size or node_size == 'None': node_size = 'parc' plot_graphs.plot_conn_mat_func(conn_matrix, conn_model, atlas, namer_dir, ID, network, labels, roi, thr, node_size, smooth, c_boot, hpass) # Plot connectome out_path_fig = "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s" % (namer_dir, '/', ID, '_modality-func_', '%s' % ("%s%s%s" % ('rsn-', network, '_') if network is not None else ''), '%s' % ("%s%s%s" % ('roi-', op.basename(roi).split('.')[0], '_') if roi is not None else ''), 'est-', conn_model, '_', '%s' % ( "%s%s%s" % ('nodetype-spheres-', node_size, 'mm_') if ((node_size != 'parc') and (node_size is not None)) else 'nodetype-parc_'), "%s" % ("%s%s%s" % ('boot-', int(c_boot), 'iter_') if float(c_boot) > 0 else ''), "%s" % ("%s%s%s" % ('smooth-', smooth, 'fwhm_') if float(smooth) > 0 else ''), "%s" % ("%s%s%s" % ('hpass-', hpass, 'Hz_') if hpass is not None else ''), '_thr-', thr, '_glass_viz.png') if roi: # Save coords to pickle coord_path = "%s%s%s%s" % (namer_dir, '/coords_', op.basename(roi).split('.')[0], '_plotting.pkl') with open(coord_path, 'wb') as f: pickle.dump(coords, f, protocol=2) # Save labels to pickle labels_path = "%s%s%s%s" % (namer_dir, '/labelnames_', op.basename(roi).split('.')[0], '_plotting.pkl') with open(labels_path, 'wb') as f: pickle.dump(labels, f, protocol=2) else: # Save coords to pickle coord_path = "%s%s" % (namer_dir, '/coords_plotting.pkl') with open(coord_path, 'wb') as f: pickle.dump(coords, f, protocol=2) # Save labels to pickle labels_path = "%s%s" % (namer_dir, '/labelnames_plotting.pkl') with open(labels_path, 'wb') as f: pickle.dump(labels, f, protocol=2) connectome = niplot.plot_connectome(np.zeros(shape=(1, 1)), [(0, 0, 0)], node_size=0.0001, black_bg=True) connectome.add_overlay(ch2better_loc, alpha=0.45, cmap=plt.cm.gray) #connectome.add_overlay(ch2better_loc, alpha=0.35, cmap=plt.cm.gray) conn_matrix = np.array(np.array(thresholding.autofix(conn_matrix))) [z_min, z_max] = -np.abs(conn_matrix).max(), np.abs(conn_matrix).max() if node_size == 'parc': node_size_plot = int(6) else: node_size_plot = int(node_size) if len(coords) != conn_matrix.shape[0]: raise RuntimeWarning('\nWARNING: Number of coordinates does not match conn_matrix dimensions. If you are ' 'using disparity filtering, try relaxing the α threshold.') else: color_theme = 'Blues' #color_theme = 'Greens' #color_theme = 'Reds' node_color = 'auto' connectome.add_graph(conn_matrix, coords, edge_threshold=edge_threshold, edge_cmap=color_theme, edge_vmax=float(z_max), edge_vmin=float(z_min), node_size=node_size_plot, node_color='auto') connectome.savefig(out_path_fig, dpi=dpi_resolution) else: raise RuntimeError('\nERROR: no coordinates to plot! Are you running plotting outside of pynets\'s internal ' 'estimation schemes?') plt.close('all') return
def _gen_mat_data(n: int=20, m: int=20, p: int=0.50, mat_type: str='sb', binary: bool=False, asfile: bool=True, n_graphs: int=1, lcc: bool=False, modality: str='func'): if binary is True: wt = 1 else: wt = np.random.uniform mat_list = [] mat_file_list = [] if n_graphs > 0: for nm in range(n_graphs): if mat_type == 'er': mat = symmetrize( remove_loops(er_nm(n, m, wt=np.random.uniform, wtargs=dict(low=0, high=1)))) elif mat_type == 'sb': if p is None: raise ValueError( f"for mat_type {mat_type}, p cannot be None") mat = symmetrize( remove_loops(sbm(np.array([n]), np.array([[p]]), wt=wt, wtargs=dict(low=0, high=1)))) else: raise ValueError(f"mat_type {mat_type} not recognized!") if lcc is True: mat = largest_connected_component(mat) mat_list.append(autofix(mat)) if asfile is True: path_tmp = tempfile.NamedTemporaryFile(mode='w+', suffix='.npy', delete=False) mat_path_tmp = str(path_tmp.name) out_folder = f"{str(Path.home())}/test_mats" os.makedirs(out_folder, exist_ok=True) if modality == 'func': mat_path = f"{out_folder}/graph_sub-999_modality-func_" \ f"model-corr_template-" \ f"MNI152_2mm_" \ f"parc_tol-6fwhm_hpass-" \ f"0Hz_" \ f"signal-mean_thrtype-prop_thr-" \ f"{round(random.uniform(0, 1),2)}.npy" elif modality == 'dwi': mat_path = f"{out_folder}/graph_sub-999_modality-func_" \ f"model-csa_template-" \ f"MNI152_2mm_tracktype-local_" \ f"traversal-det_minlength-30_" \ f"tol-5_thrtype-prop_thr-" \ f"{round(random.uniform(0, 1),2)}.npy" shutil.copyfile(mat_path_tmp, mat_path) np.save(mat_path, mat) mat_file_list.append(mat_path) path_tmp.close() return {'mat_list': mat_list, 'mat_file_list': mat_file_list}
def test_autofix(x, thr, cp): x[1][1] = np.inf x[2][1] = np.nan s = thresholding.autofix(x) assert (np.nan not in s) and (np.inf not in s)
def motif_matching( paths, ID, atlas, namer_dir, name_list, metadata_list, multigraph_list_all, graph_path_list_all, rsn=None, ): import networkx as nx import numpy as np import glob import pickle from pynets.core import thresholding from pynets.stats.netmotifs import compare_motifs from sklearn.metrics.pairwise import cosine_similarity from pynets.stats.netstats import community_resolution_selection from graspy.utils import remove_loops, symmetrize, get_lcc from pynets.core.nodemaker import get_brainnetome_node_attributes [struct_graph_path, func_graph_path] = paths struct_mat = np.load(struct_graph_path) func_mat = np.load(func_graph_path) [struct_coords, struct_labels, struct_label_intensities] = \ get_brainnetome_node_attributes(glob.glob( f"{str(Path(struct_graph_path).parent.parent)}/nodes/*.json"), struct_mat.shape[0]) [func_coords, func_labels, func_label_intensities] = \ get_brainnetome_node_attributes(glob.glob( f"{str(Path(func_graph_path).parent.parent)}/nodes/*.json"), func_mat.shape[0]) # Find intersecting nodes across modalities (i.e. assuming the same # parcellation, but accomodating for the possibility of dropped nodes) diff1 = list(set(struct_label_intensities) - set(func_label_intensities)) diff2 = list(set(func_label_intensities) - set(struct_label_intensities)) G_struct = nx.from_numpy_array(struct_mat) G_func = nx.from_numpy_array(func_mat) bad_idxs = [] for val in diff1: bad_idxs.append(struct_label_intensities.index(val)) bad_idxs = sorted(list(set(bad_idxs)), reverse=True) if type(struct_coords) is np.ndarray: struct_coords = list(tuple(x) for x in struct_coords) for j in bad_idxs: G_struct.remove_node(j) print(f"Removing: {(struct_labels[j], struct_coords[j])}...") del struct_labels[j], struct_coords[j] bad_idxs = [] for val in diff2: bad_idxs.append(func_label_intensities.index(val)) bad_idxs = sorted(list(set(bad_idxs)), reverse=True) if type(func_coords) is np.ndarray: func_coords = list(tuple(x) for x in func_coords) for j in bad_idxs: G_func.remove_node(j) print(f"Removing: {(func_labels[j], func_coords[j])}...") del func_labels[j], func_coords[j] struct_mat = nx.to_numpy_array(G_struct) func_mat = nx.to_numpy_array(G_func) struct_mat = thresholding.autofix(symmetrize(remove_loops(struct_mat))) func_mat = thresholding.autofix(symmetrize(remove_loops(func_mat))) if func_mat.shape == struct_mat.shape: func_mat[~struct_mat.astype("bool")] = 0 struct_mat[~func_mat.astype("bool")] = 0 print( "Edge disagreements after matching: ", sum(sum(abs(func_mat - struct_mat))), ) metadata = {} assert ( len(struct_coords) == len(struct_labels) == len(func_coords) == len(func_labels) == func_mat.shape[0] ) metadata["coords"] = struct_coords metadata["labels"] = struct_labels metadata_list.append(metadata) struct_mat = np.maximum(struct_mat, struct_mat.T) func_mat = np.maximum(func_mat, func_mat.T) struct_mat = thresholding.standardize(struct_mat) func_mat = thresholding.standardize(func_mat) struct_node_comm_aff_mat = community_resolution_selection( nx.from_numpy_matrix(np.abs(struct_mat)) )[1] func_node_comm_aff_mat = community_resolution_selection( nx.from_numpy_matrix(np.abs(func_mat)) )[1] struct_comms = [] for i in np.unique(struct_node_comm_aff_mat): struct_comms.append(struct_node_comm_aff_mat == i) func_comms = [] for i in np.unique(func_node_comm_aff_mat): func_comms.append(func_node_comm_aff_mat == i) sims = cosine_similarity(struct_comms, func_comms) try: struct_comm = struct_comms[np.argmax(sims, axis=0)[0]] except BaseException: print('Matching by structural communities failed...') struct_comm = struct_mat try: func_comm = func_comms[np.argmax(sims, axis=0)[0]] except BaseException: print('Matching by functional communities failed...') func_comm = func_mat comm_mask = np.equal.outer(struct_comm, func_comm).astype(bool) try: assert comm_mask.shape == struct_mat.shape == func_mat.shape except AssertionError as e: e.args += (comm_mask, comm_mask.shape, struct_mat, struct_mat.shape, func_mat, func_mat.shape) try: struct_mat[~comm_mask] = 0 except BaseException: print('Skipping community masking...') try: func_mat[~comm_mask] = 0 except BaseException: print('Skipping community masking...') struct_name = struct_graph_path.split("/rawgraph_" )[-1].split(".npy")[0] func_name = func_graph_path.split("/rawgraph_")[-1].split(".npy")[0] name = f"sub-{ID}_{atlas}_mplx_Layer-1_{struct_name}_" \ f"Layer-2_{func_name}" name_list.append(name) struct_mat = np.maximum(struct_mat, struct_mat.T) func_mat = np.maximum(func_mat, func_mat.T) try: [mldict, g_dict] = compare_motifs( struct_mat, func_mat, name, namer_dir) except BaseException: print(f"Adaptive thresholding by motif comparisons failed " f"for {name}. This usually happens when no motifs are found") return [], [], [], [] multigraph_list_all.append(list(mldict.values())[0]) graph_path_list = [] for thr in list(g_dict.keys()): multigraph_path_list_dict = {} [struct, func] = g_dict[thr] struct_out = f"{namer_dir}/struct_{atlas}_{struct_name}.npy" func_out = f"{namer_dir}/struct_{atlas}_{func_name}_" \ f"motif-{thr}.npy" np.save(struct_out, struct) np.save(func_out, func) multigraph_path_list_dict[f"struct_{atlas}_{thr}"] = struct_out multigraph_path_list_dict[f"func_{atlas}_{thr}"] = func_out graph_path_list.append(multigraph_path_list_dict) graph_path_list_all.append(graph_path_list) else: print( f"Skipping {rsn} rsn, since structural and functional graphs are " f"not identical shapes." ) return name_list, metadata_list, multigraph_list_all, graph_path_list_all
def create_gb_palette(mat, edge_cmap, coords, labels, node_size='auto', node_cmap=None, prune=True): """ Create conectome color palatte based on topography. Parameters ---------- mat : array NxN matrix. edge_cmap: colormap colormap used for representing the weight of the edges. coords : list List of (x, y, z) tuples corresponding to an a-priori defined set (e.g. a coordinate atlas). labels : list List of string labels corresponding to ROI nodes. node_size : int Spherical centroid node size in the case that coordinate-based centroids are used as ROI's. node_size: scalar or array_like size(s) of the nodes in points^2. node_cmap: colormap colormap used for representing the community assignment of the nodes. """ import random import seaborn as sns import networkx as nx from pynets.core import thresholding from matplotlib import colors from sklearn.preprocessing import minmax_scale from pynets.stats.netstats import community_resolution_selection, prune_disconnected mat = np.array(np.array(thresholding.autofix(mat))) if prune is True: [G, pruned_nodes] = prune_disconnected(nx.from_numpy_matrix(np.abs(mat))) pruned_nodes.sort(reverse=True) coords_pre = list(coords) labels_pre = list(labels) if len(pruned_nodes) > 0: for j in pruned_nodes: del labels_pre[j], coords_pre[j] mat = nx.to_numpy_array(G) labels = labels_pre coords = coords_pre else: print('No nodes to prune for plotting...') else: G = nx.from_numpy_matrix(np.abs(mat)) # Node centralities try: node_centralities = list( nx.algorithms.eigenvector_centrality_numpy( G, weight='weight').values()) except: node_centralities = len(coords) * [1] max_node_size = (1 / mat.shape[0] * 1e3 if node_size == 'auto' else node_size) node_sizes = np.array( minmax_scale(node_centralities, feature_range=(1, max_node_size))) # Node communities _, node_comm_aff_mat, resolution, num_comms = community_resolution_selection( G) # Path lengths edge_lengths = [] for edge_dict in [i[1] for i in nx.all_pairs_shortest_path_length(G)]: edge_lengths.extend(list(edge_dict.values())) edge_sizes = np.array(minmax_scale(edge_lengths, feature_range=(0.5, 2))) # Nodes if not node_cmap: # Generate as many randomly distinct colors as num_comms def random_color(n): ret = [] r = int(random.random() * 256) g = int(random.random() * 256) b = int(random.random() * 256) step = 256 / n for i in range(n): r += step g += step b += step r = int(r) % 256 g = int(g) % 256 b = int(b) % 256 ret.append((r, g, b)) return ret flatui = [ '#{:02x}{:02x}{:02x}'.format(i[0], i[1], i[2]) for i in random_color(num_comms) ] try: ls_cmap = colors.LinearSegmentedColormap.from_list( node_comm_aff_mat, sns.color_palette(flatui, n_colors=num_comms)) matplotlib.cm.register_cmap("community", ls_cmap) clust_pal = sns.color_palette("community", n_colors=mat.shape[0]) except: clust_pal = sns.color_palette("Set2", n_colors=mat.shape[0]) else: clust_pal = sns.color_palette(node_cmap, n_colors=mat.shape[0]) clust_pal_nodes = colors.to_rgba_array(clust_pal) # Edges z_min = np.percentile(mat[mat > 0], 10) z_max = np.percentile(mat[mat > 0], 90) edge_cmap_pl = sns.color_palette(edge_cmap) clust_pal_edges = colors.ListedColormap(edge_cmap_pl.as_hex()) return mat, clust_pal_edges, clust_pal_nodes, node_sizes, edge_sizes, z_min, z_max, coords, labels
def matching( paths, atlas, namer_dir, ): import glob import networkx as nx import numpy as np from pynets.core import thresholding from pynets.statistics.utils import parse_closest_ixs from graspologic.utils import remove_loops, symmetrize, \ multigraph_lcc_intersection [dwi_graph_path, func_graph_path] = paths dwi_mat = np.load(dwi_graph_path) func_mat = np.load(func_graph_path) dwi_mat = thresholding.autofix(symmetrize(remove_loops(dwi_mat))) func_mat = thresholding.autofix(symmetrize(remove_loops(func_mat))) dwi_mat = thresholding.standardize(dwi_mat) func_mat = thresholding.standardize(func_mat) node_dict_dwi = parse_closest_ixs( glob.glob(f"{str(Path(dwi_graph_path).parent.parent)}" f"/nodes/*.json"), dwi_mat.shape[0])[1] node_dict_func = parse_closest_ixs( glob.glob(f"{str(Path(func_graph_path).parent.parent)}" f"/nodes/*.json"), func_mat.shape[0])[1] G_dwi = nx.from_numpy_array(dwi_mat) nx.set_edge_attributes(G_dwi, 'structural', nx.get_edge_attributes(G_dwi, 'weight').values()) nx.set_node_attributes(G_dwi, dict(node_dict_dwi), name='dwi') #G_dwi.nodes(data=True) G_func = nx.from_numpy_array(func_mat) nx.set_edge_attributes(G_func, 'functional', nx.get_edge_attributes(G_func, 'weight').values()) nx.set_node_attributes(G_func, dict(node_dict_func), name='func') #G_func.nodes(data=True) R = G_dwi.copy() R.remove_nodes_from(n for n in G_dwi if n not in G_func) R.remove_edges_from(e for e in G_dwi.edges if e not in G_func.edges) G_dwi = R.copy() R = G_func.copy() R.remove_nodes_from(n for n in G_func if n not in G_dwi) R.remove_edges_from(e for e in G_func.edges if e not in G_dwi.edges) G_func = R.copy() [G_dwi, G_func] = multigraph_lcc_intersection([G_dwi, G_func]) def writeJSON(metadata_str, outputdir): import json import uuid modality = metadata_str.split('modality-')[1].split('_')[0] metadata_list = [ i for i in metadata_str.split('modality-')[1].split('_') if '-' in i ] hash = str(uuid.uuid4()) filename = f"{outputdir}/sidecar_modality-{modality}_{hash}.json" metadata_dict = {} for meta in metadata_list: k, v = meta.split('-') metadata_dict[k] = v with open(filename, 'w+') as jsonfile: json.dump(metadata_dict, jsonfile, indent=4) jsonfile.close() return hash dwi_name = dwi_graph_path.split("/")[-1].split(".npy")[0] func_name = func_graph_path.split("/")[-1].split(".npy")[0] dwi_hash = writeJSON(dwi_name, namer_dir) func_hash = writeJSON(func_name, namer_dir) name = f"{atlas}_mplx_layer1-dwi_ensemble-{dwi_hash}_" \ f"layer2-func_ensemble-{func_hash}" dwi_opt, func_opt, best_mi = optimize_mutual_info( nx.to_numpy_array(G_dwi), nx.to_numpy_array(G_func), bins=50) func_mat_final = list(func_opt.values())[0] dwi_mat_final = list(dwi_opt.values())[0] G_dwi_final = nx.from_numpy_array(dwi_mat_final) G_func_final = nx.from_numpy_array(func_mat_final) G_multi = nx.OrderedMultiGraph(nx.compose(G_dwi_final, G_func_final)) out_name = f"{name}_matchthr-{list(dwi_opt.keys())[0]}_" \ f"{list(func_opt.keys())[0]}" mG = build_mx_multigraph(nx.to_numpy_array(G_func_final), nx.to_numpy_array(G_dwi_final), out_name, namer_dir) mG_nx = f"{namer_dir}/{out_name}.gpickle" nx.write_gpickle(G_multi, mG_nx) dwi_file_out = f"{namer_dir}/{dwi_name}.npy" func_file_out = f"{namer_dir}/{func_name}.npy" np.save(dwi_file_out, dwi_mat_final) np.save(func_file_out, func_mat_final) return mG_nx, mG, dwi_file_out, func_file_out