OSCR

A multidimensional framework for dissociating the neuroplasticity of auditory and early language deprivation.

Code ↔ Paper

10 matches between paragraphs of the paper and lines of its authors' code, computed by the harvester (lexical-v1). Click a colored paragraph or line to see its counterpart.

The 10 matches
  1. [1] § Materials and methods › Cluster analysis of intrinsic functional dimensions across cortical networks ↔ Code/S03_stats_the_rsFC_gradient_2group_model_AD_effect.ipynb, lines 508 to 542 · score 0.79 · co occurrence matrix, n_components, silhouette scoring, Ward, linkage, PCA · Report a mismatch
  2. [2] § Materials and methods › Cluster analysis of intrinsic functional dimensions across cortical networks ↔ Code/S04_stats_the_rsFC_gradient_2group_model_ELD_effect.ipynb, lines 509 to 543 · score 0.79 · co occurrence matrix, n_components, silhouette scoring, Ward, linkage, PCA · Report a mismatch
  3. [3] § Materials and methods › Reconstruction of brain activity with intrinsic functional dimensions ↔ Code/S05_the_rsFC_gradient_rest_predict_task_activation.ipynb, lines 348 to 461 · score 0.79 · predicted task activation, Pearson correlation, FC gradient features, 1–10, incrementally, regression · Report a mismatch
  4. [4] § Materials and methods › Reconstruction of brain activity with intrinsic functional dimensions ↔ Code/S05_the_rsFC_gradient_rest_predict_task_activation.ipynb, lines 348 to 461 · score 0.70 · linear regression model, task activation, 1–10, FC gradients, predict, scored · Report a mismatch
  5. [5] § Materials and methods › Building ridge classifier models based on intrinsic functional dimensions ↔ Code/S02_Calculate_the_rsFC_gradient_2group_classify_model.ipynb, lines 198 to 316 · score 0.66 · Ridge classifier, linear explainer, trained, SHAP, score, ROI · Report a mismatch
  6. [6] § Materials and methods › Computation of the gradients of the resting-state FC ↔ Code/S01_Calculate_the_resting_state_gradient_2group.ipynb, lines 449 to 470 · score 0.61 · Procrustes alignment, FC gradients, template, deaf · Report a mismatch
  7. [7] § Results › The effects of auditory and early language deprivation exhibit dissociation between the dominant and subdominant dimensions › Global feature analysis of the dominant and subdominant dimensio ↔ Code/S04_stats_the_rsFC_gradient_2group_model_ELD_effect.ipynb, lines 1746 to 1883 · score 0.56 · G1 G3, G4 G10, Dom, Sub, LAN, ELD · Report a mismatch
  8. [8] § Results › The effects of auditory and early language deprivation exhibit dissociation between the dominant and subdominant dimensions › Global feature analysis of the dominant and subdominant dimensio ↔ Code/S03_stats_the_rsFC_gradient_2group_model_AD_effect.ipynb, lines 1430 to 1568 · score 0.55 · G1 G3, G4 G10, Dom, Sub, AD, clusters · Report a mismatch
  9. [9] § Materials and methods › Volumetric-to-surface mapping ↔ Code/S05_the_rsFC_gradient_rest_predict_task_activation.ipynb, lines 16 to 47 · score 0.51 · fs lr, Geometry, lh, rh, surf, templates · Report a mismatch
  10. [10] § Materials and methods › Volumetric-to-surface mapping ↔ Code/S01_Calculate_the_resting_state_gradient_2group.ipynb, lines 16 to 47 · score 0.51 · fs lr, Geometry, lh, rh, surf, templates · Report a mismatch

Paper

Loaded from Europe PMC by your browser; OSCR does not store it: doi.org · Europe PMC

The paper is loaded when this pane is shown.

The authors' code

