def compare_motifs(struct_mat, func_mat, name, bins=50, N=4): from pynets.stats.netmotifs import adaptivethresh from pynets.core.thresholding import standardize from scipy import spatial import pandas as pd from py3plex.core import multinet # Structural graph threshold window struct_mat = standardize(struct_mat) dims_struct = struct_mat.shape[0] struct_mat[range(dims_struct), range(dims_struct)] = 0 tmin_struct = struct_mat.min() tmax_struct = struct_mat.max() threshes_struct = np.linspace(tmin_struct, tmax_struct, bins) # Functional graph threshold window func_mat = standardize(func_mat) dims_func = func_mat.shape[0] func_mat[range(dims_func), range(dims_func)] = 0 tmin_func = func_mat.min() tmax_func = func_mat.max() threshes_func = np.linspace(tmin_func, tmax_func, bins) assert np.all( struct_mat == struct_mat.T), "Structural Matrix must be symmetric" assert np.all( func_mat == func_mat.T), "Functional Matrix must be symmetric" # list of mlib = ['1113', '1122', '1223', '2222', '2233', '3333'] # Count motifs print("%s%s%s%s" % ('Mining ', N, '-node motifs: ', mlib)) motif_dict = {} for thr_struct, thr_func in list( itertools.product(threshes_struct, threshes_func)): # Count at_struct = adaptivethresh(struct_mat, float(thr_struct), mlib, N) at_func = adaptivethresh(func_mat, float(thr_func), mlib, N) motif_dict["%s%s%s%s" % ('struct_', np.round( thr_struct, 4), '_func_', np.round(thr_func, 4))] = {} motif_dict["%s%s%s%s" % ('struct_', np.round(thr_struct, 4), '_func_', np.round(thr_func, 4))]['struct'] = at_struct motif_dict["%s%s%s%s" % ('struct_', np.round( thr_struct, 4), '_func_', np.round(thr_func, 4))]['func'] = at_func print("%s%s%s%s%s" % ('Layer 1 (structural) with absolute threshold of : ', thr_struct, ' yields ', np.sum(at_struct), ' total motifs')) print("%s%s%s%s%s" % ('Layer 2 (functional) with absolute threshold of : ', thr_func, ' yields ', np.sum(at_func), ' total motifs')) for k, v in list(motif_dict.items()): if np.sum(v['struct']) == 0 or np.sum(v['func']) == 0: del motif_dict[k] for k, v in list(motif_dict.items()): motif_dict[k]['dist'] = spatial.distance.cosine(v['struct'], v['func']) df = pd.DataFrame(motif_dict).T df['struct_func_3333'] = np.zeros(len(df)) df['struct_func_2233'] = np.zeros(len(df)) df['struct_func_2222'] = np.zeros(len(df)) df['struct_func_1223'] = np.zeros(len(df)) df['struct_func_1122'] = np.zeros(len(df)) df['struct_func_1113'] = np.zeros(len(df)) df['struct_3333'] = np.zeros(len(df)) df['func_3333'] = np.zeros(len(df)) df['struct_2233'] = np.zeros(len(df)) df['func_2233'] = np.zeros(len(df)) df['struct_2222'] = np.zeros(len(df)) df['func_2222'] = np.zeros(len(df)) df['struct_1223'] = np.zeros(len(df)) df['func_1223'] = np.zeros(len(df)) df['struct_1122'] = np.zeros(len(df)) df['func_1122'] = np.zeros(len(df)) df['struct_1113'] = np.zeros(len(df)) df['func_1113'] = np.zeros(len(df)) for idx in range(len(df)): df.set_value(df.index[idx], 'struct_3333', df['struct'][idx][-1]) df.set_value(df.index[idx], 'func_3333', df['func'][idx][-1]) df.set_value(df.index[idx], 'struct_2233', df['struct'][idx][-2]) df.set_value(df.index[idx], 'func_2233', df['func'][idx][-2]) df.set_value(df.index[idx], 'struct_2222', df['struct'][idx][-3]) df.set_value(df.index[idx], 'func_2222', df['func'][idx][-3]) df.set_value(df.index[idx], 'struct_1223', df['struct'][idx][-4]) df.set_value(df.index[idx], 'func_1223', df['func'][idx][-4]) df.set_value(df.index[idx], 'struct_1122', df['struct'][idx][-5]) df.set_value(df.index[idx], 'func_1122', df['func'][idx][-5]) df.set_value(df.index[idx], 'struct_1113', df['struct'][idx][-6]) df.set_value(df.index[idx], 'func_1113', df['func'][idx][-6]) df['struct_func_3333'] = np.abs(df['struct_3333'] - df['func_3333']) df['struct_func_2233'] = np.abs(df['struct_2233'] - df['func_2233']) df['struct_func_2222'] = np.abs(df['struct_2222'] - df['func_2222']) df['struct_func_1223'] = np.abs(df['struct_1223'] - df['func_1223']) df['struct_func_1122'] = np.abs(df['struct_1122'] - df['func_1122']) df['struct_func_1113'] = np.abs(df['struct_1113'] - df['func_1113']) df = df[(df.struct_3333 != 0) & (df.func_3333 != 0) & (df.struct_2233 != 0) & (df.func_2233 != 0) & (df.struct_2222 != 0) & (df.func_2222 != 0) & (df.struct_1223 != 0) & (df.func_1223 != 0) & (df.struct_1122 != 0) & (df.func_1122 != 0) & (df.struct_1113 != 0) & (df.func_1113 != 0)] df = df.sort_values(by=[ 'dist', 'struct_func_3333', 'struct_func_2233', 'struct_func_2222', 'struct_func_1223', 'struct_func_1122', 'struct_func_1113', 'struct_3333', 'func_3333', 'struct_2233', 'func_2233', 'struct_2222', 'func_2222', 'struct_1223', 'func_1223', 'struct_1122', 'func_1122', 'struct_1113', 'func_1113' ], ascending=[ True, True, True, True, True, True, True, False, False, False, False, False, False, False, False, False, False, False, False ]) # Take the top 25th percentile df = df[df['dist'] < df['dist'].quantile(0.25)] best_threshes = [] best_mats = [] #best_graphs = [] best_multigraphs = [] for str in list(df.index): func_mat_tmp = func_mat.copy() struct_mat_tmp = struct_mat.copy() struct_thr = float(str.split('_')[1]) func_thr = float(str.split('_')[3]) best_threshes.append((struct_thr, func_thr)) func_mat_tmp[func_mat_tmp < func_thr] = 0 struct_mat_tmp[struct_mat_tmp < struct_thr] = 0 best_mats.append((func_mat_tmp, struct_mat_tmp)) G = build_nx_multigraph(func_mat, struct_mat, str) #best_graphs.append(G) B = multinet.multi_layer_network(network_type="multiplex", directed=False) B.add_edges([[x, 1, y, 2, z] for x, y, z in list(G.edges)], input_type="list") best_multigraphs.append(B) mg_dict = dict(zip(best_threshes, best_multigraphs)) return mg_dict
def compare_motifs(struct_mat, func_mat, name, namer_dir, bins=20, N=4): ''' Compare motif structure and population across structural and functional graphs to achieve a homeostatic absolute threshold of each that optimizes multiplex community detection and analysis. Parameters ---------- in_mat : ndarray M x M Connectivity matrix thr : float Absolute threshold [0, 1]. mlib : list List of motif classes. Returns ------- mf : ndarray 1D vector listing the total motifs of size N for each class of mlib. References ---------- .. [1] Battiston, F., Nicosia, V., Chavez, M., & Latora, V. (2017). Multilayer motif analysis of brain networks. Chaos. https://doi.org/10.1063/1.4979282 ''' from pynets.stats.netmotifs import adaptivethresh from pynets.core.thresholding import threshold_absolute from pynets.core.thresholding import standardize from scipy import spatial from nilearn.connectome import sym_matrix_to_vec import pandas as pd import gc mlib = ['1113', '1122', '1223', '2222', '2233', '3333'] # Standardize structural graph struct_mat = standardize(struct_mat) dims_struct = struct_mat.shape[0] struct_mat[range(dims_struct), range(dims_struct)] = 0 at_struct = adaptivethresh(struct_mat, float(0.0), mlib, N) print("%s%s%s" % ('Layer 1 (structural) has: ', np.sum(at_struct), ' total motifs')) # Functional graph threshold window func_mat = standardize(func_mat) dims_func = func_mat.shape[0] func_mat[range(dims_func), range(dims_func)] = 0 tmin_func = func_mat.min() tmax_func = func_mat.max() threshes_func = np.linspace(tmin_func, tmax_func, bins) assert np.all( struct_mat == struct_mat.T), "Structural Matrix must be symmetric" assert np.all( func_mat == func_mat.T), "Functional Matrix must be symmetric" # Count motifs print("%s%s%s%s" % ('Mining ', N, '-node motifs: ', mlib)) motif_dict = {} motif_dict['struct'] = {} motif_dict['func'] = {} mat_dict = {} mat_dict['struct'] = sym_matrix_to_vec(struct_mat, discard_diagonal=True) mat_dict['funcs'] = {} for thr_func in threshes_func: # Count at_func = adaptivethresh(func_mat, float(thr_func), mlib, N) motif_dict['struct']["%s%s" % ('thr-', np.round(thr_func, 4))] = at_struct motif_dict['func']["%s%s" % ('thr-', np.round(thr_func, 4))] = at_func mat_dict['funcs']["%s%s" % ('thr-', np.round(thr_func, 4))] = sym_matrix_to_vec( threshold_absolute(func_mat, thr_func), discard_diagonal=True) print("%s%s%s%s%s" % ('Layer 2 (functional) with absolute threshold of: ', np.round(thr_func, 2), ' yields ', np.sum(at_func), ' total motifs')) gc.collect() df = pd.DataFrame(motif_dict) for idx in range(len(df)): df.set_value( df.index[idx], 'motif_dist', spatial.distance.cosine(df['struct'][idx], df['func'][idx])) df = df[pd.notnull(df['motif_dist'])] for idx in range(len(df)): df.set_value( df.index[idx], 'graph_dist_cosine', spatial.distance.cosine( mat_dict['struct'].reshape(-1, 1), mat_dict['funcs'][df.index[idx]].reshape(-1, 1))) df.set_value( df.index[idx], 'graph_dist_correlation', spatial.distance.correlation( mat_dict['struct'].reshape(-1, 1), mat_dict['funcs'][df.index[idx]].reshape(-1, 1))) df['struct_func_3333'] = np.zeros(len(df)) df['struct_func_2233'] = np.zeros(len(df)) df['struct_func_2222'] = np.zeros(len(df)) df['struct_func_1223'] = np.zeros(len(df)) df['struct_func_1122'] = np.zeros(len(df)) df['struct_func_1113'] = np.zeros(len(df)) df['struct_3333'] = np.zeros(len(df)) df['func_3333'] = np.zeros(len(df)) df['struct_2233'] = np.zeros(len(df)) df['func_2233'] = np.zeros(len(df)) df['struct_2222'] = np.zeros(len(df)) df['func_2222'] = np.zeros(len(df)) df['struct_1223'] = np.zeros(len(df)) df['func_1223'] = np.zeros(len(df)) df['struct_1122'] = np.zeros(len(df)) df['func_1122'] = np.zeros(len(df)) df['struct_1113'] = np.zeros(len(df)) df['func_1113'] = np.zeros(len(df)) for idx in range(len(df)): df.set_value(df.index[idx], 'struct_3333', df['struct'][idx][-1]) df.set_value(df.index[idx], 'func_3333', df['func'][idx][-1]) df.set_value(df.index[idx], 'struct_2233', df['struct'][idx][-2]) df.set_value(df.index[idx], 'func_2233', df['func'][idx][-2]) df.set_value(df.index[idx], 'struct_2222', df['struct'][idx][-3]) df.set_value(df.index[idx], 'func_2222', df['func'][idx][-3]) df.set_value(df.index[idx], 'struct_1223', df['struct'][idx][-4]) df.set_value(df.index[idx], 'func_1223', df['func'][idx][-4]) df.set_value(df.index[idx], 'struct_1122', df['struct'][idx][-5]) df.set_value(df.index[idx], 'func_1122', df['func'][idx][-5]) df.set_value(df.index[idx], 'struct_1113', df['struct'][idx][-6]) df.set_value(df.index[idx], 'func_1113', df['func'][idx][-6]) df['struct_func_3333'] = np.abs(df['struct_3333'] - df['func_3333']) df['struct_func_2233'] = np.abs(df['struct_2233'] - df['func_2233']) df['struct_func_2222'] = np.abs(df['struct_2222'] - df['func_2222']) df['struct_func_1223'] = np.abs(df['struct_1223'] - df['func_1223']) df['struct_func_1122'] = np.abs(df['struct_1122'] - df['func_1122']) df['struct_func_1113'] = np.abs(df['struct_1113'] - df['func_1113']) df = df.drop(columns=['struct', 'func']) df = df.loc[~(df == 0).all(axis=1)] df = df.sort_values(by=[ 'motif_dist', 'graph_dist_cosine', 'graph_dist_correlation', 'struct_func_3333', 'struct_func_2233', 'struct_func_2222', 'struct_func_1223', 'struct_func_1122', 'struct_func_1113', 'struct_3333', 'func_3333', 'struct_2233', 'func_2233', 'struct_2222', 'func_2222', 'struct_1223', 'func_1223', 'struct_1122', 'func_1122', 'struct_1113', 'func_1113' ], ascending=[ True, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False ]) # Take the top 25th percentile df = df.head(int(0.25 * len(df))) best_threshes = [] best_mats = [] best_multigraphs = [] for key in list(df.index): func_mat_tmp = func_mat.copy() struct_mat_tmp = struct_mat.copy() struct_thr = float(key.split('-')[-1]) func_thr = float(key.split('-')[-1]) best_threshes.append(str(func_thr)) func_mat_tmp[func_mat_tmp < func_thr] = 0 struct_mat_tmp[struct_mat_tmp < struct_thr] = 0 best_mats.append((func_mat_tmp, struct_mat_tmp)) mG = build_mx_multigraph(func_mat, struct_mat, f"{name}_{key}", namer_dir) best_multigraphs.append(mG) mg_dict = dict(zip(best_threshes, best_multigraphs)) g_dict = dict(zip(best_threshes, best_mats)) return mg_dict, g_dict