diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b560df3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +*.pyc +__pychache__\* +venv +.idea diff --git a/netNorm.py b/netNorm.py index 2cb628b..3402e0f 100644 --- a/netNorm.py +++ b/netNorm.py @@ -1,101 +1,113 @@ -"""Main function of netNorm for the paper: Estimation of Connectional Brain Templates using Selective Multi -View Network Normalization - Details can be found in: - (1) the original paper https://www.ncbi.nlm.nih.gov/pubmed/31622839 - Salma Dhifallah, and Islem Rekik. - --------------------------------------------------------------------- - This file contains the implementation of three key steps of our netNorm framework: - netNorm(sourceGraph, number_of_subjects, number_of_regions) - Inputs: - sourceGraph: (n × m x t x t) matrix stacking the source graphs of all subjects - n the total number of views - m the number of subjects - t number of regions - Output: - CBT: (t x t) matrix representing the cortical brain template - (2) Dependencies: please install the following libraries: - - matplotlib - - numpy - - snfpy (https://github.com/rmarkello/snfpy) - - scikitlearn - --------------------------------------------------------------------- - Copyright 2019 Salma Dhifallah, Sousse University. - Please cite the above paper if you use this code. - All rights reserved. - """ - import numpy as np import snf from sklearn import preprocessing import matplotlib.pyplot as plt -def netNorm(v, nbr_of_sub, nbr_of_regions): - nbr_of_feat = int((np.square(nbr_of_regions) - nbr_of_regions) / 2) +class NetNorm: + """ + Main function of netNorm for the paper: Estimation of Connectional Brain Templates using Selective Multi + View Network Normalization + Details can be found in: + (1) the original paper https://www.ncbi.nlm.nih.gov/pubmed/31622839 + Salma Dhifallah, and Islem Rekik. + --------------------------------------------------------------------- + This file contains the implementation of three key steps of our netNorm framework: + netNorm(sourceGraph, number_of_subjects, number_of_regions) + Inputs: + sourceGraph: (n × m x t x t) matrix stacking the source graphs of all subjects + n the total number of views + m the number of subjects + t number of regions + Output: + CBT: (t x t) matrix representing the cortical brain template + (2) Dependencies: please install the following libraries: + - matplotlib + - numpy + - snfpy (https://github.com/rmarkello/snfpy) + - scikitlearn + --------------------------------------------------------------------- + Copyright 2019 Salma Dhifallah, Sousse University. + Please cite the above paper if you use this code. + All rights reserved. + """ + + def __init__(self, v_matrix, num_of_sub, num_of_reg): + self.nbr_of_sub = num_of_sub + self.nbr_of_feat = int((np.square(num_of_reg) - num_of_reg) / 2) + self.nbr_of_views = v_matrix.shape[0] + self.nbr_of_regions = num_of_reg + self.v = v_matrix + + @staticmethod def minmax_sc(x): min_max_scaler = preprocessing.MinMaxScaler() x = min_max_scaler.fit_transform(x) return x - def upper_triangular(): - All_subj = np.zeros((nbr_of_sub, len(v), nbr_of_feat)) - for i in range(len(v)): - for j in range (nbr_of_sub): + def upper_triangular(self): + all_subj = np.zeros((self.nbr_of_sub, len(self.v), self.nbr_of_feat)) + for i in range(len(self.v)): + for j in range(self.nbr_of_sub): - subj_x = v[i, j, :, :] - subj_x = np.reshape(subj_x, (nbr_of_regions, nbr_of_regions)) - subj_x = minmax_sc(subj_x) - subj_x = subj_x[np.triu_indices(nbr_of_regions, k = 1)] - subj_x = np.reshape(subj_x, (1, 1, nbr_of_feat)) - All_subj[j, i, :] = subj_x + subj_x = self.v[i, j, :, :] + subj_x = np.reshape(subj_x, (self.nbr_of_regions, self.nbr_of_regions)) + subj_x = self.minmax_sc(subj_x) + subj_x = subj_x[np.triu_indices(self.nbr_of_regions, k=1)] + subj_x = np.reshape(subj_x, (1, 1, self.nbr_of_feat)) + all_subj[j, i, :] = subj_x - return All_subj + return all_subj - def distances_inter(All_subj): + def distances_inter(self, all_subj): theta = 0 distance_vector = np.zeros(1) distance_vector_final = np.zeros(1) - x = All_subj - for i in range(nbr_of_feat): #par rapport ll number of ROIs - ROI_i = x[:, :, i] - ROI_i = np.reshape(ROI_i, (nbr_of_sub, nbr_of_views)) #1,3 - for j in range(nbr_of_sub): - subj_j = ROI_i[j:j+1, :] - subj_j = np.reshape(subj_j, (1, nbr_of_views)) - for k in range(nbr_of_sub): + x = all_subj + distance_euclidienne_sub_j_sub_k = None + for i in range(self.nbr_of_feat): # par rapport ll number of ROIs + roi_i = x[:, :, i] + roi_i = np.reshape(roi_i, (self.nbr_of_sub, self.nbr_of_views)) # 1,3 + for j in range(self.nbr_of_sub): + subj_j = roi_i[j:j+1, :] + subj_j = np.reshape(subj_j, (1, self.nbr_of_views)) + for k in range(self.nbr_of_sub): if k != j: - subj_k = ROI_i[k:k+1, :] - subj_k = np.reshape(subj_k, (1, nbr_of_views)) + subj_k = roi_i[k:k+1, :] + subj_k = np.reshape(subj_k, (1, self.nbr_of_views)) - for l in range(nbr_of_views): - if l ==0: + for l in range(self.nbr_of_views): + if distance_euclidienne_sub_j_sub_k is None: distance_euclidienne_sub_j_sub_k = np.square(subj_k[:, l:l+1] - subj_j[:, l:l+1]) else: - distance_euclidienne_sub_j_sub_k = distance_euclidienne_sub_j_sub_k + np.square(subj_k[:, l:l+1] - subj_j[:, l:l+1]) + distance_euclidienne_sub_j_sub_k = distance_euclidienne_sub_j_sub_k + np.square( + subj_k[:, l:l+1] - subj_j[:, l:l+1] + ) - theta +=1 - if j ==0: + theta += 1 + if j == 0: distance_vector = np.sqrt(distance_euclidienne_sub_j_sub_k) else: - distance_vector = np.concatenate((distance_vector, np.sqrt(distance_euclidienne_sub_j_sub_k)), axis=0) + distance_vector = np.concatenate((distance_vector, np.sqrt( + distance_euclidienne_sub_j_sub_k)), axis=0 + ) - if i ==0: + if i == 0: distance_vector_final = distance_vector else: distance_vector_final = np.concatenate((distance_vector_final, distance_vector), axis=1) - print(theta) return distance_vector_final - - def minimum_distances(distance_vector_final): + def minimum_distances(self, distance_vector_final): x = distance_vector_final + general_minimum = final_general_minimum = None - for i in range(nbr_of_feat): - for j in range(nbr_of_sub): + for i in range(self.nbr_of_feat): + for j in range(self.nbr_of_sub): minimum_sub = x[j:j+1, i:i+1] minimum_sub = float(minimum_sub) - for k in range(nbr_of_sub): + for k in range(self.nbr_of_sub): if k != j: local_sub = x[k:k+1, i:i+1] local_sub = float(local_sub) @@ -111,94 +123,100 @@ def minimum_distances(distance_vector_final): return final_general_minimum - def new_tensor(final_general_minimum, All_subj): - y = All_subj + def new_tensor(self, final_general_minimum, all_subj): + y = all_subj x = final_general_minimum - for i in range(nbr_of_feat): + final_new_tensor = None + for i in range(self.nbr_of_feat): optimal_subj = x[:, i:i+1] - optimal_subj = np.reshape(optimal_subj, (1)) + optimal_subj = np.reshape(optimal_subj, (1,)) optimal_subj = int(optimal_subj) - if i ==0: + if final_new_tensor is None: final_new_tensor = y[optimal_subj: optimal_subj+1, :, i:i+1] else: final_new_tensor = np.concatenate((final_new_tensor, y[optimal_subj: optimal_subj+1, :, i:i+1]), axis=2) return final_new_tensor + def make_sym_matrix(self, feature_vector): - def make_sym_matrix(nbr_of_regions, feature_vector): - - nbr_of_regions = nbr_of_regions - feature_vector = feature_vector - my_matrix = np.zeros([nbr_of_regions,nbr_of_regions], dtype=np.double) + my_matrix = np.zeros([self.nbr_of_regions, self.nbr_of_regions], dtype=np.double) - my_matrix[np.triu_indices(nbr_of_regions, k=1)] = feature_vector + my_matrix[np.triu_indices(self.nbr_of_regions, k=1)] = feature_vector my_matrix = my_matrix + my_matrix.T - my_matrix[np.diag_indices(nbr_of_regions)] = 0 + my_matrix[np.diag_indices(self.nbr_of_regions)] = 0 return my_matrix - def re_make_tensor(final_new_tensor, nbr_of_regions): - x =final_new_tensor - x = np.reshape(x, (nbr_of_views, nbr_of_feat)) - for i in range (nbr_of_views): + def re_make_tensor(self, final_new_tensor): + x = final_new_tensor + x = np.reshape(x, (self.nbr_of_views, self.nbr_of_feat)) + tensor_for_snf = None + for i in range(self.nbr_of_views): view_x = x[i, :] - view_x = np.reshape(view_x, (1, nbr_of_feat)) - view_x = make_sym_matrix(nbr_of_regions, view_x) - view_x = np.reshape(view_x, (1, nbr_of_regions, nbr_of_regions)) - if i ==0: + view_x = np.reshape(view_x, (1, self.nbr_of_feat)) + view_x = self.make_sym_matrix(view_x) + view_x = np.reshape(view_x, (1, self.nbr_of_regions, self.nbr_of_regions)) + if tensor_for_snf is None: tensor_for_snf = view_x else: tensor_for_snf = np.concatenate((tensor_for_snf, view_x), axis=0) return tensor_for_snf - def create_list(tensor_for_snf): - x =tensor_for_snf - for i in range(nbr_of_views): + def create_list(self, tensor_for_snf): + x = tensor_for_snf + list_final = list() + for i in range(self.nbr_of_views): view = x[i, :, :] - view = np.reshape(view, (nbr_of_regions, nbr_of_regions)) - list = [view] - if i ==0: - list_final = list - else: - list_final = list_final +list + view = np.reshape(view, (self.nbr_of_regions, self.nbr_of_regions)) + list_final.append(view) return list_final - def cross_subjects_cbt(fused_network, nbr_of_exemples): - final_cbt = np.zeros((nbr_of_exemples, nbr_of_feat)) + # not used + def cross_subjects_cbt(self, fused_network, nbr_of_examples): + final_cbt = np.zeros((nbr_of_examples, self.nbr_of_feat)) x = fused_network - x = x[np.triu_indices(nbr_of_regions, k=1)] - x = np.reshape(x, (1, nbr_of_feat)) - for i in range(nbr_of_exemples): + x = x[np.triu_indices(self.nbr_of_regions, k=1)] + x = np.reshape(x, (1, self.nbr_of_feat)) + for i in range(nbr_of_examples): final_cbt[i, :] = x - return final_cbt - Upp_trig = upper_triangular() - Dis_int = distances_inter(Upp_trig) - Min_dis = minimum_distances(Dis_int) - New_ten = new_tensor(Min_dis, Upp_trig) - Re_ten = re_make_tensor(New_ten, nbr_of_regions) - Cre_lis = create_list(Re_ten) - fused_network = snf.snf((Cre_lis), K=20) - fused_network = minmax_sc(fused_network) - np.fill_diagonal(fused_network, 0) - fused_network = np.array(fused_network) - return fused_network - -nbr_of_sub = int(input('Please select the number of subjects: ')) -nbr_of_regions = int(input('Please select the number of regions: ')) -nbr_of_views= int(input('Please select the number of views: ')) - -v = np.random.rand(nbr_of_views, nbr_of_sub,nbr_of_regions, nbr_of_regions) -A = netNorm(v, nbr_of_sub, nbr_of_regions) -print(A) - -mx = A.max() -mn = A.min() -print(mx) -print(mn) -plt.pcolor(A, vmin=mn, vmax=mx) -plt.imshow(A) -plt.show() + def run(self): + upp_trig = self.upper_triangular() + dis_int = self.distances_inter(upp_trig) + min_distances = self.minimum_distances(dis_int) + new_tensor = self.new_tensor(min_distances, upp_trig) + re_tensor = self.re_make_tensor(new_tensor) + cre_lis = self.create_list(re_tensor) + fused_network = snf.snf(cre_lis, K=20) + fused_network = self.minmax_sc(fused_network) + np.fill_diagonal(fused_network, 0) + fused_network = np.array(fused_network) + return fused_network + + +# work if file not imported +if __name__ == "__main__": + + # take user inputs + nbr_of_sub = int(input('Please select the number of subjects: ')) + nbr_of_regions = int(input('Please select the number of regions: ')) + nbr_of_views = int(input('Please select the number of views: ')) + + # get random views and calculate example CBT + v = np.random.rand(nbr_of_views, nbr_of_sub, nbr_of_regions, nbr_of_regions) + nn = NetNorm(v, nbr_of_sub, nbr_of_regions) + + # run operations + A = nn.run() + + # print min and max values + mx = A.max() + mn = A.min() + + # plot the final CBT matrix + plt.pcolor(A, vmin=mn, vmax=mx) + plt.imshow(A) + plt.show() diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..888507e --- /dev/null +++ b/requirements.txt @@ -0,0 +1,11 @@ +cycler==0.10.0 +joblib==0.14.1 +kiwisolver==1.2.0 +matplotlib==3.2.1 +numpy==1.18.3 +pyparsing==2.4.7 +python-dateutil==2.8.1 +scikit-learn==0.22.2.post1 +scipy==1.4.1 +six==1.14.0 +snfpy==0.2.2