Jupyter notebook · 1,605 lines · 56 KB · no license · 3 matches

  1. # %%
  2. import matplotlib.pyplot as plt
  3. import numpy as np
  4. import pandas as pd
  5. from scipy.stats import zscore
  6. from sklearn.metrics.pairwise import cosine_similarity
  7. import seaborn as sns
  8. from collections import Counter
  9. import ActflowToolbox as actflow
  10. # %%
  11. ##加载cole模板网络标签
  12. roi_path = 'F:/early_language__experienced_data/经验期待和经验依赖分析/ROI/ColeAnticevicNetPartition/'
  13. labels = pd.read_excel(roi_path + 'CAB-NP_v1.1_Labels-ReorderedbyNetworks.xlsx')['NETWORKKEY'][0:360]
  14. # %%
  15. import h5py, sys, io, numpy as np
  16. import nibabel as nib
  17. path = 'F:/early_language__experienced_data/经验期待和经验依赖分析/功能梯度/code/gradient_analysis-master/gradient_data/templates/'
  18. surfmL = nib.freesurfer.read_geometry(path + 'S900.L.midthickness_MSMAll.32k_fs_LR.surf')
  19. surfiL = nib.freesurfer.read_geometry(path + 'S900.L.very_inflated_MSMAll.32k_fs_LR.surf')
  20. surfL = []
  21. surfL.append(np.array(surfmL[0]*0.3 + surfiL[0]*0.7))
  22. surfL.append(surfmL[1])
  23. surfmR = nib.freesurfer.read_geometry(path + 'S900.R.midthickness_MSMAll.32k_fs_LR.surf')
  24. surfiR = nib.freesurfer.read_geometry(path + 'S900.R.very_inflated_MSMAll.32k_fs_LR.surf')
  25. surfR = []
  26. surfR.append(np.array(surfmR[0]*0.3 + surfiR[0]*0.7))
  27. surfR.append(surfmR[1])
  28. res = nib.load(path +'hcp.tmp.lh.dscalar.nii').get_fdata()
  29. cortL = np.squeeze(np.array(np.where(res != 0)[1], dtype=np.int32))
  30. res = nib.load(path +'hcp.tmp.rh.dscalar.nii').get_fdata()
  31. cortR = np.squeeze(np.array(np.where(res != 0)[1], dtype=np.int32))
  32. cortLen = len(cortL) + len(cortR)
  33. del res
  34. sulcL = np.zeros(len(surfL[0]))
  35. sulcR = np.zeros(len(surfR[0]))
  36. #MSMAll是一种表皮功能对齐的工具
  37. sulcL[cortL] = -1 * nib.load(path + 'S1200.sulc_MSMAll.32k_fs_LR.dscalar.nii').get_fdata()[0,:len(cortL)]
  38. sulcR[cortR] = -1 * nib.load(path + 'S1200.sulc_MSMAll.32k_fs_LR.dscalar.nii').get_fdata()[0,len(cortL)::]
  39. sulcL[np.setdiff1d(range(32492),cortL)] = -1 * nib.load(path + 'Q1-Q6_R440.sulc.32k_fs_LR.dscalar.nii').get_fdata()[0,np.setdiff1d(range(32492),cortL)]
  40. sulcR[np.setdiff1d(range(32492),cortR)] = -1 * nib.load(path + 'Q1-Q6_R440.sulc.32k_fs_LR.dscalar.nii').get_fdata()[0,32492+np.setdiff1d(range(32492),cortR)]
  41. # %% [markdown]
  42. # # 绘制语言激活图
  43. # %%
  44. # 静息态平均梯度画图
  45. from brainspace.gradient import ProcrustesAlignment
  46. import numpy as np
  47. import pickle
  48. import matplotlib.pyplot as plt
  49. from neuromaps.datasets import fetch_fslr
  50. from surfplot import Plot
  51. from brainspace.datasets import load_parcellation
  52. from nilearn.plotting.cm import _cmap_d as nilearn_cmaps
  53. from matplotlib.colors import LinearSegmentedColormap,ListedColormap
  54. # Load and prepare task
  55. out_path = 'J:/HCP_analysis/DEAF/10_rest_predict_task/'
  56. path = 'J:/HCP_analysis/DEAF/data_DF_cole/BLOCK/'
  57. task = np.load(path + 'combined_all_tasks.npy') #91,360,8non language
  58. task_mean = np.mean(task[61:, :, :8], axis = (0,2))
  59. task_mean = zscore(task_mean)
  60. emb = task_mean[:,np.newaxis]
  61. ##加载cole模板
  62. surfaces = fetch_fslr()
  63. lh, rh = surfaces['veryinflated']
  64. p = Plot(lh, rh,brightness=.6)
  65. Cole_path = 'F:/early_language__experienced_data/经验期待和经验依赖分析/ROI/ColeAnticevicNetPartition/'
  66. coleLR = nib.load(Cole_path+'Glasser360Indices_LR.dscalar.nii').get_fdata()[:, 0:64984]
  67. #把模板填入到完整的皮层中
  68. for i in range(360):
  69. coleLR[coleLR==i+1] = emb[i,0]
  70. cifti = coleLR.T
  71. dataL = np.zeros((len(surfL[0]), cifti.shape[1]))
  72. dataL[cortL,:] = cifti[0:len(cortL),:]
  73. dataR = np.zeros((len(surfR[0]), cifti.shape[1]))
  74. dataR[cortR,:] = cifti[len(cortL):cortLen,:]
  75. cmap = nilearn_cmaps['brown_cyan']
  76. # 翻转色阶,将深色设置在两端
  77. colors = cmap(np.linspace(0, 1, cmap.N))
  78. colors = np.concatenate([colors[-int(cmap.N/2):], colors[:int(cmap.N/2)]], axis=0)
  79. new_cmap = LinearSegmentedColormap.from_list('custom', colors)
  80. p.add_layer({'left': dataL, 'right': dataR}, cmap=new_cmap, cbar=True)
  81. fig = p.build()
  82. plt.savefig(out_path + 'task_language_activation_NON-ELA.png', dpi=300, bbox_inches='tight')
  83. fig.show()
  84. # %%
  85. # 静息态平均梯度画图
  86. from brainspace.gradient import ProcrustesAlignment
  87. import numpy as np
  88. import pickle
  89. import matplotlib.pyplot as plt
  90. from neuromaps.datasets import fetch_fslr
  91. from surfplot import Plot
  92. from brainspace.datasets import load_parcellation
  93. from nilearn.plotting.cm import _cmap_d as nilearn_cmaps
  94. from matplotlib.colors import LinearSegmentedColormap,ListedColormap
  95. # Load and prepare task
  96. path = 'J:/HCP_analysis/DEAF/1_gradient/'
  97. out_path = 'J:/HCP_analysis/DEAF/10_rest_predict_task/'
  98. emb_all = np.load(path + 'restFC_align_Gradients_10.npy') # emb_all.shape(91, 360, 10)
  99. path = 'J:/HCP_analysis/DEAF/data_DF_cole/BLOCK/'
  100. task1 = np.load(path + 'combined_all_tasks.npy')[:, :, :8] #91,360,8 language
  101. task1 = np.mean(task1, axis = 2)
  102. task2 = np.load(path + 'combined_all_tasks.npy')[:, :, 8] #91,360,1 non language
  103. task = task1 - task2
  104. task_mean = np.mean(task[:34], axis = 0)
  105. emb = task_mean[:,np.newaxis]
  106. ##加载cole模板
  107. surfaces = fetch_fslr()
  108. lh, rh = surfaces['veryinflated']
  109. p = Plot(lh, rh,brightness=.6)
  110. Cole_path = 'F:/early_language__experienced_data/经验期待和经验依赖分析/ROI/ColeAnticevicNetPartition/'
  111. coleLR = nib.load(Cole_path+'Glasser360Indices_LR.dscalar.nii').get_fdata()[:, 0:64984]
  112. #把模板填入到完整的皮层中
  113. for i in range(360):
  114. coleLR[coleLR==i+1] = emb[i,0]
  115. cifti = coleLR.T
  116. dataL = np.zeros((len(surfL[0]), cifti.shape[1]))
  117. dataL[cortL,:] = cifti[0:len(cortL),:]
  118. dataR = np.zeros((len(surfR[0]), cifti.shape[1]))
  119. dataR[cortR,:] = cifti[len(cortL):cortLen,:]
  120. cmap = nilearn_cmaps['brown_cyan']
  121. # 翻转色阶,将深色设置在两端
  122. colors = cmap(np.linspace(0, 1, cmap.N))
  123. colors = np.concatenate([colors[-int(cmap.N/2):], colors[:int(cmap.N/2)]], axis=0)
  124. new_cmap = LinearSegmentedColormap.from_list('custom', colors)
  125. p.add_layer({'left': dataL, 'right': dataR}, cmap=new_cmap, cbar=True)
  126. fig = p.build()
  127. plt.savefig(out_path + 'task_language_activation_hearing_reverse.png', dpi=300, bbox_inches='tight')
  128. fig.show()
  129. # %%
  130. # 静息态平均梯度画图
  131. from brainspace.gradient import ProcrustesAlignment
  132. import numpy as np
  133. import pickle
  134. import matplotlib.pyplot as plt
  135. from neuromaps.datasets import fetch_fslr
  136. from surfplot import Plot
  137. from brainspace.datasets import load_parcellation
  138. from nilearn.plotting.cm import _cmap_d as nilearn_cmaps
  139. from matplotlib.colors import LinearSegmentedColormap,ListedColormap
  140. # Load and prepare task
  141. out_path = 'J:/HCP_analysis/DEAF/10_rest_predict_task/'
  142. predict_y = np.load(out_path + 'Y_pred_gradient_predict_task.npy') # emb_all.shape(91, 360, 10)
  143. predict_y_mean = np.mean(predict_y[:34], axis = (0,1))
  144. emb = predict_y_mean[:,np.newaxis]
  145. ##加载cole模板
  146. surfaces = fetch_fslr()
  147. lh, rh = surfaces['veryinflated']
  148. p = Plot(lh, rh,brightness=.6)
  149. Cole_path = 'F:/early_language__experienced_data/经验期待和经验依赖分析/ROI/ColeAnticevicNetPartition/'
  150. coleLR = nib.load(Cole_path+'Glasser360Indices_LR.dscalar.nii').get_fdata()[:, 0:64984]
  151. #把模板填入到完整的皮层中
  152. for i in range(360):
  153. coleLR[coleLR==i+1] = emb[i,0]
  154. cifti = coleLR.T
  155. dataL = np.zeros((len(surfL[0]), cifti.shape[1]))
  156. dataL[cortL,:] = cifti[0:len(cortL),:]
  157. dataR = np.zeros((len(surfR[0]), cifti.shape[1]))
  158. dataR[cortR,:] = cifti[len(cortL):cortLen,:]
  159. cmap = nilearn_cmaps['brown_cyan']
  160. # 翻转色阶,将深色设置在两端
  161. colors = cmap(np.linspace(0, 1, cmap.N))
  162. colors = np.concatenate([colors[-int(cmap.N/2):], colors[:int(cmap.N/2)]], axis=0)
  163. new_cmap = LinearSegmentedColormap.from_list('custom', colors)
  164. p.add_layer({'left': dataL, 'right': dataR}, cmap=new_cmap, cbar=True)
  165. fig = p.build()
  166. plt.savefig(out_path + 'task_language_predict_activation_hearing.png', dpi=300, bbox_inches='tight')
  167. fig.show()
  168. # %% [markdown]
  169. # # 使用静息态梯度的神经可塑性重构实际任务的激活差值
  170. # %%
  171. import numpy as np
  172. import shap
  173. from sklearn.linear_model import Ridge
  174. from scipy.stats import pearsonr
  175. import matplotlib.pyplot as plt
  176. from sklearn.linear_model import LinearRegression
  177. from scipy.stats import zscore
  178. # Load and prepare task
  179. path = 'J:/HCP_analysis/DEAF/1_gradient/'
  180. out_path = 'J:/HCP_analysis/DEAF/10_rest_predict_task/'
  181. emb_all = np.load(path + 'restFC_align_Gradients_10.npy') # emb_all.shape(91, 360, 10)
  182. path = 'J:/HCP_analysis/DEAF/data_DF_cole/BLOCK/'
  183. task_combined = np.load(path + 'combined_all_tasks.npy')[:, :, :8] #91,360,4 non language
  184. subs = 91
  185. features = 10
  186. blocks = 8
  187. tasks = 2
  188. rois = 360
  189. # Initialize result arrays
  190. corr_predict_ind = np.zeros((subs, tasks, blocks, 3))
  191. Y_pred_all = np.zeros((subs, tasks, blocks, rois))
  192. shap_values_all = np.zeros((subs, tasks, blocks, features)) # For storing SHAP values
  193. for d, task in enumerate(task_combined):
  194. for sub in range(subs):
  195. for block in range(blocks):
  196. # Prepare data
  197. X = zscore(emb_all[sub], axis=0) # Resting-state gradients (360, 10)
  198. Y = zscore(task[sub, :, block]) # Task activation (360,)
  199. # Fit linear regression model
  200. model = LinearRegression()
  201. model.fit(X, Y)
  202. # Compute predictions
  203. Y_pred = model.predict(X)
  204. Y_pred_all[sub, :, d] = Y_pred
  205. # Calculate statistics
  206. r_squared = model.score(X, Y)
  207. corr, p_value = pearsonr(Y, Y_pred)
  208. # Store results
  209. corr_predict_ind[sub, d, block, 0] = corr
  210. corr_predict_ind[sub, d, block, 1] = p_value
  211. corr_predict_ind[sub, d, block, 2] = r_squared
  212. # SHAP analysis
  213. explainer = shap.Explainer(model.predict, X)
  214. shap_values = explainer(X)
  215. # Average absolute SHAP values across ROIs
  216. shap_values_all[sub, d, block] = np.mean(np.abs(shap_values.values), axis=0)
  217. # Save results
  218. np.save(out_path + 'gradient_predict_task.npy', corr_predict_ind)
  219. np.save(out_path + 'Y_pred_gradient_predict_task.npy', Y_pred_all)
  220. np.save(out_path + 'shap_feature_importance.npy', shap_values_all)
  221. # Calculate and save mean SHAP values across subjects and tasks
  222. mean_shap = np.mean(shap_values_all, axis=(0, 1, 2))
  223. np.save(out_path + 'mean_shap_feature_importance.npy', mean_shap)
  224. # Plot mean SHAP importance
  225. plt.figure(figsize=(10, 6))
  226. plt.bar(range(features), mean_shap)
  227. plt.title('Average SHAP Feature Importance')
  228. plt.xlabel('Gradient Feature')
  229. plt.ylabel('Mean |SHAP value|')
  230. plt.savefig(out_path + 'mean_shap_feature_importance.png')
  231. plt.close()
  232. print("Analysis completed and results saved.")
  233. # %%
  234. import numpy as np
  235. import shap
  236. from sklearn.linear_model import Ridge
  237. from scipy.stats import pearsonr
  238. import matplotlib.pyplot as plt
  239. from sklearn.linear_model import LinearRegression
  240. from scipy.stats import zscore
  241. # Load and prepare task
  242. path = 'J:/HCP_analysis/DEAF/1_gradient/'
  243. out_path = 'J:/HCP_analysis/DEAF/10_rest_predict_task/'
  244. emb_all = np.load(path + 'restFC_align_Gradients_10.npy') # emb_all.shape(91, 360, 10)
  245. path = 'J:/HCP_analysis/DEAF/data_DF_cole/BLOCK/'
  246. task = np.load(path + 'combined_all_tasks.npy')[:, :, :8] #91,360,8 non language
  247. subs = 91
  248. features = 10
  249. rois = 360
  250. blocks = 8
  251. # Initialize result arrays
  252. corr_predict_ind = np.zeros((subs, blocks, 3))
  253. Y_pred_all = np.zeros((subs, blocks, rois))
  254. shap_values_all = np.zeros((subs, blocks, features)) # For storing SHAP values
  255. for sub in range(subs):
  256. for block in range(blocks):
  257. # Prepare data
  258. X = zscore(emb_all[sub], axis=0) # Resting-state gradients (360, 10)
  259. Y = zscore(task[sub, :, block]) # Task activation (360,)
  260. # Fit linear regression model
  261. model = LinearRegression()
  262. model.fit(X, Y)
  263. # Compute predictions
  264. Y_pred = model.predict(X)
  265. Y_pred_all[sub, block, :] = Y_pred
  266. # Calculate statistics
  267. r_squared = model.score(X, Y)
  268. corr, p_value = pearsonr(Y, Y_pred)
  269. # Store results
  270. corr_predict_ind[sub, block, 0] = corr
  271. corr_predict_ind[sub, block, 1] = p_value
  272. corr_predict_ind[sub, block, 2] = r_squared
  273. # SHAP analysis
  274. explainer = shap.Explainer(model.predict, X)
  275. shap_values = explainer(X)
  276. # Average absolute SHAP values across ROIs
  277. shap_values_all[sub, block] = np.mean(np.abs(shap_values.values), axis=0)
  278. # Save results
  279. np.save(out_path + 'gradient_predict_task.npy', corr_predict_ind)
  280. np.save(out_path + 'Y_pred_gradient_predict_task.npy', Y_pred_all)
  281. np.save(out_path + 'shap_feature_importance.npy', shap_values_all)
  282. # Calculate and save mean SHAP values across subjects and tasks
  283. mean_shap = np.mean(shap_values_all, axis=(0, 1, 2))
  284. np.save(out_path + 'mean_shap_feature_importance.npy', mean_shap)
  285. # Plot mean SHAP importance
  286. plt.figure(figsize=(10, 6))
  287. plt.bar(range(features), mean_shap)
  288. plt.title('Average SHAP Feature Importance')
  289. plt.xlabel('Gradient Feature')
  290. plt.ylabel('Mean |SHAP value|')
  291. plt.savefig(out_path + 'mean_shap_feature_importance.png')
  292. plt.close()
  293. print("Analysis completed and results saved.")
  294. # %% [markdown]
  295. # # 循环增加特征
  296. # %%
  297. import numpy as np
  298. import shap
  299. from sklearn.linear_model import Ridge
  300. from scipy.stats import pearsonr
  301. import matplotlib.pyplot as plt
  302. from sklearn.linear_model import LinearRegression
  303. from scipy.stats import zscore
  304. # Load and prepare task
  305. path = 'J:/HCP_analysis/DEAF/1_gradient/'
  306. out_path = 'J:/HCP_analysis/DEAF/10_rest_predict_task/'
  307. emb_all = np.load(path + 'restFC_align_Gradients_10.npy') # emb_all.shape(91, 360, 10)
  308. path = 'J:/HCP_analysis/DEAF/data_DF_cole/BLOCK/'
  309. task = np.load(path + 'combined_all_tasks.npy')[:, :, :8] #91,360,4 non language
  310. subs = 91
  311. features = 10
  312. blocks = 8
  313. rois = 360 # Added this since it was used but not defined
  314. # Initialize result arrays for all feature combinations
  315. # We'll have results for each feature count (1-10), each subject, each block
  316. corr_predict_ind = np.zeros((features, subs, blocks, 3)) # Now shape (10, 91, 4, 3)
  317. Y_pred_all = np.zeros((features, subs, blocks, rois)) # Now shape (10, 91, 4, 360)
  318. shap_values_all = np.zeros((features, subs, blocks, features)) # Now shape (10, 91, 4, 10)
  319. for num_features in range(1, features+1): # Loop from 1 to 10 features
  320. print(f"Processing models with {num_features} features...")
  321. for sub in range(subs):
  322. for block in range(blocks):
  323. # Prepare data - use only the first num_features features
  324. X = zscore(emb_all[sub, :, :num_features], axis=0) # (360, num_features)
  325. Y = zscore(task[sub, :, block]) # Task activation (360,)
  326. # Fit linear regression model
  327. model = LinearRegression()
  328. model.fit(X, Y)
  329. # Compute predictions
  330. Y_pred = model.predict(X)
  331. Y_pred_all[num_features-1, sub, block, :] = Y_pred # num_features-1 for 0-based index
  332. # Calculate statistics
  333. r_squared = model.score(X, Y)
  334. corr, p_value = pearsonr(Y, Y_pred)
  335. # Store results
  336. corr_predict_ind[num_features-1, sub, block, 0] = corr
  337. corr_predict_ind[num_features-1, sub, block, 1] = p_value
  338. corr_predict_ind[num_features-1, sub, block, 2] = r_squared
  339. # SHAP analysis
  340. explainer = shap.Explainer(model.predict, X)
  341. shap_values = explainer(X)
  342. # Store SHAP values (only the first num_features will have values)
  343. shap_values_all[num_features-1, sub, block, :num_features] = np.mean(np.abs(shap_values.values), axis=0)
  344. # Save results
  345. np.save(out_path + 'gradient_predict_task_by_feature_count.npy', corr_predict_ind)
  346. np.save(out_path + 'Y_pred_gradient_predict_task_by_feature_count.npy', Y_pred_all)
  347. np.save(out_path + 'shap_feature_importance_by_feature_count.npy', shap_values_all)
  348. # Calculate and save mean results across subjects and tasks for each feature count
  349. mean_corr = np.mean(corr_predict_ind[:,:,:,0], axis=(1,2)) # Mean correlation for each feature count
  350. mean_r2 = np.mean(corr_predict_ind[:,:,:,2], axis=(1,2)) # Mean R-squared for each feature count
  351. mean_shap = np.zeros((features, features)) # Will store mean SHAP for each feature at each feature count
  352. for num_features in range(features):
  353. # For each feature count, calculate mean SHAP values for the features used
  354. mean_shap[num_features, :num_features+1] = np.mean(shap_values_all[num_features, :, :, :num_features+1], axis=(0,1))
  355. np.save(out_path + 'mean_correlation_by_feature_count.npy', mean_corr)
  356. np.save(out_path + 'mean_r2_by_feature_count.npy', mean_r2)
  357. np.save(out_path + 'mean_shap_by_feature_count.npy', mean_shap)
  358. # Plot results
  359. plt.figure(figsize=(12, 8))
  360. # Plot mean correlation by feature count
  361. plt.subplot(2, 2, 1)
  362. plt.plot(range(1, features+1), mean_corr, marker='o')
  363. plt.title('Mean Prediction Correlation by Number of Features')
  364. plt.xlabel('Number of Features')
  365. plt.ylabel('Mean Pearson Correlation')
  366. # Plot mean R-squared by feature count
  367. plt.subplot(2, 2, 2)
  368. plt.plot(range(1, features+1), mean_r2, marker='o')
  369. plt.title('Mean R-squared by Number of Features')
  370. plt.xlabel('Number of Features')
  371. plt.ylabel('Mean R-squared')
  372. # Plot SHAP importance heatmap
  373. plt.subplot(2, 1, 2)
  374. plt.imshow(mean_shap.T, aspect='auto', cmap='viridis')
  375. plt.colorbar(label='Mean |SHAP value|')
  376. plt.title('SHAP Feature Importance by Number of Features Used')
  377. plt.xlabel('Number of Features Used in Model')
  378. plt.ylabel('Gradient Feature')
  379. plt.yticks(range(features), range(1, features+1))
  380. plt.xticks(range(features), range(1, features+1))
  381. plt.tight_layout()
  382. plt.savefig(out_path + 'feature_incremental_results.png')
  383. plt.close()
  384. print("Analysis completed and results saved.")
  385. # %% [markdown]
  386. # # 断点回归分析
  387. # %%
  388. import numpy as np
  389. import matplotlib.pyplot as plt
  390. from sklearn.linear_model import LinearRegression
  391. from scipy.stats import ttest_1samp, ttest_rel, zscore
  392. import seaborn as sns
  393. # Load data
  394. out_path = 'J:/HCP_analysis/DEAF/10_rest_predict_task/'
  395. corr = np.load(out_path + 'gradient_predict_task_by_feature_count.npy')[:, :, :, 0] # (10, 91, 9)
  396. # Preprocess: Fisher z-transform but don't average across blocks
  397. corr_z = np.arctanh(corr) # (10, 91, 8)
  398. # Define breakpoint (cutoff=3)
  399. cutoff = 2
  400. dimensions = np.arange(10) # 0-9
  401. # Initialize storage for results
  402. n_subjects = corr_z.shape[1]
  403. n_blocks = corr_z.shape[2]
  404. slopes_low = np.zeros((n_subjects, n_blocks)) # Low-dim slopes for each subject and block
  405. slopes_high = np.zeros((n_subjects, n_blocks)) # High-dim slopes
  406. jump_effects = np.zeros((n_subjects, n_blocks)) # Jump effects
  407. for subj in range(n_subjects):
  408. for block in range(n_blocks):
  409. y = corr_z[:, subj, block]
  410. # Fit low-dimension (0-3) regression
  411. X_low = dimensions[dimensions <= cutoff].reshape(-1, 1)
  412. reg_low = LinearRegression().fit(X_low, y[dimensions <= cutoff])
  413. y_pred_low = reg_low.predict([[cutoff]])
  414. slopes_low[subj, block] = reg_low.coef_[0]
  415. # Fit high-dimension (3-9) regression
  416. X_high = dimensions[dimensions >= cutoff].reshape(-1, 1)
  417. reg_high = LinearRegression().fit(X_high, y[dimensions >= cutoff])
  418. y_pred_high = reg_high.predict([[cutoff]])
  419. slopes_high[subj, block] = reg_high.coef_[0]
  420. # Calculate jump effect
  421. jump_effects[subj, block] = y_pred_high - y_pred_low
  422. # =================================================================
  423. # 1. Analyze results across subjects and blocks
  424. # =================================================================
  425. # Flatten the results across blocks for subject-level analysis
  426. slopes_low_flat = slopes_low.ravel()
  427. slopes_high_flat = slopes_high.ravel()
  428. jump_effects_flat = jump_effects.ravel()
  429. # Low-dimension slopes
  430. t_low, p_low = ttest_1samp(slopes_low_flat, 0)
  431. print("=== Low-dimension regression (0-3) ===")
  432. print(f"Mean Slope: {np.mean(slopes_low_flat):.4f} ± {np.std(slopes_low_flat, ddof=1):.4f}")
  433. print(f"t = {t_low:.4f}, p = {p_low:.4f}\n")
  434. # High-dimension slopes
  435. t_high, p_high = ttest_1samp(slopes_high_flat, 0)
  436. print("=== High-dimension regression (3-9) ===")
  437. print(f"Mean Slope: {np.mean(slopes_high_flat):.4f} ± {np.std(slopes_high_flat, ddof=1):.4f}")
  438. print(f"t = {t_high:.4f}, p = {p_high:.4f}\n")
  439. # Slope comparison (paired t-test)
  440. t_slope_diff, p_slope_diff = ttest_rel(slopes_low_flat, slopes_high_flat)
  441. print("=== Low vs High dimension slope comparison ===")
  442. print(f"Mean Slope Difference: {np.mean(slopes_low_flat - slopes_high_flat):.4f}")
  443. print(f"t = {t_slope_diff:.4f}, p = {p_slope_diff:.4f}\n")
  444. # Jump effects
  445. mean_jump = np.mean(jump_effects_flat)
  446. std_jump = np.std(jump_effects_flat, ddof=1)
  447. t_jump, p_jump = ttest_1samp(jump_effects_flat, 0)
  448. print("=== Breakpoint jump effect ===")
  449. print(f"Mean Jump: {mean_jump:.4f} ± {std_jump:.4f}")
  450. print(f"t = {t_jump:.4f}, p = {p_jump:.4f}")
  451. # =================================================================
  452. # 2. Mixed-effects analysis (optional)
  453. # =================================================================
  454. # For a more sophisticated analysis, you could use mixed-effects models
  455. # that account for both within-subject and between-subject variability
  456. # (would require packages like statsmodels or pingouin)
  457. # =================================================================
  458. # 3. Visualization
  459. # =================================================================
  460. plt.figure(figsize=(15, 5))
  461. # Slope distributions
  462. plt.subplot(1, 3, 1)
  463. sns.histplot(slopes_low_flat, color='blue', kde=True, label='Low Dim (0-3)')
  464. sns.histplot(slopes_high_flat, color='orange', kde=True, label='High Dim (3-9)')
  465. plt.axvline(0, color='black', linestyle='--')
  466. plt.xlabel('Regression Slope')
  467. plt.ylabel('Frequency')
  468. plt.title('Slope Distribution by Dimension')
  469. plt.legend()
  470. # Slope differences
  471. plt.subplot(1, 3, 2)
  472. sns.histplot(slopes_low_flat - slopes_high_flat, color='green', kde=True)
  473. plt.axvline(0, color='black', linestyle='--')
  474. plt.xlabel('Slope Difference (Low - High)')
  475. plt.title('Slope Difference Distribution')
  476. # Jump effects
  477. plt.subplot(1, 3, 3)
  478. sns.histplot(jump_effects_flat, color='red', kde=True)
  479. plt.axvline(mean_jump, color='black', linestyle='--', label=f'Mean Jump = {mean_jump:.3f}')
  480. plt.xlabel('Jump Effect at Cutoff')
  481. plt.title('Jump Effect Distribution')
  482. plt.legend()
  483. plt.tight_layout()
  484. plt.show()
  485. # %%
  486. import numpy as np
  487. import shap
  488. from sklearn.linear_model import Ridge
  489. from scipy.stats import pearsonr
  490. import matplotlib.pyplot as plt
  491. from sklearn.linear_model import LinearRegression
  492. from scipy.stats import zscore
  493. out_path = 'J:/HCP_analysis/DEAF/10_rest_predict_task/'
  494. corr = np.load(out_path + 'gradient_predict_task_by_feature_count.npy')[:, :, :, 0] # (10, 91, 4)
  495. # 计算均值和误差(标准差或标准误)
  496. mean_corr = np.mean(corr, axis=(1, 2)) # 跨被试和block的平均
  497. std_corr = np.std(corr, axis=(1, 2)) # 标准差
  498. mean_shap = np.load(out_path + 'mean_shap_by_feature_count.npy')
  499. subs = 91
  500. features = 10
  501. blocks = 8
  502. rois = 360 # Added this since it was used but not defined
  503. # 绘图设置
  504. plt.figure(figsize=(8, 5))
  505. title_font = {'fontsize': 18, 'fontweight': 'bold'}
  506. label_font = {'fontsize': 18, 'fontweight': 'bold'}
  507. tick_font = {'fontsize': 18, 'fontweight': 'bold'}
  508. # 绘制均值线及误差线(这里使用标准误,如需标准差请替换为std_corr)
  509. plt.errorbar(
  510. range(1, 11),
  511. mean_corr,
  512. yerr=std_corr, # 误差线长度(标准误)
  513. fmt='-o', # 线型+标记
  514. linewidth=3,
  515. markersize=8,
  516. color='gray',
  517. capsize=5, # 误差线端帽长度
  518. capthick=2, # 端帽线宽
  519. ecolor='gray' # 误差线颜色
  520. )
  521. # 美化图形
  522. plt.xlabel('Number of Features', **label_font)
  523. plt.ylabel('Correlation (±SD)', **label_font)
  524. plt.xticks(range(1, 11), **tick_font)
  525. plt.yticks(**tick_font)
  526. plt.grid(False)
  527. ax = plt.gca()
  528. ax.spines['top'].set_visible(False)
  529. ax.spines['right'].set_visible(False)
  530. ax.spines['bottom'].set_linewidth(3)
  531. ax.spines['left'].set_linewidth(3)
  532. ax.spines['bottom'].set_color('black')
  533. ax.spines['left'].set_color('black')
  534. plt.tight_layout()
  535. plt.savefig(out_path + 'mean_correlation_plot_with_errorbars.png', dpi=300, bbox_inches='tight')
  536. plt.close()
  537. # Second plot: SHAP Heatmap
  538. plt.figure(figsize=(7, 4))
  539. im = plt.imshow(mean_shap.T, aspect='auto', cmap='viridis')
  540. #plt.title('Feature Importance by Number of Features', **title_font)
  541. plt.xlabel('Number of Features Used in Model', **label_font)
  542. #plt.ylabel('Gradient Feature', **label_font)
  543. plt.yticks(range(features), [f'G{i+1}' for i in range(10)], **tick_font)
  544. plt.xticks(range(features), range(1, features+1), **tick_font)
  545. cbar = plt.colorbar(im, pad=0.05)
  546. cbar.set_label('Mean SHAP Value', **label_font)
  547. cbar.ax.tick_params(
  548. labelsize=15,
  549. which='both',
  550. width=2,
  551. length=6
  552. )
  553. for label in cbar.ax.get_yticklabels():
  554. label.set_fontweight('bold')
  555. plt.tight_layout()
  556. plt.savefig(out_path + 'shap_heatmap.png', dpi=300, bbox_inches='tight')
  557. plt.close()
  558. # %%
  559. import numpy as np
  560. import matplotlib.pyplot as plt
  561. from matplotlib.colors import LinearSegmentedColormap
  562. from scipy.stats import linregress
  563. out_path = 'J:/HCP_analysis/DEAF/10_rest_predict_task/'
  564. corr = np.load(out_path + 'gradient_predict_task_by_feature_count.npy')[:, :, :, 0] # (10, 91, 8)
  565. # Define 10-step red gradient colormap
  566. red_gradient = [
  567. '#400000', # 深黑红
  568. '#800000', # 暗红
  569. '#b30000', # 标准红
  570. '#e60000', # 亮红
  571. '#ff3333', # 浅红
  572. '#ff6666', # 淡红
  573. '#ff9999', # 粉红
  574. '#ffb3b3', # 浅粉
  575. '#ffd6d6', # 极浅粉
  576. '#ffcccc' # 淡灰红
  577. ]
  578. n_dims = 10
  579. # Calculate statistics
  580. mean_corr = np.mean(corr, axis=(1, 2)) # Average across subjects and blocks
  581. std_corr = np.std(corr, axis=(1, 2)) # Standard deviation
  582. # Plot settings
  583. plt.figure(figsize=(8, 5))
  584. label_font = {'fontsize': 24, 'fontweight': 'bold'}
  585. tick_font = {'fontsize': 24, 'fontweight': 'bold'}
  586. # Plot jittered individual points with gradient colors
  587. for i in range(10):
  588. # Create jittered x positions
  589. x_jitter = np.random.normal(i+1, 0.08, size=corr[i].size)
  590. plt.scatter(
  591. x_jitter,
  592. corr[i].flatten(),
  593. color=red_gradient[i],
  594. alpha=0.7,
  595. s=25,
  596. edgecolor='white',
  597. linewidth=0.5,
  598. zorder=1
  599. )
  600. # Add boxplot with thicker elements and black borders
  601. box_data = [corr[i].flatten() for i in range(10)]
  602. box = plt.boxplot(
  603. box_data,
  604. positions=range(1, 11),
  605. widths=0.5,
  606. patch_artist=True,
  607. showfliers=False,
  608. medianprops={'color': 'black', 'linewidth': 3}, # Thicker median line
  609. boxprops={'color': 'black', 'linewidth': 3}, # Black border for box
  610. whiskerprops={'color': 'black', 'linewidth': 3}, # Black whiskers
  611. capprops={'color': 'black', 'linewidth': 3}, # Black caps
  612. zorder=2
  613. )
  614. # Color boxes with red gradient
  615. for patch, color in zip(box['boxes'], red_gradient):
  616. patch.set_facecolor(color)
  617. patch.set_alpha(0.4)
  618. # Calculate and plot regression lines
  619. x_vals = np.array(range(1, 11))
  620. # Regression for features 1-3 (dark red)
  621. x1 = x_vals[:3]
  622. y1 = mean_corr[:3]
  623. slope1, intercept1, _, _, _ = linregress(x1, y1)
  624. plt.plot(x1, intercept1 + slope1*x1,
  625. color='#800000', linewidth=5, linestyle='-',
  626. label='Features 1-3 Trend')
  627. # Regression for features 3-10 (pink)
  628. x2 = x_vals[2:] # From feature 3 to 10
  629. y2 = mean_corr[2:]
  630. slope2, intercept2, _, _, _ = linregress(x2, y2)
  631. plt.plot(x2, intercept2 + slope2*x2,
  632. color='#ff9999', linewidth=5, linestyle='-',
  633. label='Features 3-10 Trend')
  634. # Plot mean points without connecting line
  635. plt.scatter(
  636. range(1, 11),
  637. mean_corr,
  638. s=100, # Larger point size
  639. color='black',
  640. edgecolor='white',
  641. linewidth=2,
  642. zorder=4
  643. )
  644. # Add error bars separately (without connecting line)
  645. plt.errorbar(
  646. range(1, 11),
  647. mean_corr,
  648. fmt='none', # No markers or connecting line
  649. color='black',
  650. capsize=5,
  651. capthick=2,
  652. linewidth=1.5,
  653. zorder=3
  654. )
  655. # Formatting
  656. plt.xlabel('Number of Features', **label_font)
  657. plt.ylabel('Correlation (±SD)', **label_font)
  658. plt.xticks(range(1, 11), **tick_font)
  659. plt.yticks(**tick_font)
  660. plt.grid(False)
  661. ax = plt.gca()
  662. ax.spines['top'].set_visible(False)
  663. ax.spines['right'].set_visible(False)
  664. ax.spines['bottom'].set_linewidth(3)
  665. ax.spines['left'].set_linewidth(3)
  666. ax.spines['bottom'].set_color('black')
  667. ax.spines['left'].set_color('black')
  668. plt.tight_layout()
  669. plt.savefig(out_path + 'feature_correlation_plot.png', dpi=300, bbox_inches='tight', transparent=True)
  670. plt.close()
  671. # %%
  672. import numpy as np
  673. import matplotlib.pyplot as plt
  674. from matplotlib.colors import LinearSegmentedColormap
  675. from scipy.stats import linregress
  676. out_path = 'J:/HCP_analysis/DEAF/10_rest_predict_task/'
  677. corr = np.load(out_path + 'gradient_predict_task_by_feature_count.npy')[:, :, :, 0] # (10, 91, 4)
  678. # Define 10-step red gradient colormap
  679. red_gradient = [
  680. '#400000', # 深黑红
  681. '#800000', # 暗红
  682. '#b30000', # 标准红
  683. '#e60000', # 亮红
  684. '#ff3333', # 浅红
  685. '#ff6666', # 淡红
  686. '#ff9999', # 粉红
  687. '#ffb3b3', # 浅粉
  688. '#ffd6d6', # 极浅粉
  689. '#ffcccc' # 淡灰红
  690. ]
  691. n_dims = 10
  692. # Calculate statistics
  693. mean_corr = np.mean(corr, axis=(1, 2)) # Average across subjects and blocks
  694. std_corr = np.std(corr, axis=(1, 2)) # Standard deviation
  695. # Plot settings
  696. plt.figure(figsize=(8, 5))
  697. label_font = {'fontsize': 24, 'fontweight': 'bold'}
  698. tick_font = {'fontsize': 24, 'fontweight': 'bold'}
  699. # Plot jittered individual points with gradient colors
  700. for i in range(10):
  701. # Create jittered x positions
  702. x_jitter = np.random.normal(i+1, 0.08, size=corr[i].size)
  703. plt.scatter(
  704. x_jitter,
  705. corr[i].flatten(),
  706. color=red_gradient[i],
  707. alpha=0.7,
  708. s=25,
  709. edgecolor='white',
  710. linewidth=0.5,
  711. zorder=1
  712. )
  713. # Plot mean points with error bars showing standard deviation
  714. plt.errorbar(
  715. range(1, 11),
  716. mean_corr,
  717. yerr=std_corr,
  718. fmt='o',
  719. markersize=10,
  720. capsize=5,
  721. capthick=3,
  722. elinewidth=3,
  723. color='black',
  724. ecolor='black',
  725. markerfacecolor='black',
  726. markeredgecolor='white',
  727. markeredgewidth=2,
  728. zorder=4
  729. )
  730. # Calculate and plot regression lines
  731. x_vals = np.array(range(1, 11))
  732. # Regression for features 1-3 (dark red)
  733. x1 = x_vals[:3]
  734. y1 = mean_corr[:3]
  735. slope1, intercept1, _, _, _ = linregress(x1, y1)
  736. plt.plot(x1, intercept1 + slope1*x1,
  737. color='#800000', linewidth=5, linestyle='-',
  738. label='Features 1-3 Trend')
  739. # Regression for features 3-10 (pink)
  740. x2 = x_vals[2:] # From feature 3 to 10
  741. y2 = mean_corr[2:]
  742. slope2, intercept2, _, _, _ = linregress(x2, y2)
  743. plt.plot(x2, intercept2 + slope2*x2,
  744. color='#ff9999', linewidth=5, linestyle='-',
  745. label='Features 3-10 Trend')
  746. # Formatting
  747. plt.xlabel('Number of Features', **label_font)
  748. plt.ylabel('Correlation (±SD)', **label_font)
  749. plt.xticks(range(1, 11), **tick_font)
  750. plt.yticks(**tick_font)
  751. plt.grid(False)
  752. ax = plt.gca()
  753. ax.spines['top'].set_visible(False)
  754. ax.spines['right'].set_visible(False)
  755. ax.spines['bottom'].set_linewidth(3)
  756. ax.spines['left'].set_linewidth(3)
  757. ax.spines['bottom'].set_color('black')
  758. ax.spines['left'].set_color('black')
  759. plt.tight_layout()
  760. plt.savefig(out_path + 'feature_correlation_plot_mean_SD.png', dpi=300, bbox_inches='tight', transparent=True)
  761. plt.close()
  762. # %% [markdown]
  763. # # 统计检验
  764. # %%
  765. import numpy as np
  766. import matplotlib.pyplot as plt
  767. import os
  768. import pandas as pd
  769. import statsmodels.api as sm
  770. import statsmodels.formula.api as smf
  771. from scipy import stats
  772. # Set paths
  773. input_path = 'J:/HCP_analysis/Deaf/10_rest_predict_task/'
  774. output_path = 'J:/HCP_analysis/Deaf/10_rest_predict_task/results/'
  775. os.makedirs(output_path, exist_ok=True)
  776. # Load and prepare data
  777. corr_values_all = np.load(input_path + 'gradient_predict_task.npy') # shape: (91, 4, 3)
  778. corr_values_all = np.arctanh(corr_values_all)
  779. # Prepare DataFrame for mixed model
  780. data_list = []
  781. subjects = np.arange(corr_values_all.shape[0])
  782. blocks = np.arange(corr_values_all.shape[1])
  783. for subj in subjects:
  784. for block in blocks:
  785. group = 'Hearing' if subj < 34 else 'DNS'
  786. data_list.append({
  787. 'Subject': f'sub-{subj:03d}',
  788. 'Block': block,
  789. 'Group': group,
  790. 'Correlation': corr_values_all[subj, block, 0]
  791. })
  792. df = pd.DataFrame(data_list)
  793. # Fit mixed effects model
  794. model = smf.mixedlm("Correlation ~ Group",
  795. data=df,
  796. groups=df["Subject"],
  797. re_formula="~1").fit()
  798. # Get p-value for group effect
  799. p_value = model.pvalues['Group[T.Hearing]']
  800. # Prepare plotting data
  801. hearing = corr_values_all[:34,:,0].flatten()
  802. deaf = corr_values_all[34:,:,0].flatten()
  803. # Create figure
  804. plt.figure(figsize=(8, 6))
  805. plt.rcParams.update({
  806. 'font.size': 12,
  807. 'axes.linewidth': 1.5,
  808. 'xtick.major.width': 1.5,
  809. 'ytick.major.width': 1.5
  810. })
  811. # Plot boxplots with thicker borders (linewidth=3)
  812. boxprops = dict(linewidth=3, color='black') # Thicker borders
  813. whiskerprops = dict(linewidth=3, color='black') # Thicker whiskers
  814. capprops = dict(linewidth=3, color='black') # Thicker caps
  815. medianprops = dict(linewidth=3, color='black') # Thicker median line
  816. bp = plt.boxplot([hearing, deaf],
  817. labels=['Hearing', 'DNS'],
  818. patch_artist=True,
  819. widths=0.6,
  820. boxprops=boxprops,
  821. whiskerprops=whiskerprops,
  822. capprops=capprops,
  823. medianprops=medianprops)
  824. # Set box fill colors to #F08E64 (orange) and #5E93CB (blue)
  825. colors = ['#F08E64', '#5E93CB']
  826. for patch, color in zip(bp['boxes'], colors):
  827. patch.set_facecolor(color)
  828. patch.set_alpha(0.7)
  829. # Plot individual data points with jitter (larger size)
  830. def plot_jitter(data, x_pos, color, alpha=0.6):
  831. jitter = np.random.normal(0, 0.05, size=len(data))
  832. plt.scatter(x_pos + jitter, data, color=color, alpha=alpha, s=250, edgecolor='none')
  833. plot_jitter(hearing, 1, '#F08E64', alpha=0.6)
  834. plot_jitter(deaf, 2, '#5E93CB', alpha=0.6)
  835. # Calculate standard errors for error bars
  836. se_hearing = stats.sem(hearing)
  837. se_deaf = stats.sem(deaf)
  838. # Mark means with white diamonds and thicker error bars
  839. mean_hearing = np.mean(hearing)
  840. mean_deaf = np.mean(deaf)
  841. # Plot mean markers with thicker error bars (linewidth=3)
  842. plt.errorbar([1], [mean_hearing], #yerr=se_hearing,
  843. fmt='none', ecolor='black', elinewidth=3, capsize=10, capthick=3)
  844. plt.errorbar([2], [mean_deaf], #yerr=se_deaf,
  845. fmt='none', ecolor='black', elinewidth=3, capsize=10, capthick=3)
  846. plt.scatter(1, mean_hearing, color='white', s=250, edgecolor='black',
  847. marker='D', zorder=10, linewidth=2, label='Mean')
  848. plt.scatter(2, mean_deaf, color='white', s=250, edgecolor='black',
  849. marker='D', zorder=10, linewidth=2)
  850. # Add significance annotation
  851. y_max = max(np.max(hearing), np.max(deaf)) + 0.1
  852. plt.plot([1, 1, 2, 2], [y_max-0.05, y_max, y_max, y_max-0.05],
  853. color='black', lw=3) # Thicker significance line
  854. if p_value < 0.001:
  855. sig_text = '***'
  856. elif p_value < 0.01:
  857. sig_text = '**'
  858. elif p_value < 0.05:
  859. sig_text = '*'
  860. else:
  861. sig_text = 'n.s.'
  862. plt.text(1.5, y_max, sig_text,
  863. ha='center', va='bottom',
  864. fontsize=48, fontweight='bold')
  865. # Customize plot
  866. plt.xticks(fontsize=46, fontweight='bold')
  867. plt.yticks(fontsize=46, fontweight='bold')
  868. # Adjust spines (thicker)
  869. ax = plt.gca()
  870. ax.spines['top'].set_visible(False)
  871. ax.spines['right'].set_visible(False)
  872. ax.spines['bottom'].set_linewidth(4)
  873. ax.spines['left'].set_linewidth(4)
  874. ax.spines['bottom'].set_color('black')
  875. ax.spines['left'].set_color('black')
  876. plt.tight_layout()
  877. plt.savefig(output_path + 'hearing_vs_deaf_boxplot_thick_borders.png',
  878. dpi=300, bbox_inches='tight', transparent=True)
  879. plt.show()
  880. # Print model summary
  881. print(model.summary())
  882. # %%
  883. import numpy as np
  884. import os
  885. import matplotlib.pyplot as plt
  886. import seaborn as sns
  887. import pandas as pd
  888. import statsmodels.api as sm
  889. import statsmodels.formula.api as smf
  890. from scipy.stats import zscore
  891. from matplotlib.colors import LinearSegmentedColormap
  892. from statsmodels.stats.multitest import multipletests # For p-value correction
  893. # Set paths
  894. input_path = 'J:/HCP_analysis/Deaf/10_rest_predict_task/'
  895. output_path = 'J:/HCP_analysis/Deaf/10_rest_predict_task/results/'
  896. os.makedirs(output_path, exist_ok=True)
  897. # Define gradient color schemes
  898. hearing_colors = LinearSegmentedColormap.from_list('hearing', ['#F08E64', '#F8C8B0'])(np.linspace(0, 1, 10))
  899. deaf_colors = LinearSegmentedColormap.from_list('DNS', ['#5E93CB', '#B8D1E8'])(np.linspace(0, 1, 10))
  900. # Load and standardize data
  901. shap_values_all = np.load(input_path + 'shap_feature_importance.npy') # shape: (91, 4, 10) or (91, 8, 10)
  902. shap_values_all = zscore(shap_values_all, axis=2) # Standardize within each dimension
  903. # Define group sizes
  904. n_Hearing = 34
  905. n_Deaf = 27
  906. n_subjects = n_Hearing + n_Deaf
  907. n_blocks = 8
  908. n_dims = 10
  909. # Prepare DataFrame for mixed model
  910. data_list = []
  911. for subj in range(n_subjects):
  912. group = 'Hearing' if subj < n_Hearing else 'DNS'
  913. for block in range(n_blocks):
  914. for dim in range(n_dims):
  915. data_list.append({
  916. 'subject': f'subj_{subj}',
  917. 'group': group,
  918. 'block': f'block_{block}',
  919. 'dimension': dim,
  920. 'shap_value': shap_values_all[subj, block, dim]
  921. })
  922. df = pd.DataFrame(data_list)
  923. # Initialize storage for results
  924. lmm_results = []
  925. # Fit mixed models for each SHAP dimension
  926. for dim in range(n_dims):
  927. dim_df = df[df['dimension'] == dim].copy()
  928. # Linear Mixed Effects Model with subject random intercept
  929. model = smf.mixedlm(
  930. "shap_value ~ group",
  931. data=dim_df,
  932. groups=dim_df["subject"],
  933. re_formula="~1" # Random intercept per subject
  934. )
  935. try:
  936. result = model.fit()
  937. coef = result.fe_params['group[T.Hearing]'] # Effect of Hearing vs Deaf
  938. pval = result.pvalues['group[T.Hearing]']
  939. t_stat = result.tvalues['group[T.Hearing]']
  940. lmm_results.append({
  941. 'dimension': dim,
  942. 'coefficient': coef,
  943. 't_statistic': t_stat,
  944. 'p_value': pval,
  945. 'significant': pval < 0.05 # Direct significance without correction
  946. })
  947. except Exception as e:
  948. print(f"Failed to fit model for dimension {dim}: {str(e)}")
  949. lmm_results.append({
  950. 'dimension': dim,
  951. 'coefficient': np.nan,
  952. 't_statistic': np.nan,
  953. 'p_value': np.nan,
  954. 'significant': False
  955. })
  956. # Convert to DataFrame
  957. results_df = pd.DataFrame(lmm_results)
  958. # Apply p-value correction (FDR)
  959. pvals = results_df['p_value'].values
  960. rejected, pvals_corrected, _, _ = multipletests(pvals, alpha=0.05, method='fdr_bh')
  961. results_df['p_value_corrected'] = pvals_corrected
  962. results_df['significant_corrected'] = rejected # Update significance based on corrected p-values
  963. # Save corrected results
  964. results_df.to_csv(output_path + 'lmm_results_corrected.csv', index=False)
  965. # Visualization with more pronounced gradients
  966. plt.figure(figsize=(12, 6.5)) # Larger figure size
  967. # Calculate group means (averaged across blocks)
  968. group_means = df.groupby(['group', 'dimension'])['shap_value'].mean().unstack()
  969. group_sems = df.groupby(['group', 'dimension'])['shap_value'].sem().unstack()
  970. # ===================== 新增:计算“每个被试在每个维度”的单个点(跨block平均) =====================
  971. subj_means = df.groupby(['group', 'subject', 'dimension'])['shap_value'].mean()
  972. hearing_subjects = subj_means.loc['Hearing'].index.get_level_values('subject').unique()
  973. dns_subjects = subj_means.loc['DNS'].index.get_level_values('subject').unique()
  974. np.random.seed(0) # 抖动可复现
  975. # =============================================================================================
  976. # Plot with more pronounced gradient colors
  977. x = range(n_dims)
  978. for dim in range(n_dims):
  979. # ===================== 新增:叠加被试散点(颜色与对应维度一致,透明,不遮挡误差线) =====================
  980. # Hearing 所有被试点(向左轻微抖动)
  981. y_hearing_pts = np.array([subj_means.loc[('Hearing', s, dim)] for s in hearing_subjects])
  982. x_hearing_pts = dim + np.random.uniform(-0.18, -0.06, size=len(y_hearing_pts))
  983. plt.scatter(x_hearing_pts, y_hearing_pts,
  984. s=75, color=hearing_colors[dim], alpha=0.88,
  985. edgecolors='none', zorder=1)
  986. # DNS 所有被试点(向右轻微抖动)
  987. y_dns_pts = np.array([subj_means.loc[('DNS', s, dim)] for s in dns_subjects])
  988. x_dns_pts = dim + np.random.uniform(0.06, 0.18, size=len(y_dns_pts))
  989. plt.scatter(x_dns_pts, y_dns_pts,
  990. s=75, color=deaf_colors[dim], alpha=0.88,
  991. edgecolors='none', zorder=1)
  992. # ==========================================================================================
  993. # Hearing markers - darker to lighter
  994. plt.errorbar(dim, group_means.loc['Hearing', dim],
  995. yerr=group_sems.loc['Hearing', dim],
  996. fmt='o', color=hearing_colors[dim],
  997. markersize=20, capsize=6, capthick=3,
  998. elinewidth=3, markeredgewidth=2,
  999. markeredgecolor='black', zorder=7)
  1000. # Deaf markers - darker to lighter
  1001. plt.errorbar(dim, group_means.loc['DNS', dim],
  1002. yerr=group_sems.loc['DNS', dim],
  1003. fmt='s', color=deaf_colors[dim],
  1004. markersize=20, capsize=6, capthick=3,
  1005. elinewidth=3, markeredgewidth=2,
  1006. markeredgecolor='black', zorder=7)
  1007. # Connect the dots with gradient-colored lines
  1008. for dim in range(n_dims-1):
  1009. plt.plot([dim, dim+1],
  1010. [group_means.loc['Hearing', dim], group_means.loc['Hearing', dim+1]],
  1011. '-', color=hearing_colors[dim], linewidth=4, alpha=0.8)
  1012. plt.plot([dim, dim+1],
  1013. [group_means.loc['DNS', dim], group_means.loc['DNS', dim+1]],
  1014. '-', color=deaf_colors[dim], linewidth=4, alpha=0.8)
  1015. # Mark significant dimensions with larger stars (based on corrected p-values)
  1016. sig_dims_corrected = results_df[results_df['significant_corrected']]['dimension']
  1017. for dim in sig_dims_corrected:
  1018. y_pos = max(group_means.loc['Hearing', dim], group_means.loc['DNS', dim]) + 0.15
  1019. plt.scatter(dim, y_pos, marker='*', color='black', s=600, zorder=10)
  1020. # Customize plot appearance
  1021. plt.ylabel('Standardized SHAP Value', fontsize=29, fontweight='bold', labelpad=15)
  1022. plt.xticks(range(10), [f'G{i+1}' for i in range(10)], fontsize=30, fontweight='bold')
  1023. plt.yticks(fontsize=30, fontweight='bold')
  1024. # Create custom legend
  1025. from matplotlib.lines import Line2D
  1026. legend_elements = [
  1027. Line2D([0], [0], marker='o', color='w', label='Hearing',
  1028. markerfacecolor=hearing_colors[0], markersize=25, markeredgewidth=2),
  1029. Line2D([0], [0], marker='s', color='w', label='DNS',
  1030. markerfacecolor=deaf_colors[0], markersize=25, markeredgewidth=2)
  1031. ]
  1032. plt.legend(handles=legend_elements, fontsize=48, prop={'weight':'bold', 'size':26},
  1033. framealpha=0.9, loc='upper right')
  1034. # Customize spines
  1035. ax = plt.gca()
  1036. ax.spines['top'].set_visible(False)
  1037. ax.spines['right'].set_visible(False)
  1038. ax.spines['bottom'].set_linewidth(4)
  1039. ax.spines['left'].set_linewidth(4)
  1040. ax.spines['bottom'].set_color('black')
  1041. ax.spines['left'].set_color('black')
  1042. plt.grid(False)
  1043. plt.tight_layout()
  1044. plt.savefig(output_path + 'shap_comparison_gradient_colors_corrected.png',
  1045. dpi=300, bbox_inches='tight', transparent=True)
  1046. plt.close()
  1047. print("Analysis complete. Results saved to:", output_path)
  1048. # %% [markdown]
  1049. # # 对比有无语言经验的差异
  1050. # %%
  1051. import numpy as np
  1052. import matplotlib.pyplot as plt
  1053. import os
  1054. import pandas as pd
  1055. import statsmodels.api as sm
  1056. import statsmodels.formula.api as smf
  1057. from scipy import stats
  1058. # Set paths
  1059. input_path = 'J:/HCP_analysis/Deaf/10_rest_predict_task/'
  1060. output_path = 'J:/HCP_analysis/Deaf/10_rest_predict_task/results_lan_ELA/'
  1061. os.makedirs(output_path, exist_ok=True)
  1062. # Load and prepare data
  1063. corr_values_all = np.load(input_path + 'gradient_predict_task.npy') # shape: (91, 4, 3)
  1064. corr_values_all = np.arctanh(corr_values_all)
  1065. # Prepare DataFrame for mixed model
  1066. data_list = []
  1067. subjects = np.arange(34, corr_values_all.shape[0]) # Only deaf subjects (34-90)
  1068. blocks = np.arange(corr_values_all.shape[1])
  1069. for i, subj in enumerate(subjects):
  1070. for block in blocks:
  1071. group = 'ELA' if i < 27 else 'Non_ELA' # ELA:34-60 (27), Non_ELA:61-90 (30)
  1072. data_list.append({
  1073. 'Subject': f'sub-{subj:03d}',
  1074. 'Block': block,
  1075. 'Group': group,
  1076. 'Correlation': corr_values_all[subj, block, 0]
  1077. })
  1078. df = pd.DataFrame(data_list)
  1079. # Fit mixed effects model
  1080. model = smf.mixedlm("Correlation ~ Group",
  1081. data=df,
  1082. groups=df["Subject"],
  1083. re_formula="~1").fit()
  1084. # Get p-value for group effect
  1085. p_value = model.pvalues['Group[T.Non_ELA]'] # Reference is ELA
  1086. # Prepare plotting data
  1087. ELA = corr_values_all[34:61,:,0].flatten()
  1088. Non_ELA = corr_values_all[61:,:,0].flatten()
  1089. # Create figure with larger size
  1090. plt.figure(figsize=(8, 6))
  1091. plt.rcParams.update({
  1092. 'font.size': 12,
  1093. 'axes.linewidth': 2,
  1094. 'xtick.major.width': 2,
  1095. 'ytick.major.width': 2
  1096. })
  1097. # Plot boxplots with thicker elements (linewidth=3)
  1098. boxprops = dict(linewidth=3, color='black') # Thicker box borders
  1099. whiskerprops = dict(linewidth=3, color='black') # Thicker whiskers
  1100. capprops = dict(linewidth=3, color='black') # Thicker caps
  1101. medianprops = dict(linewidth=3, color='black') # Thicker median line
  1102. bp = plt.boxplot([ELA, Non_ELA],
  1103. labels=['DNS', 'DLS'],
  1104. patch_artist=True,
  1105. widths=0.6,
  1106. boxprops=boxprops,
  1107. whiskerprops=whiskerprops,
  1108. capprops=capprops,
  1109. medianprops=medianprops)
  1110. # Set box fill colors with new color scheme
  1111. colors = ['#5E93CB', '#9A4942'] # DNS and DLS colors '#5E93CB' '#79902D'
  1112. for patch, color in zip(bp['boxes'], colors):
  1113. patch.set_facecolor(color)
  1114. patch.set_alpha(0.7)
  1115. # Plot individual data points with jitter (larger size)
  1116. def plot_jitter(data, x_pos, color, alpha=0.6):
  1117. jitter = np.random.normal(0, 0.05, size=len(data))
  1118. plt.scatter(x_pos + jitter, data, color=color, alpha=alpha, s=250, edgecolor='none')
  1119. plot_jitter(ELA, 1, '#5E93CB')
  1120. plot_jitter(Non_ELA, 2, '#9A4942')
  1121. # Calculate standard errors for error bars
  1122. se_ELA = stats.sem(ELA)
  1123. se_Non_ELA = stats.sem(Non_ELA)
  1124. # Mark means with larger diamond shapes (s=150) and thicker error bars
  1125. mean_ELA = np.mean(ELA)
  1126. mean_Non_ELA = np.mean(Non_ELA)
  1127. # Plot error bars with thicker lines (linewidth=3)
  1128. plt.errorbar([1], [mean_ELA], #yerr=se_ELA,
  1129. fmt='none', ecolor='black', elinewidth=3, capsize=12, capthick=3)
  1130. plt.errorbar([2], [mean_Non_ELA], #yerr=se_Non_ELA,
  1131. fmt='none', ecolor='black', elinewidth=3, capsize=12, capthick=3)
  1132. # 显著增大均值标记的大小到s=300
  1133. plt.scatter(1, mean_ELA, color='white', s=250, edgecolor='black', # 增大到300
  1134. marker='D', zorder=10, linewidth=3, label='Mean') # 同时加粗边框到3
  1135. plt.scatter(2, mean_Non_ELA, color='white', s=250, edgecolor='black',
  1136. marker='D', zorder=10, linewidth=3)
  1137. # Add significance annotation with thicker line
  1138. y_max = max(np.max(ELA), np.max(Non_ELA)) + 0.1
  1139. plt.plot([1, 1, 2, 2], [y_max-0.05, y_max, y_max, y_max-0.05],
  1140. color='black', lw=3) # Thicker significance line
  1141. if p_value < 0.001:
  1142. sig_text = '***'
  1143. elif p_value < 0.01:
  1144. sig_text = '**'
  1145. elif p_value < 0.05:
  1146. sig_text = '*'
  1147. else:
  1148. sig_text = 'n.s.'
  1149. plt.text(1.5, y_max, sig_text,
  1150. ha='center', va='bottom',
  1151. fontsize=48, fontweight='bold')
  1152. # Customize plot with larger fonts
  1153. plt.xticks(fontsize=48, fontweight='bold')
  1154. plt.yticks(fontsize=48, fontweight='bold')
  1155. # Adjust spines (thicker)
  1156. ax = plt.gca()
  1157. ax.spines['top'].set_visible(False)
  1158. ax.spines['right'].set_visible(False)
  1159. ax.spines['bottom'].set_linewidth(3)
  1160. ax.spines['left'].set_linewidth(3)
  1161. ax.spines['bottom'].set_color('black')
  1162. ax.spines['left'].set_color('black')
  1163. plt.tight_layout()
  1164. plt.savefig(output_path + 'ELA_vs_Non_ELA_boxplot_enhanced.png',
  1165. dpi=300, bbox_inches='tight', transparent=True)
  1166. plt.show()
  1167. # Print model summary
  1168. print("Mixed Effects Model Results:")
  1169. print(model.summary())
  1170. print(f"\nGroup difference p-value: {p_value:.4f}")
  1171. # %%
  1172. import numpy as np
  1173. import os
  1174. import matplotlib.pyplot as plt
  1175. import seaborn as sns
  1176. import pandas as pd
  1177. import statsmodels.api as sm
  1178. import statsmodels.formula.api as smf
  1179. from scipy.stats import zscore
  1180. from statsmodels.stats.multitest import multipletests # For p-value correction
  1181. # Set paths
  1182. input_path = 'J:/HCP_analysis/deaf/10_rest_predict_task/'
  1183. output_path = 'J:/HCP_analysis/deaf/10_rest_predict_task/results_lan_DNS/'
  1184. os.makedirs(output_path, exist_ok=True)
  1185. # Load and standardize data
  1186. shap_values_all = np.load(input_path + 'shap_feature_importance.npy') # shape: (91, 4, 10)
  1187. shap_values_all = zscore(shap_values_all, axis=2) # Standardize within each dimension
  1188. # Define group sizes
  1189. n_DNS = 27
  1190. n_Non_DNS = 30
  1191. n_subjects = n_DNS + n_Non_DNS
  1192. n_blocks = 4
  1193. n_dims = 10
  1194. # Prepare DataFrame for mixed model
  1195. data_list = []
  1196. for subj in range(n_subjects):
  1197. group = 'DNS' if subj < n_DNS else 'DLS'
  1198. actual_subj_idx = 34 + subj # Adjust index since DNS group starts at position 34
  1199. for block in range(n_blocks):
  1200. for dim in range(n_dims):
  1201. data_list.append({
  1202. 'subject': f'subj_{actual_subj_idx}',
  1203. 'group': group,
  1204. 'block': block, # Changed to numeric
  1205. 'dimension': dim,
  1206. 'shap_value': shap_values_all[actual_subj_idx, block, dim]
  1207. })
  1208. df = pd.DataFrame(data_list)
  1209. # Ensure group is categorical and set reference level
  1210. df['group'] = pd.Categorical(df['group'], categories=['DLS', 'DNS'])
  1211. df['block'] = pd.Categorical(df['block']) # Make block categorical
  1212. # Initialize storage for results
  1213. lmm_results = []
  1214. # Fit mixed models for each SHAP dimension
  1215. for dim in range(n_dims):
  1216. dim_df = df[df['dimension'] == dim].copy()
  1217. try:
  1218. model = smf.mixedlm(
  1219. "shap_value ~ C(group, Treatment('DLS'))",
  1220. data=dim_df,
  1221. groups=dim_df["subject"],
  1222. re_formula="~1"
  1223. )
  1224. result = model.fit(reml=True)
  1225. coef = result.fe_params["C(group, Treatment('DLS'))[T.DNS]"]
  1226. pval = result.pvalues["C(group, Treatment('DLS'))[T.DNS]"]
  1227. t_stat = result.tvalues["C(group, Treatment('DLS'))[T.DNS]"]
  1228. lmm_results.append({
  1229. 'dimension': dim,
  1230. 'coefficient': coef,
  1231. 't_statistic': t_stat,
  1232. 'p_value': pval,
  1233. 'significant': pval < 0.05,
  1234. 'random_effect_variance': result.cov_re.iloc[0, 0]
  1235. })
  1236. except Exception as e:
  1237. print(f"Failed to fit model for dimension {dim}: {str(e)}")
  1238. lmm_results.append({
  1239. 'dimension': dim,
  1240. 'coefficient': np.nan,
  1241. 't_statistic': np.nan,
  1242. 'p_value': np.nan,
  1243. 'significant': False,
  1244. 'random_effect_variance': np.nan
  1245. })
  1246. # Convert to DataFrame
  1247. results_df = pd.DataFrame(lmm_results)
  1248. # Apply p-value correction (FDR)
  1249. pvals = results_df['p_value'].values
  1250. rejected, pvals_corrected, _, _ = multipletests(pvals, alpha=0.05, method='fdr_bh')
  1251. results_df['p_value_corrected'] = pvals_corrected
  1252. results_df['significant_corrected'] = rejected
  1253. # Save corrected results
  1254. results_df.to_csv(output_path + 'lmm_results_DNS_vs_DLS_corrected.csv', index=False)
  1255. # Visualization with gradient colors and black borders
  1256. plt.figure(figsize=(12, 6.5))
  1257. # Calculate group means (averaged across blocks)
  1258. # 用“被试层面均值”(跨 4 个 block 平均)来计算组均值与SEM,避免SEM过小
  1259. df_subj = df.groupby(['group', 'subject', 'dimension'], as_index=False)['shap_value'].mean()
  1260. group_means = df_subj.groupby(['group', 'dimension'])['shap_value'].mean().unstack()
  1261. group_sems = df_subj.groupby(['group', 'dimension'])['shap_value'].sem().unstack()
  1262. # Create color gradients for each group
  1263. dns_base = np.array([0.3686, 0.5765, 0.7961]) # base blue
  1264. dls_base = np.array([0.6039, 0.2863, 0.2588]) # base red
  1265. dns_gradient = [dns_base * (1 - i*0.08) + np.array([1, 1, 1]) * (i*0.08) for i in range(10)]
  1266. dls_gradient = [dls_base * (1 - i*0.08) + np.array([1, 1, 1]) * (i*0.08) for i in range(10)]
  1267. # ===================== 新增:计算“每个被试在每个维度”的单个点(跨block平均) =====================
  1268. # 这就是你说的 shap_feature_importance.npy 里对应条件的“被试点”
  1269. subj_means = df.groupby(['group', 'subject', 'dimension'])['shap_value'].mean()
  1270. dns_subjects = subj_means.loc['DNS'].index.get_level_values('subject').unique()
  1271. dls_subjects = subj_means.loc['DLS'].index.get_level_values('subject').unique()
  1272. np.random.seed(0) # 仅用于抖动可复现(不想固定可删)
  1273. # =============================================================================================
  1274. # Plot each dimension with its own color from the gradient and black borders
  1275. for dim in range(10):
  1276. # ===================== 新增:叠加“所有被试点”(颜色与条件/维度一致,透明不遮挡误差线) =====================
  1277. # DNS 所有被试
  1278. y_dns_pts = np.array([subj_means.loc[('DNS', s, dim)] for s in dns_subjects])
  1279. x_dns_pts = dim + np.random.uniform(-0.18, -0.06, size=len(y_dns_pts))
  1280. plt.scatter(x_dns_pts, y_dns_pts,
  1281. s=85, color=dns_gradient[dim], alpha=0.88,
  1282. edgecolors='white', zorder=1)
  1283. # DLS 所有被试
  1284. y_dls_pts = np.array([subj_means.loc[('DLS', s, dim)] for s in dls_subjects])
  1285. x_dls_pts = dim + np.random.uniform(0.06, 0.18, size=len(y_dls_pts))
  1286. plt.scatter(x_dls_pts, y_dls_pts,
  1287. s=85, color=dls_gradient[dim], alpha=0.88,
  1288. edgecolors='white', zorder=1)
  1289. # ====================================================================================================
  1290. # DNS plot with black borders
  1291. plt.errorbar(dim, group_means.loc['DNS', dim],
  1292. yerr=group_sems.loc['DNS', dim],
  1293. fmt='o', zorder=5, capsize=6, linewidth=3, markersize=20,
  1294. color=dns_gradient[dim], ecolor='black',
  1295. elinewidth=2,
  1296. markeredgecolor='black', markeredgewidth=2,
  1297. label='DNS' if dim == 0 else "")
  1298. # DLS plot with black borders
  1299. plt.errorbar(dim, group_means.loc['DLS', dim],
  1300. yerr=group_sems.loc['DLS', dim],
  1301. fmt='s', zorder=5, capsize=6, linewidth=3, markersize=20,
  1302. color=dls_gradient[dim], ecolor='black',
  1303. elinewidth=2,
  1304. markeredgecolor='black', markeredgewidth=2,
  1305. label='DLS' if dim == 0 else "")
  1306. # Connect the dots with lines in the gradient colors
  1307. plt.plot(range(10), group_means.loc['DNS'],
  1308. color='#5E93CB', linewidth=3, alpha=1)
  1309. plt.plot(range(10), group_means.loc['DLS'],
  1310. color='#9A4942', linewidth=3, alpha=1)
  1311. # Mark significant differences (corrected p < 0.05)
  1312. for i in range(10):
  1313. if results_df['significant_corrected'].iloc[i]:
  1314. y_pos = max(group_means.loc['DNS', i], group_means.loc['DLS', i]) + 0.03
  1315. plt.scatter(i, y_pos + 0.2, marker='*', color='black', s=600, zorder=10)
  1316. plt.ylabel('Standardized SHAP Value', fontsize=29, fontweight='bold', labelpad=10)
  1317. plt.xticks(range(10), [f'G{i+1}' for i in range(10)], fontsize=30, fontweight='bold')
  1318. plt.yticks(fontsize=30, fontweight='bold')
  1319. # Create custom legend with black borders
  1320. from matplotlib.lines import Line2D
  1321. legend_elements = [
  1322. Line2D([0], [0], marker='o', color='w', label='DNS',
  1323. markerfacecolor='#5E93CB', markersize=25,
  1324. markeredgecolor='black', markeredgewidth=2),
  1325. Line2D([0], [0], marker='s', color='w', label='DLS',
  1326. markerfacecolor='#9A4942', markersize=25,
  1327. markeredgecolor='black', markeredgewidth=2)
  1328. ]
  1329. plt.legend(handles=legend_elements, fontsize=26,
  1330. prop={'weight': 'bold', 'size': 26},
  1331. framealpha=1, loc='upper right')
  1332. # Customize spines
  1333. ax = plt.gca()
  1334. ax.spines['top'].set_visible(False)
  1335. ax.spines['right'].set_visible(False)
  1336. ax.spines['bottom'].set_linewidth(4)
  1337. ax.spines['left'].set_linewidth(4)
  1338. ax.spines['bottom'].set_color('black')
  1339. ax.spines['left'].set_color('black')
  1340. plt.tight_layout()
  1341. plt.savefig(output_path + 'shap_comparison_gradient_DNS_DLS_bordered_corrected.png',
  1342. dpi=300, bbox_inches='tight', transparent=True)
  1343. plt.close()
  1344. print("Analysis complete. Results saved to:", output_path)
  1345. # %%

