def test_prune_disconnected(): """ Test pruning functionality """ base_dir = str(Path(__file__).parent / "examples") in_mat = np.load( f"{base_dir}/miscellaneous/graphs/002_modality-func_rsn-Default_est-cov_nodetype-spheres-2mm_smooth-2fwhm_hpass-0.1Hz_thrtype-PROP_thr-0.95.npy" ) G = nx.from_numpy_array(in_mat) start_time = time.time() [G, pruned_nodes] = netstats.prune_disconnected(G) print("%s%s%s" % ( 'thresh_and_fit (Functional, proportional thresholding) --> finished: ', str(np.round(time.time() - start_time, 1)), 's')) assert G is not None assert pruned_nodes is not None
def test_prune_disconnected(): """ Test pruning functionality """ base_dir = str(Path(__file__).parent / "examples") in_mat = np.load( base_dir + '/002/fmri/graphs/002_Default_est_cov_0.95prop_TESTmm_3nb_2fwhm_0.1Hz_func.npy' ) G = nx.from_numpy_array(in_mat) start_time = time.time() [G, pruned_nodes] = netstats.prune_disconnected(G) print("%s%s%s" % ( 'thresh_and_fit (Functional, proportional thresholding) --> finished: ', str(np.round(time.time() - start_time, 1)), 's')) assert G is not None assert pruned_nodes is not None
def test_raw_mets(): """ Test raw_mets extraction functionality """ from pynets.stats.netstats import global_efficiency, average_local_efficiency from networkx.algorithms import degree_assortativity_coefficient, average_clustering, \ average_shortest_path_length, degree_pearson_correlation_coefficient, graph_number_of_cliques, transitivity, \ sigma base_dir = str(Path(__file__).parent/"examples") est_path = f"{base_dir}/miscellaneous/sub-0021001_rsn-Default_nodetype-parc_model-sps_template-MNI152_T1_thrtype-DENS_thr-0.19.npy" in_mat = np.load(est_path) G = nx.from_numpy_array(in_mat) [G, _] = netstats.prune_disconnected(G) metric_list_glob = [global_efficiency, average_local_efficiency, degree_assortativity_coefficient, average_clustering, average_shortest_path_length, degree_pearson_correlation_coefficient, graph_number_of_cliques, transitivity] for i in metric_list_glob: net_met_val = netstats.raw_mets(G, i) print(i) print(net_met_val) assert net_met_val is not np.nan
def test_raw_mets(): """ Test raw_mets extraction functionality """ from pynets.stats.netstats import global_efficiency, average_local_efficiency from networkx.algorithms import degree_assortativity_coefficient, average_clustering, average_shortest_path_length, degree_pearson_correlation_coefficient, graph_number_of_cliques, transitivity, sigma base_dir = str(Path(__file__).parent / "examples") est_path = base_dir + '/002/fmri/DesikanKlein2012/graphs/0021001_Default_est_sps_0.19densparc_mm.npy' in_mat = np.load(est_path) G = nx.from_numpy_array(in_mat) [G, _] = netstats.prune_disconnected(G) metric_list_glob = [ global_efficiency, average_local_efficiency, degree_assortativity_coefficient, average_clustering, average_shortest_path_length, degree_pearson_correlation_coefficient, graph_number_of_cliques, transitivity ] for i in metric_list_glob: net_met_val = netstats.raw_mets(G, i) print(i) print(net_met_val) assert net_met_val is not np.nan
def test_prune_disconnected(connected_case, fallback_lcc): """ Test pruning functionality """ base_dir = str(Path(__file__).parent/"examples") if connected_case is True: in_mat = np.load(f"{base_dir}/miscellaneous/graphs/002_modality-func_rsn-Default_model-cov_nodetype-spheres-2mm_smooth-2fwhm_hpass-0.1Hz_thrtype-PROP_thr-0.95.npy") G = nx.from_numpy_array(in_mat) elif connected_case is False: G = nx.Graph() G.add_edge(1, 2) G.add_node(3) start_time = time.time() [G_out, pruned_nodes] = netstats.prune_disconnected(G) print("%s%s%s" % ('Pruning disconnected test --> finished: ', str(np.round(time.time() - start_time, 1)), 's')) assert type(G_out) is nx.Graph assert type(pruned_nodes) is list if connected_case is True: assert len(pruned_nodes) == 0 elif connected_case is False: assert len(pruned_nodes) > 0 assert len(list(G_out.nodes())) < len(list(G.nodes()))
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 local_thresholding_prop(conn_matrix, coords, labels, thr): """ Threshold the adjacency matrix by building from the minimum spanning tree (MST) and adding successive N-nearest neighbour degree graphs to achieve target proportional threshold. Parameters ---------- conn_matrix : array Weighted NxN matrix. thr : float A proportional threshold, between 0 and 1, to achieve through local thresholding. Returns ------- conn_matrix_thr : array Weighted, MST local-thresholded, NxN matrix. """ from pynets.core import thresholding from pynets.stats import netstats fail_tol = 100 conn_matrix = np.nan_to_num(conn_matrix) G = nx.from_numpy_matrix(np.abs(conn_matrix)) if not nx.is_connected(G): [G, pruned_nodes] = netstats.prune_disconnected(G) 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 maximum_edges = G.number_of_edges() min_t = nx.minimum_spanning_tree(thresholding.weight_to_distance(G), weight="distance") len_edges = min_t.number_of_edges() upper_values = np.triu_indices(np.shape(conn_matrix)[0], k=1) weights = np.array(conn_matrix[upper_values]) edgenum = int(float(thr) * float(len(weights[~np.isnan(weights)]))) if len_edges > edgenum: print("%s%s%s" % ( 'Warning: The minimum spanning tree already has: ', len_edges, ' edges, select more edges. Local Threshold will be applied by just retaining the Minimum ' 'Spanning Tree')) conn_matrix_thr = nx.to_numpy_array(G) return conn_matrix_thr, coords, labels k = 1 len_edge_list = [] while len_edges < edgenum and k <= np.shape(conn_matrix)[0] and ( len(len_edge_list[-fail_tol:]) - len(set(len_edge_list[-fail_tol:]))) < (fail_tol - 1): # print(k) # print(len_edges) len_edge_list.append(len_edges) # Create nearest neighbour graph nng = thresholding.knn(conn_matrix, k) # Remove edges from the NNG that exist already in the new graph/MST nng.remove_edges_from(min_t.edges()) number_before = nng.number_of_edges() if nng.number_of_edges() == 0 and number_before >= maximum_edges: break # Add weights to NNG for e in nng.edges(): nng.edges[e[0], e[1]]['weight'] = float(conn_matrix[e[0], e[1]]) # Obtain list of edges from the NNG in order of weight edge_list = sorted(nng.edges(data=True), key=lambda t: t[2]['weight'], reverse=True) # Add edges in order of connectivity strength for edge in edge_list: # print("%s%s" % ('Adding edge to mst: ', edge)) min_t.add_edges_from([edge]) len_edges = min_t.number_of_edges() if len_edges >= edgenum: print(len_edges) break k += 1 conn_matrix_bin = thresholding.binarize( nx.to_numpy_array(min_t, nodelist=sorted(min_t.nodes()), dtype=np.float64)) # Enforce original dimensionality by padding with zeros. if conn_matrix_bin.shape != conn_matrix.shape: if conn_matrix.shape[0] > conn_matrix_bin.shape[0]: result = np.zeros(conn_matrix.shape) result[:conn_matrix_bin.shape[0], :conn_matrix_bin. shape[1]] = conn_matrix_bin conn_matrix_thr = np.multiply(conn_matrix, result) else: result = np.zeros(conn_matrix_bin.shape) result[:conn_matrix.shape[0], :conn_matrix.shape[1]] = conn_matrix conn_matrix_thr = np.multiply(conn_matrix_bin, result) else: conn_matrix_thr = np.multiply(conn_matrix, conn_matrix_bin) return conn_matrix_thr, coords, labels
def local_thresholding_dens(conn_matrix, thr): """ Threshold the adjacency matrix by building from the minimum spanning tree (MST) and adding successive N-nearest neighbour degree graphs to achieve target density threshold. Parameters ---------- conn_matrix : array Weighted NxN matrix. thr : float A density threshold, between 0 and 1, to achieve through local thresholding. Returns ------- conn_matrix_thr : array Weighted, MST local-thresholded, NxN matrix. """ from pynets import thresholding from pynets.stats import netstats fail_tol = 10 conn_matrix = np.nan_to_num(conn_matrix) G = nx.from_numpy_matrix(conn_matrix) if not nx.is_connected(G): [G, _] = netstats.prune_disconnected(G) maximum_edges = G.number_of_edges() G = thresholding.weight_to_distance(G) min_t = nx.minimum_spanning_tree(G, weight="distance") mst_density = nx.density(min_t) G_density = nx.density(G) if mst_density > G_density: print("%s%s%s" % ( 'Warning: The minimum spanning tree already has: ', thr, ' density. Local Threshold will be applied by just retaining the Minimum Spanning Tree' )) conn_matrix_thr = nx.to_numpy_array(G) return conn_matrix_thr k = 1 dense_list = [] while mst_density < float(thr) and (len(dense_list[-fail_tol:]) - len( set(dense_list[-fail_tol:]))) < (fail_tol - 1): print(k) print(mst_density) dense_list.append(mst_density) # Create nearest neighbour graph nng = thresholding.knn(conn_matrix, k) number_before = nng.number_of_edges() # Remove edges from the NNG that exist already in the new graph/MST nng.remove_edges_from(min_t.edges()) if nng.number_of_edges() == 0 and number_before >= maximum_edges: break # Add weights to NNG for e in nng.edges(): nng.edges[e[0], e[1]]['weight'] = float(conn_matrix[e[0], e[1]]) # Obtain list of edges from the NNG in order of weight edge_list = sorted(nng.edges(data=True), key=lambda t: t[2]['weight'], reverse=True) # Add edges in order of connectivity strength for edge in edge_list: min_t.add_edges_from([edge]) mst_density = thresholding.est_density((nx.to_numpy_array(min_t))) # print("%s%s" % ('Adding edge to mst: ', edge)) if mst_density >= G_density or mst_density >= float(thr): # print(mst_density) break if (len(dense_list[-fail_tol:]) - len(set(dense_list[-fail_tol:]))) >= (fail_tol - 1): print("%s%s%s" % ('Cannot apply local thresholding to achieve density of: ', thr, '. Using maximally saturated connected matrix instead...')) k += 1 conn_matrix_thr = nx.to_numpy_array(min_t, nodelist=sorted(min_t.nodes()), dtype=np.float64) if len(min_t.nodes()) < conn_matrix.shape[0]: raise RuntimeWarning( "%s%s%s" % ('Cannot apply local thresholding to achieve density of: ', thr, '. Try a higher -thr or -min_thr')) return conn_matrix_thr
def local_thresholding_prop(conn_matrix, thr): """ Threshold the adjacency matrix by building from the minimum spanning tree (MST) and adding successive N-nearest neighbour degree graphs to achieve target proportional threshold. Parameters ---------- conn_matrix : array Weighted NxN matrix. thr : float A proportional threshold, between 0 and 1, to achieve through local thresholding. Returns ------- conn_matrix_thr : array Weighted, MST local-thresholded, NxN matrix. """ from pynets import thresholding from pynets.stats import netstats fail_tol = 10 conn_matrix = np.nan_to_num(conn_matrix) G = nx.from_numpy_matrix(conn_matrix) if not nx.is_connected(G): [G, _] = netstats.prune_disconnected(G) maximum_edges = G.number_of_edges() G = thresholding.weight_to_distance(G) min_t = nx.minimum_spanning_tree(G, weight="distance") len_edges = min_t.number_of_edges() upper_values = np.triu_indices(np.shape(conn_matrix)[0], k=1) weights = np.array(conn_matrix[upper_values]) weights = weights[~np.isnan(weights)] edgenum = int(float(thr) * float(len(weights))) if len_edges > edgenum: print("%s%s%s" % ( 'Warning: The minimum spanning tree already has: ', len_edges, ' edges, select more edges. Local Threshold will be applied by just retaining the Minimum ' 'Spanning Tree')) conn_matrix_thr = nx.to_numpy_array(G) return conn_matrix_thr k = 1 len_edge_list = [] while len_edges < edgenum and k <= np.shape(conn_matrix)[0] and ( len(len_edge_list[-fail_tol:]) - len(set(len_edge_list[-fail_tol:]))) < (fail_tol - 1): print(k) print(len_edges) len_edge_list.append(len_edges) # Create nearest neighbour graph nng = thresholding.knn(conn_matrix, k) number_before = nng.number_of_edges() # Remove edges from the NNG that exist already in the new graph/MST nng.remove_edges_from(min_t.edges()) if nng.number_of_edges() == 0 and number_before >= maximum_edges: break # Add weights to NNG for e in nng.edges(): nng.edges[e[0], e[1]]['weight'] = float(conn_matrix[e[0], e[1]]) # Obtain list of edges from the NNG in order of weight edge_list = sorted(nng.edges(data=True), key=lambda t: t[2]['weight'], reverse=True) # Add edges in order of connectivity strength for edge in edge_list: # print("%s%s" % ('Adding edge to mst: ', edge)) min_t.add_edges_from([edge]) min_t_mx = nx.to_numpy_array(min_t) len_edges = nx.from_numpy_matrix(min_t_mx).number_of_edges() if len_edges >= edgenum: # print(len_edges) break if (len(len_edge_list[-fail_tol:]) - len(set(len_edge_list[-fail_tol:]))) >= (fail_tol - 1): print("%s%s%s" % ('Cannot apply local thresholding to achieve threshold of: ', thr, '. Using maximally saturated connected matrix instead...')) k += 1 conn_matrix_thr = nx.to_numpy_array(min_t, nodelist=sorted(min_t.nodes()), dtype=np.float64) if len(min_t.nodes()) < conn_matrix.shape[0]: raise RuntimeWarning( "%s%s%s" % ('Cannot apply local thresholding to achieve threshold of: ', thr, '. Try a higher -thr or -min_thr')) return conn_matrix_thr
def plot_all(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): """ :param conn_matrix: :param conn_model: :param atlas: :param dir_path: :param ID: :param network: :param labels: :param roi: :param coords: :param thr: :param node_size: :param edge_threshold: :param smooth: :param prune: :param uatlas: :param c_boot: :param norm: :param binary: :param hpass: :return: """ 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 import plotting, 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 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(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) # Plot connectogram if len(conn_matrix) > 20: try: plot_gen.plot_connectogram(conn_matrix, conn_model, atlas, dir_path, 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, dir_path, ID, network, labels, roi, thr, node_size, smooth, c_boot, hpass) # Plot connectome if roi: out_path_fig = "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s" % ( dir_path, '/', ID, '_', atlas, '_', conn_model, '_', op.basename(roi).split('.')[0], "%s" % ("%s%s%s" % ('_', network, '_') if network else "_"), thr, '_', node_size, '%s' % ("mm_" if node_size != 'parc' else "_"), "%s" % ("%s%s" % (int(c_boot), 'nb_') if float(c_boot) > 0 else 'nb_'), "%s" % ("%s%s" % (smooth, 'fwhm_') if float(smooth) > 0 else ''), "%s" % ("%s%s" % (hpass, 'Hz_') if hpass is not None else ''), 'func_glass_viz.png') # Save coords to pickle coord_path = "%s%s%s%s" % (dir_path, '/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" % (dir_path, '/labelnames_', op.basename(roi).split('.')[0], '_plotting.pkl') with open(labels_path, 'wb') as f: pickle.dump(labels, f, protocol=2) else: out_path_fig = "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s" % ( dir_path, '/', ID, '_', atlas, '_', conn_model, "%s" % ("%s%s%s" % ('_', network, '_') if network else "_"), thr, '_', node_size, '%s' % ("mm_" if node_size != 'parc' else "_"), "%s" % ("%s%s" % (int(c_boot), 'nb_') if float(c_boot) > 0 else 'nb_'), "%s" % ("%s%s" % (smooth, 'fwhm_') if float(smooth) > 0 else ''), "%s" % ("%s%s" % (hpass, 'Hz_') if hpass is not None else ''), 'func_glass_viz.png') # Save coords to pickle coord_path = "%s%s" % (dir_path, '/coords_plotting.pkl') with open(coord_path, 'wb') as f: pickle.dump(coords, f, protocol=2) # Save labels to pickle labels_path = "%s%s" % (dir_path, '/labelnames_plotting.pkl') with open(labels_path, 'wb') as f: pickle.dump(labels, f, protocol=2) ch2better_loc = pkg_resources.resource_filename( "pynets", "templates/ch2better.nii.gz") 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(2) if uatlas: connectome.add_contours(uatlas, filled=True, alpha=0.20, cmap=plt.cm.gist_rainbow) 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?') return
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