S05_the_rsFC_gradient_rest_predict_task_activation.ipynb, no license · at the source

Overview

Authors: Linyan Liu1,2, Chan Tang1,2, Jie Chen1,2, Yang Lei1,2, Yanyan Li3,4, Guosheng Ding1,2
  1. Faculty of Psychology, Beijing Normal University,Beijing, China
  2. State Key Laboratory of Cognitive Neuroscience and Learning & IDG/McGovern Institute for Brain Research, Beijing Normal University,Beijing, China
  3. State Key Laboratory of Cognitive Science and Mental Health, Institute of Psychology, Chinese Academy of Sciences,Beijing, China
  4. Department of Psychology, University of Chinese Academy of Sciences,Beijing, China
Journal: Communications biology, volume 9, issue 1, article 703
Dates: received 1 September 2025; accepted 9 March 2026; published online 30 March 2026
Type: Research article · Language: English
License: CC BY-NC-ND
Identifiers: DOI 10.1038/s42003-026-09900-8 · PMID 41912615 · PMCID PMC13199478 · OpenAlex W7143385668
Open access: gold, a free copy (OpenAlex)
Status: code verified (how the code is found and verified)
Categories: human (organism), other condition (population), cognitive (subfield)
Methods: Connectivity, Statistics, Smoothing, state filtering, decompositions, Machine learning, Preprocessing, fMRI & imaging
Keywords: Language, Sensory processing
MeSH: Auditory Perception*, Brain*, Deafness*, Language*, Neuronal Plasticity*, Sensory Deprivation*, Acoustic Stimulation, Auditory Cortex, Brain Mapping, Female, Humans, Magnetic Resonance Imaging, Male (* major topic)
Topic: Language Development and Disorders (Developmental and Educational Psychology, Psychology), according to OpenAlex
Funding: National Natural Science Foundation of China (32471100, 32371141)
Citations: cited by 1 paper (Europe PMC); 61 references in the paper

Abstract

The abstract is not reproduced here: the paper's license (CC BY-NC-ND) does not allow it. Read it in the paper, at the publisher or on Europe PMC.

Repository

Its files are read in the Code ↔ Paper reader above, with 10 matches between paragraphs and lines of code.

OSF ebsvz

License: none: the authors keep all their rights
State: the link answers, verified on 30 September 2026
Evidence: files inventoried
Languages: Jupyter (6)
Size: 31 files, 6 scripts
Software Heritage: not checked
Found in: “Code availability”
Holds: 6 notebooks
Not found: README, license file, CITATION.cff, environment file, tests, continuous integration, documentation
Tools: BrainSpace (6 files), h5py (6 files), Matplotlib (6 files), neuromaps (6 files), NiBabel (6 files), Nilearn (6 files), NumPy (6 files), pandas (6 files), scikit-learn (6 files), SciPy (6 files), seaborn (6 files), statsmodels (6 files), SHAP (4 files), Pingouin (1 file)
Availability: 1 check, the latest on 30 September 2026: the link answers (HTTP 200)
  • 30 September 2026: the link answers (HTTP 200)
6 files
At the source: osf.io/ebsvz/

Code availability statement

The paper has a code availability statement. Its license (CC BY-NC-ND) does not allow reproducing it here; in short, from what the harvester recognized in it:

Read it in the paper: doi.org/10.1038/s42003-026-09900-8.

Tracing map

Proposed by the machine: these links were found in the paper and verified at the source, without human review. The map will receive a Zenodo DOI once one of the paper's authors has validated it with their ORCID.

What the map holds:

  • 1 repository of the authors' code, each at its verified commit, with its license and how the link was found in the paper;
  • 6 scripts, each with its path and the digest of its content;
  • 10 matches between paragraphs of the paper and lines of the code (method lexical-v1);
  • neither the text of the paper nor the code itself.

Its JSON (tracing-map.json) is deposited on Zenodo with its DOI once the map is validated.

Data

No dataset and no data link were found in the paper.

Data availability statement

The paper has a data availability statement. Its license (CC BY-NC-ND) does not allow reproducing it here; in short, from what the harvester recognized in it:

  • no repository, dataset or request procedure was recognized in it

Read it in the paper: doi.org/10.1038/s42003-026-09900-8.

Versions

The history of this record: each version stored by the harvester or made by a correction of its authors or of the maintainers of its code, and what changed in its facts. The texts of the paper (its abstract, its availability statements) are not part of it; versions that changed only those are not listed.

Version 1, 30 September 2026: the first record

Recorded: type, language, journal, volume, issue, pages, dates, 6 authors, 2 keywords, 13 MeSH terms, 1 funder, 61 references.

Cite

This paper

Liu, L., Tang, C., Chen, J., Lei, Y., Li, Y., & Ding, G. (2026). A multidimensional framework for dissociating the neuroplasticity of auditory and early language deprivation. Communications biology, 9(1), 703. https://doi.org/10.1038/s42003-026-09900-8

BibTeX

@article{liu2026multidimensional,
author = {Liu, Linyan and Tang, Chan and Chen, Jie and Lei, Yang and Li, Yanyan and Ding, Guosheng},
title = {{A multidimensional framework for dissociating the neuroplasticity of auditory and early language deprivation}},
journal = {Communications biology},
year = {2026},
month = mar,
volume = {9},
number = {1},
pages = {703},
publisher = {Nature Publishing Group},
issn = {2399-3642},
doi = {10.1038/s42003-026-09900-8},
url = {https://doi.org/10.1038/s42003-026-09900-8},
pmid = {41912615},
pmcid = {PMC13199478}
}

RIS

TY - JOUR
AU - Liu, Linyan
AU - Tang, Chan
AU - Chen, Jie
AU - Lei, Yang
AU - Li, Yanyan
AU - Ding, Guosheng
TI - A multidimensional framework for dissociating the neuroplasticity of auditory and early language deprivation
T2 - Communications biology
J2 - Commun Biol
PY - 2026
DA - 2026/03/30
VL - 9
IS - 1
SP - 703
SN - 2399-3642
PB - Nature Publishing Group
DO - 10.1038/s42003-026-09900-8
UR - https://doi.org/10.1038/s42003-026-09900-8
LA - en
ER -

CSL-JSON

{
"id": "10.1038/s42003-026-09900-8",
"type": "article-journal",
"title": "A multidimensional framework for dissociating the neuroplasticity of auditory and early language deprivation",
"container-title": "Communications biology",
"author": [
{
"family": "Liu",
"given": "Linyan"
},
{
"family": "Tang",
"given": "Chan"
},
{
"family": "Chen",
"given": "Jie"
},
{
"family": "Lei",
"given": "Yang"
},
{
"family": "Li",
"given": "Yanyan"
},
{
"family": "Ding",
"given": "Guosheng"
}
],
"container-title-short": "Commun Biol",
"volume": "9",
"issue": "1",
"page": "703",
"DOI": "10.1038/s42003-026-09900-8",
"PMID": "41912615",
"PMCID": "PMC13199478",
"ISSN": "2399-3642",
"publisher": "Nature Publishing Group",
"URL": "https://doi.org/10.1038/s42003-026-09900-8",
"language": "en",
"issued": {
"date-parts": [
[
2026,
3,
30
]
]
}
}

The tracing map gets a citation of its own once an author has validated it and it has a DOI.

Similar papers

The papers with a page that share the most with this one: the tools found in their code, their categories, datasets, cited references and authors, the rarest counting most.

[1] doi:10.21203/rs.3.rs-9326213/v1 [code]
Multi-task fMRI outperforms resting-state fMRI for revealing task-invariant organization of the human brain
Journal: Research Square (preprint)
In common: neuromaps, Nilearn, h5py, 7 other tools, cognitive, 7 references
[2] doi:10.64898/2026.03.09.710558 [code]
Multi-task fMRI outperforms resting-state fMRI for revealing task-invariant organization of the human brain
Journal: bioRxiv (preprint)
In common: neuromaps, Nilearn, h5py, 7 other tools, cognitive, 7 references
[3] doi:10.7554/elife.96944 [code]
Unraveling the impact of congenital deafness on individual brain organization.
Journal: eLife
In common: other condition, 11 references
[4] doi:10.1162/netn_a_00382 [code]
Comparison of different group-level templates in gradient-based multimodal connectivity analysis.
Journal: Network neuroscience (Cambridge, Mass.)
In common: BrainSpace, Nilearn, h5py, 8 other tools, 6 references
[5] doi:10.1162/netn_a_00402 [code]
The impact of functional correlations on task information coding.
Journal: Network neuroscience (Cambridge, Mass.)
In common: neuromaps, Nilearn, h5py, 8 other tools, 6 references
[6] doi:10.7554/elife.103097 [code]
Canonical neurodevelopmental trajectories of structural and functional manifolds.
Journal: eLife
In common: neuromaps, BrainSpace, Pingouin, 8 other tools, 4 references
[7] doi:10.1038/s41467-026-75959-w [code]
Charting higher-order models of brain function beyond pairwise interactions.
Journal: Nature communications
In common: neuromaps, BrainSpace, Nilearn, 9 other tools, 4 references
[8] doi:10.1162/imag_a_00474 [code]
Exploring neuroendocrine influences on the sensorimotor-association axis in a female and a male individual.
Journal: Imaging neuroscience (Cambridge, Mass.)
In common: neuromaps, BrainSpace, Nilearn, 8 other tools, 5 references
[9] doi:10.1038/s41467-025-66783-9 [code]
Evidence for divergent cortical organisation in Parkinson's disease and Lewy Body Dementia.
Journal: Nature communications
In common: neuromaps, BrainSpace, Pingouin, 8 other tools, 4 references
[10] doi:10.1038/s41467-024-51942-1 [code]
Sex differences in functional cortical organization reflect differences in network topology rather than cortical morphometry.
Journal: Nature communications
In common: neuromaps, BrainSpace, Pingouin, 9 other tools, 3 references

Contribute

The authors of this paper can claim it, correct its record and validate its tracing map, and the maintainers of its code (its owner, or a public member of its organization) correct what it says of their repository; anyone signed in can ask for its removal. Every request goes to OSCR's own machine, which answers it; your account page follows them.

Sign in with ORCID to claim this paper as one of its authors, correct its record or validate its tracing map: when the paper's metadata lists your ORCID iD, you are recognized at once. Maintainers of its code: sign in with GitHub, then claim the repository on your account page.

Add the badge to the code's README

OSCR: the badge of this paper

If you are an author or a maintainer of this paper's code, you can add this badge. It says what OSCR knows of the paper (its code, its validated tracing map) and links the code to this page. Paste one of these snippets under the README's title. Keep the two marks around it, so that the badge can be replaced in place and is never added twice. OSCR changes nothing in your repository.

Markdown
<!-- oscr-badge:start -->
[![OSCR](https://openscicode.org/badge/doi/10.1038/s42003-026-09900-8.svg)](https://openscicode.org/badge/doi/10.1038/s42003-026-09900-8)
<!-- oscr-badge:end -->
reStructuredText
.. oscr-badge:start

.. image:: https://openscicode.org/badge/doi/10.1038/s42003-026-09900-8.svg
   :target: https://openscicode.org/badge/doi/10.1038/s42003-026-09900-8
   :alt: OSCR

.. oscr-badge:end
HTML
<!-- oscr-badge:start -->
<a href="https://openscicode.org/badge/doi/10.1038/s42003-026-09900-8"><img src="https://openscicode.org/badge/doi/10.1038/s42003-026-09900-8.svg" alt="OSCR"></a>
<!-- oscr-badge:end -->

If you choose to, you can have the badge kept up to date for you, with oscr badge --write from the command line or with the GitHub Action in your repository's workflows. Every other form and option (a card, AsciiDoc, LaTeX, shields.io) is on the badge page.

Request its removal

To ask OSCR to remove this record, the copies of its authors' scripts or its tracing map, use the removal request page: signed in, you say who you are, what to remove and why, then review and confirm the request. Published rules decide every request (how).

Discussion, reproductions, activity

Discussion: code errors and mismatches between the code and the paper about this paper and its code, from readers and its authors, beside the paper and its tracing map.

Report a mismatch between the code and the paper · Report a code error (signed in)

Reproductions: reports from readers who ran the authors' code and did not get the paper's result, what they ran, with which environment, commit and data.

Report a reproduction failure (signed in)

Activity: what happens around this paper: new versions of its record, its map's validation, discussions and reproductions. It opens with sign-in.