A multidimensional framework for dissociating the neuroplasticity of auditory and early language deprivation.
The 10 matches
- [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] § 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] § 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] § 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] § 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] § 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] § 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] § 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] § 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] § 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
- # %%
- import matplotlib.pyplot as plt
- import numpy as np
- import pandas as pd
- from scipy.stats import zscore
- from sklearn.metrics.pairwise import cosine_similarity
- import seaborn as sns
- from collections import Counter
- import ActflowToolbox as actflow
- # %%
- ##加载cole模板网络标签
- roi_path = 'F:/early_language__experienced_data/经验期待和经验依赖分析/ROI/ColeAnticevicNetPartition/'
- labels = pd.read_excel(roi_path + 'CAB-NP_v1.1_Labels-ReorderedbyNetworks.xlsx')['NETWORKKEY'][0:360]
- # %%
- import h5py, sys, io, numpy as np
- import nibabel as nib
- path = 'F:/early_language__experienced_data/经验期待和经验依赖分析/功能梯度/code/gradient_analysis-master/gradient_data/templates/'
- surfmL = nib.freesurfer.read_geometry(path + 'S900.L.midthickness_MSMAll.32k_fs_LR.surf')
- surfiL = nib.freesurfer.read_geometry(path + 'S900.L.very_inflated_MSMAll.32k_fs_LR.surf')
- surfL = []
- surfL.append(np.array(surfmL[0]*0.3 + surfiL[0]*0.7))
- surfL.append(surfmL[1])
- surfmR = nib.freesurfer.read_geometry(path + 'S900.R.midthickness_MSMAll.32k_fs_LR.surf')
- surfiR = nib.freesurfer.read_geometry(path + 'S900.R.very_inflated_MSMAll.32k_fs_LR.surf')
- surfR = []
- surfR.append(np.array(surfmR[0]*0.3 + surfiR[0]*0.7))
- surfR.append(surfmR[1])
- res = nib.load(path +'hcp.tmp.lh.dscalar.nii').get_fdata()
- cortL = np.squeeze(np.array(np.where(res != 0)[1], dtype=np.int32))
- res = nib.load(path +'hcp.tmp.rh.dscalar.nii').get_fdata()
- cortR = np.squeeze(np.array(np.where(res != 0)[1], dtype=np.int32))
- cortLen = len(cortL) + len(cortR)
- del res
- sulcL = np.zeros(len(surfL[0]))
- sulcR = np.zeros(len(surfR[0]))
- #MSMAll是一种表皮功能对齐的工具
- sulcL[cortL] = -1 * nib.load(path + 'S1200.sulc_MSMAll.32k_fs_LR.dscalar.nii').get_fdata()[0,:len(cortL)]
- sulcR[cortR] = -1 * nib.load(path + 'S1200.sulc_MSMAll.32k_fs_LR.dscalar.nii').get_fdata()[0,len(cortL)::]
- 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)]
- 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)]
- # %% [markdown]
- # # 绘制语言激活图
- # %%
- # 静息态平均梯度画图
- from brainspace.gradient import ProcrustesAlignment
- import numpy as np
- import pickle
- import matplotlib.pyplot as plt
- from neuromaps.datasets import fetch_fslr
- from surfplot import Plot
- from brainspace.datasets import load_parcellation
- from nilearn.plotting.cm import _cmap_d as nilearn_cmaps
- from matplotlib.colors import LinearSegmentedColormap,ListedColormap
- # Load and prepare task
- out_path = 'J:/HCP_analysis/DEAF/10_rest_predict_task/'
- path = 'J:/HCP_analysis/DEAF/data_DF_cole/BLOCK/'
- task = np.load(path + 'combined_all_tasks.npy') #91,360,8non language
- task_mean = np.mean(task[61:, :, :8], axis = (0,2))
- task_mean = zscore(task_mean)
- emb = task_mean[:,np.newaxis]
- ##加载cole模板
- surfaces = fetch_fslr()
- lh, rh = surfaces['veryinflated']
- p = Plot(lh, rh,brightness=.6)
- Cole_path = 'F:/early_language__experienced_data/经验期待和经验依赖分析/ROI/ColeAnticevicNetPartition/'
- coleLR = nib.load(Cole_path+'Glasser360Indices_LR.dscalar.nii').get_fdata()[:, 0:64984]
- #把模板填入到完整的皮层中
- for i in range(360):
- coleLR[coleLR==i+1] = emb[i,0]
- cifti = coleLR.T
- dataL = np.zeros((len(surfL[0]), cifti.shape[1]))
- dataL[cortL,:] = cifti[0:len(cortL),:]
- dataR = np.zeros((len(surfR[0]), cifti.shape[1]))
- dataR[cortR,:] = cifti[len(cortL):cortLen,:]
- cmap = nilearn_cmaps['brown_cyan']
- # 翻转色阶,将深色设置在两端
- colors = cmap(np.linspace(0, 1, cmap.N))
- colors = np.concatenate([colors[-int(cmap.N/2):], colors[:int(cmap.N/2)]], axis=0)
- new_cmap = LinearSegmentedColormap.from_list('custom', colors)
- p.add_layer({'left': dataL, 'right': dataR}, cmap=new_cmap, cbar=True)
- fig = p.build()
- plt.savefig(out_path + 'task_language_activation_NON-ELA.png', dpi=300, bbox_inches='tight')
- fig.show()
- # %%
- # 静息态平均梯度画图
- from brainspace.gradient import ProcrustesAlignment
- import numpy as np
- import pickle
- import matplotlib.pyplot as plt
- from neuromaps.datasets import fetch_fslr
- from surfplot import Plot
- from brainspace.datasets import load_parcellation
- from nilearn.plotting.cm import _cmap_d as nilearn_cmaps
- from matplotlib.colors import LinearSegmentedColormap,ListedColormap
- # Load and prepare task
- path = 'J:/HCP_analysis/DEAF/1_gradient/'
- out_path = 'J:/HCP_analysis/DEAF/10_rest_predict_task/'
- emb_all = np.load(path + 'restFC_align_Gradients_10.npy') # emb_all.shape(91, 360, 10)
- path = 'J:/HCP_analysis/DEAF/data_DF_cole/BLOCK/'
- task1 = np.load(path + 'combined_all_tasks.npy')[:, :, :8] #91,360,8 language
- task1 = np.mean(task1, axis = 2)
- task2 = np.load(path + 'combined_all_tasks.npy')[:, :, 8] #91,360,1 non language
- task = task1 - task2
- task_mean = np.mean(task[:34], axis = 0)
- emb = task_mean[:,np.newaxis]
- ##加载cole模板
- surfaces = fetch_fslr()
- lh, rh = surfaces['veryinflated']
- p = Plot(lh, rh,brightness=.6)
- Cole_path = 'F:/early_language__experienced_data/经验期待和经验依赖分析/ROI/ColeAnticevicNetPartition/'
- coleLR = nib.load(Cole_path+'Glasser360Indices_LR.dscalar.nii').get_fdata()[:, 0:64984]
- #把模板填入到完整的皮层中
- for i in range(360):
- coleLR[coleLR==i+1] = emb[i,0]
- cifti = coleLR.T
- dataL = np.zeros((len(surfL[0]), cifti.shape[1]))
- dataL[cortL,:] = cifti[0:len(cortL),:]
- dataR = np.zeros((len(surfR[0]), cifti.shape[1]))
- dataR[cortR,:] = cifti[len(cortL):cortLen,:]
- cmap = nilearn_cmaps['brown_cyan']
- # 翻转色阶,将深色设置在两端
- colors = cmap(np.linspace(0, 1, cmap.N))
- colors = np.concatenate([colors[-int(cmap.N/2):], colors[:int(cmap.N/2)]], axis=0)
- new_cmap = LinearSegmentedColormap.from_list('custom', colors)
- p.add_layer({'left': dataL, 'right': dataR}, cmap=new_cmap, cbar=True)
- fig = p.build()
- plt.savefig(out_path + 'task_language_activation_hearing_reverse.png', dpi=300, bbox_inches='tight')
- fig.show()
- # %%
- # 静息态平均梯度画图
- from brainspace.gradient import ProcrustesAlignment
- import numpy as np
- import pickle
- import matplotlib.pyplot as plt
- from neuromaps.datasets import fetch_fslr
- from surfplot import Plot
- from brainspace.datasets import load_parcellation
- from nilearn.plotting.cm import _cmap_d as nilearn_cmaps
- from matplotlib.colors import LinearSegmentedColormap,ListedColormap
- # Load and prepare task
- out_path = 'J:/HCP_analysis/DEAF/10_rest_predict_task/'
- predict_y = np.load(out_path + 'Y_pred_gradient_predict_task.npy') # emb_all.shape(91, 360, 10)
- predict_y_mean = np.mean(predict_y[:34], axis = (0,1))
- emb = predict_y_mean[:,np.newaxis]
- ##加载cole模板
- surfaces = fetch_fslr()
- lh, rh = surfaces['veryinflated']
- p = Plot(lh, rh,brightness=.6)
- Cole_path = 'F:/early_language__experienced_data/经验期待和经验依赖分析/ROI/ColeAnticevicNetPartition/'
- coleLR = nib.load(Cole_path+'Glasser360Indices_LR.dscalar.nii').get_fdata()[:, 0:64984]
- #把模板填入到完整的皮层中
- for i in range(360):
- coleLR[coleLR==i+1] = emb[i,0]
- cifti = coleLR.T
- dataL = np.zeros((len(surfL[0]), cifti.shape[1]))
- dataL[cortL,:] = cifti[0:len(cortL),:]
- dataR = np.zeros((len(surfR[0]), cifti.shape[1]))
- dataR[cortR,:] = cifti[len(cortL):cortLen,:]
- cmap = nilearn_cmaps['brown_cyan']
- # 翻转色阶,将深色设置在两端
- colors = cmap(np.linspace(0, 1, cmap.N))
- colors = np.concatenate([colors[-int(cmap.N/2):], colors[:int(cmap.N/2)]], axis=0)
- new_cmap = LinearSegmentedColormap.from_list('custom', colors)
- p.add_layer({'left': dataL, 'right': dataR}, cmap=new_cmap, cbar=True)
- fig = p.build()
- plt.savefig(out_path + 'task_language_predict_activation_hearing.png', dpi=300, bbox_inches='tight')
- fig.show()
- # %% [markdown]
- # # 使用静息态梯度的神经可塑性重构实际任务的激活差值
- # %%
- import numpy as np
- import shap
- from sklearn.linear_model import Ridge
- from scipy.stats import pearsonr
- import matplotlib.pyplot as plt
- from sklearn.linear_model import LinearRegression
- from scipy.stats import zscore
- # Load and prepare task
- path = 'J:/HCP_analysis/DEAF/1_gradient/'
- out_path = 'J:/HCP_analysis/DEAF/10_rest_predict_task/'
- emb_all = np.load(path + 'restFC_align_Gradients_10.npy') # emb_all.shape(91, 360, 10)
- path = 'J:/HCP_analysis/DEAF/data_DF_cole/BLOCK/'
- task_combined = np.load(path + 'combined_all_tasks.npy')[:, :, :8] #91,360,4 non language
- subs = 91
- features = 10
- blocks = 8
- tasks = 2
- rois = 360
- # Initialize result arrays
- corr_predict_ind = np.zeros((subs, tasks, blocks, 3))
- Y_pred_all = np.zeros((subs, tasks, blocks, rois))
- shap_values_all = np.zeros((subs, tasks, blocks, features)) # For storing SHAP values
- for d, task in enumerate(task_combined):
- for sub in range(subs):
- for block in range(blocks):
- # Prepare data
- X = zscore(emb_all[sub], axis=0) # Resting-state gradients (360, 10)
- Y = zscore(task[sub, :, block]) # Task activation (360,)
- # Fit linear regression model
- model = LinearRegression()
- model.fit(X, Y)
- # Compute predictions
- Y_pred = model.predict(X)
- Y_pred_all[sub, :, d] = Y_pred
- # Calculate statistics
- r_squared = model.score(X, Y)
- corr, p_value = pearsonr(Y, Y_pred)
- # Store results
- corr_predict_ind[sub, d, block, 0] = corr
- corr_predict_ind[sub, d, block, 1] = p_value
- corr_predict_ind[sub, d, block, 2] = r_squared
- # SHAP analysis
- explainer = shap.Explainer(model.predict, X)
- shap_values = explainer(X)
- # Average absolute SHAP values across ROIs
- shap_values_all[sub, d, block] = np.mean(np.abs(shap_values.values), axis=0)
- # Save results
- np.save(out_path + 'gradient_predict_task.npy', corr_predict_ind)
- np.save(out_path + 'Y_pred_gradient_predict_task.npy', Y_pred_all)
- np.save(out_path + 'shap_feature_importance.npy', shap_values_all)
- # Calculate and save mean SHAP values across subjects and tasks
- mean_shap = np.mean(shap_values_all, axis=(0, 1, 2))
- np.save(out_path + 'mean_shap_feature_importance.npy', mean_shap)
- # Plot mean SHAP importance
- plt.figure(figsize=(10, 6))
- plt.bar(range(features), mean_shap)
- plt.title('Average SHAP Feature Importance')
- plt.xlabel('Gradient Feature')
- plt.ylabel('Mean |SHAP value|')
- plt.savefig(out_path + 'mean_shap_feature_importance.png')
- plt.close()
- print("Analysis completed and results saved.")
- # %%
- import numpy as np
- import shap
- from sklearn.linear_model import Ridge
- from scipy.stats import pearsonr
- import matplotlib.pyplot as plt
- from sklearn.linear_model import LinearRegression
- from scipy.stats import zscore
- # Load and prepare task
- path = 'J:/HCP_analysis/DEAF/1_gradient/'
- out_path = 'J:/HCP_analysis/DEAF/10_rest_predict_task/'
- emb_all = np.load(path + 'restFC_align_Gradients_10.npy') # emb_all.shape(91, 360, 10)
- path = 'J:/HCP_analysis/DEAF/data_DF_cole/BLOCK/'
- task = np.load(path + 'combined_all_tasks.npy')[:, :, :8] #91,360,8 non language
- subs = 91
- features = 10
- rois = 360
- blocks = 8
- # Initialize result arrays
- corr_predict_ind = np.zeros((subs, blocks, 3))
- Y_pred_all = np.zeros((subs, blocks, rois))
- shap_values_all = np.zeros((subs, blocks, features)) # For storing SHAP values
- for sub in range(subs):
- for block in range(blocks):
- # Prepare data
- X = zscore(emb_all[sub], axis=0) # Resting-state gradients (360, 10)
- Y = zscore(task[sub, :, block]) # Task activation (360,)
- # Fit linear regression model
- model = LinearRegression()
- model.fit(X, Y)
- # Compute predictions
- Y_pred = model.predict(X)
- Y_pred_all[sub, block, :] = Y_pred
- # Calculate statistics
- r_squared = model.score(X, Y)
- corr, p_value = pearsonr(Y, Y_pred)
- # Store results
- corr_predict_ind[sub, block, 0] = corr
- corr_predict_ind[sub, block, 1] = p_value
- corr_predict_ind[sub, block, 2] = r_squared
- # SHAP analysis
- explainer = shap.Explainer(model.predict, X)
- shap_values = explainer(X)
- # Average absolute SHAP values across ROIs
- shap_values_all[sub, block] = np.mean(np.abs(shap_values.values), axis=0)
- # Save results
- np.save(out_path + 'gradient_predict_task.npy', corr_predict_ind)
- np.save(out_path + 'Y_pred_gradient_predict_task.npy', Y_pred_all)
- np.save(out_path + 'shap_feature_importance.npy', shap_values_all)
- # Calculate and save mean SHAP values across subjects and tasks
- mean_shap = np.mean(shap_values_all, axis=(0, 1, 2))
- np.save(out_path + 'mean_shap_feature_importance.npy', mean_shap)
- # Plot mean SHAP importance
- plt.figure(figsize=(10, 6))
- plt.bar(range(features), mean_shap)
- plt.title('Average SHAP Feature Importance')
- plt.xlabel('Gradient Feature')
- plt.ylabel('Mean |SHAP value|')
- plt.savefig(out_path + 'mean_shap_feature_importance.png')
- plt.close()
- print("Analysis completed and results saved.")
- # %% [markdown]
- # # 循环增加特征
- # %%
- import numpy as np
- import shap
- from sklearn.linear_model import Ridge
- from scipy.stats import pearsonr
- import matplotlib.pyplot as plt
- from sklearn.linear_model import LinearRegression
- from scipy.stats import zscore
- # Load and prepare task
- path = 'J:/HCP_analysis/DEAF/1_gradient/'
- out_path = 'J:/HCP_analysis/DEAF/10_rest_predict_task/'
- emb_all = np.load(path + 'restFC_align_Gradients_10.npy') # emb_all.shape(91, 360, 10)
- path = 'J:/HCP_analysis/DEAF/data_DF_cole/BLOCK/'
- task = np.load(path + 'combined_all_tasks.npy')[:, :, :8] #91,360,4 non language
- subs = 91
- features = 10
- blocks = 8
- rois = 360 # Added this since it was used but not defined
- # Initialize result arrays for all feature combinations
- # We'll have results for each feature count (1-10), each subject, each block
- corr_predict_ind = np.zeros((features, subs, blocks, 3)) # Now shape (10, 91, 4, 3)
- Y_pred_all = np.zeros((features, subs, blocks, rois)) # Now shape (10, 91, 4, 360)
- shap_values_all = np.zeros((features, subs, blocks, features)) # Now shape (10, 91, 4, 10)
- for num_features in range(1, features+1): # Loop from 1 to 10 features
- print(f"Processing models with {num_features} features...")
- for sub in range(subs):
- for block in range(blocks):
- # Prepare data - use only the first num_features features
- X = zscore(emb_all[sub, :, :num_features], axis=0) # (360, num_features)
- Y = zscore(task[sub, :, block]) # Task activation (360,)
- # Fit linear regression model
- model = LinearRegression()
- model.fit(X, Y)
- # Compute predictions
- Y_pred = model.predict(X)
- Y_pred_all[num_features-1, sub, block, :] = Y_pred # num_features-1 for 0-based index
- # Calculate statistics
- r_squared = model.score(X, Y)
- corr, p_value = pearsonr(Y, Y_pred)
- # Store results
- corr_predict_ind[num_features-1, sub, block, 0] = corr
- corr_predict_ind[num_features-1, sub, block, 1] = p_value
- corr_predict_ind[num_features-1, sub, block, 2] = r_squared
- # SHAP analysis
- explainer = shap.Explainer(model.predict, X)
- shap_values = explainer(X)
- # Store SHAP values (only the first num_features will have values)
- shap_values_all[num_features-1, sub, block, :num_features] = np.mean(np.abs(shap_values.values), axis=0)
- # Save results
- np.save(out_path + 'gradient_predict_task_by_feature_count.npy', corr_predict_ind)
- np.save(out_path + 'Y_pred_gradient_predict_task_by_feature_count.npy', Y_pred_all)
- np.save(out_path + 'shap_feature_importance_by_feature_count.npy', shap_values_all)
- # Calculate and save mean results across subjects and tasks for each feature count
- mean_corr = np.mean(corr_predict_ind[:,:,:,0], axis=(1,2)) # Mean correlation for each feature count
- mean_r2 = np.mean(corr_predict_ind[:,:,:,2], axis=(1,2)) # Mean R-squared for each feature count
- mean_shap = np.zeros((features, features)) # Will store mean SHAP for each feature at each feature count
- for num_features in range(features):
- # For each feature count, calculate mean SHAP values for the features used
- mean_shap[num_features, :num_features+1] = np.mean(shap_values_all[num_features, :, :, :num_features+1], axis=(0,1))
- np.save(out_path + 'mean_correlation_by_feature_count.npy', mean_corr)
- np.save(out_path + 'mean_r2_by_feature_count.npy', mean_r2)
- np.save(out_path + 'mean_shap_by_feature_count.npy', mean_shap)
- # Plot results
- plt.figure(figsize=(12, 8))
- # Plot mean correlation by feature count
- plt.subplot(2, 2, 1)
- plt.plot(range(1, features+1), mean_corr, marker='o')
- plt.title('Mean Prediction Correlation by Number of Features')
- plt.xlabel('Number of Features')
- plt.ylabel('Mean Pearson Correlation')
- # Plot mean R-squared by feature count
- plt.subplot(2, 2, 2)
- plt.plot(range(1, features+1), mean_r2, marker='o')
- plt.title('Mean R-squared by Number of Features')
- plt.xlabel('Number of Features')
- plt.ylabel('Mean R-squared')
- # Plot SHAP importance heatmap
- plt.subplot(2, 1, 2)
- plt.imshow(mean_shap.T, aspect='auto', cmap='viridis')
- plt.colorbar(label='Mean |SHAP value|')
- plt.title('SHAP Feature Importance by Number of Features Used')
- plt.xlabel('Number of Features Used in Model')
- plt.ylabel('Gradient Feature')
- plt.yticks(range(features), range(1, features+1))
- plt.xticks(range(features), range(1, features+1))
- plt.tight_layout()
- plt.savefig(out_path + 'feature_incremental_results.png')
- plt.close()
- print("Analysis completed and results saved.")
- # %% [markdown]
- # # 断点回归分析
- # %%
- import numpy as np
- import matplotlib.pyplot as plt
- from sklearn.linear_model import LinearRegression
- from scipy.stats import ttest_1samp, ttest_rel, zscore
- import seaborn as sns
- # Load data
- out_path = 'J:/HCP_analysis/DEAF/10_rest_predict_task/'
- corr = np.load(out_path + 'gradient_predict_task_by_feature_count.npy')[:, :, :, 0] # (10, 91, 9)
- # Preprocess: Fisher z-transform but don't average across blocks
- corr_z = np.arctanh(corr) # (10, 91, 8)
- # Define breakpoint (cutoff=3)
- cutoff = 2
- dimensions = np.arange(10) # 0-9
- # Initialize storage for results
- n_subjects = corr_z.shape[1]
- n_blocks = corr_z.shape[2]
- slopes_low = np.zeros((n_subjects, n_blocks)) # Low-dim slopes for each subject and block
- slopes_high = np.zeros((n_subjects, n_blocks)) # High-dim slopes
- jump_effects = np.zeros((n_subjects, n_blocks)) # Jump effects
- for subj in range(n_subjects):
- for block in range(n_blocks):
- y = corr_z[:, subj, block]
- # Fit low-dimension (0-3) regression
- X_low = dimensions[dimensions <= cutoff].reshape(-1, 1)
- reg_low = LinearRegression().fit(X_low, y[dimensions <= cutoff])
- y_pred_low = reg_low.predict([[cutoff]])
- slopes_low[subj, block] = reg_low.coef_[0]
- # Fit high-dimension (3-9) regression
- X_high = dimensions[dimensions >= cutoff].reshape(-1, 1)
- reg_high = LinearRegression().fit(X_high, y[dimensions >= cutoff])
- y_pred_high = reg_high.predict([[cutoff]])
- slopes_high[subj, block] = reg_high.coef_[0]
- # Calculate jump effect
- jump_effects[subj, block] = y_pred_high - y_pred_low
- # =================================================================
- # 1. Analyze results across subjects and blocks
- # =================================================================
- # Flatten the results across blocks for subject-level analysis
- slopes_low_flat = slopes_low.ravel()
- slopes_high_flat = slopes_high.ravel()
- jump_effects_flat = jump_effects.ravel()
- # Low-dimension slopes
- t_low, p_low = ttest_1samp(slopes_low_flat, 0)
- print("=== Low-dimension regression (0-3) ===")
- print(f"Mean Slope: {np.mean(slopes_low_flat):.4f} ± {np.std(slopes_low_flat, ddof=1):.4f}")
- print(f"t = {t_low:.4f}, p = {p_low:.4f}\n")
- # High-dimension slopes
- t_high, p_high = ttest_1samp(slopes_high_flat, 0)
- print("=== High-dimension regression (3-9) ===")
- print(f"Mean Slope: {np.mean(slopes_high_flat):.4f} ± {np.std(slopes_high_flat, ddof=1):.4f}")
- print(f"t = {t_high:.4f}, p = {p_high:.4f}\n")
- # Slope comparison (paired t-test)
- t_slope_diff, p_slope_diff = ttest_rel(slopes_low_flat, slopes_high_flat)
- print("=== Low vs High dimension slope comparison ===")
- print(f"Mean Slope Difference: {np.mean(slopes_low_flat - slopes_high_flat):.4f}")
- print(f"t = {t_slope_diff:.4f}, p = {p_slope_diff:.4f}\n")
- # Jump effects
- mean_jump = np.mean(jump_effects_flat)
- std_jump = np.std(jump_effects_flat, ddof=1)
- t_jump, p_jump = ttest_1samp(jump_effects_flat, 0)
- print("=== Breakpoint jump effect ===")
- print(f"Mean Jump: {mean_jump:.4f} ± {std_jump:.4f}")
- print(f"t = {t_jump:.4f}, p = {p_jump:.4f}")
- # =================================================================
- # 2. Mixed-effects analysis (optional)
- # =================================================================
- # For a more sophisticated analysis, you could use mixed-effects models
- # that account for both within-subject and between-subject variability
- # (would require packages like statsmodels or pingouin)
- # =================================================================
- # 3. Visualization
- # =================================================================
- plt.figure(figsize=(15, 5))
- # Slope distributions
- plt.subplot(1, 3, 1)
- sns.histplot(slopes_low_flat, color='blue', kde=True, label='Low Dim (0-3)')
- sns.histplot(slopes_high_flat, color='orange', kde=True, label='High Dim (3-9)')
- plt.axvline(0, color='black', linestyle='--')
- plt.xlabel('Regression Slope')
- plt.ylabel('Frequency')
- plt.title('Slope Distribution by Dimension')
- plt.legend()
- # Slope differences
- plt.subplot(1, 3, 2)
- sns.histplot(slopes_low_flat - slopes_high_flat, color='green', kde=True)
- plt.axvline(0, color='black', linestyle='--')
- plt.xlabel('Slope Difference (Low - High)')
- plt.title('Slope Difference Distribution')
- # Jump effects
- plt.subplot(1, 3, 3)
- sns.histplot(jump_effects_flat, color='red', kde=True)
- plt.axvline(mean_jump, color='black', linestyle='--', label=f'Mean Jump = {mean_jump:.3f}')
- plt.xlabel('Jump Effect at Cutoff')
- plt.title('Jump Effect Distribution')
- plt.legend()
- plt.tight_layout()
- plt.show()
- # %%
- import numpy as np
- import shap
- from sklearn.linear_model import Ridge
- from scipy.stats import pearsonr
- import matplotlib.pyplot as plt
- from sklearn.linear_model import LinearRegression
- from scipy.stats import zscore
- out_path = 'J:/HCP_analysis/DEAF/10_rest_predict_task/'
- corr = np.load(out_path + 'gradient_predict_task_by_feature_count.npy')[:, :, :, 0] # (10, 91, 4)
- # 计算均值和误差(标准差或标准误)
- mean_corr = np.mean(corr, axis=(1, 2)) # 跨被试和block的平均
- std_corr = np.std(corr, axis=(1, 2)) # 标准差
- mean_shap = np.load(out_path + 'mean_shap_by_feature_count.npy')
- subs = 91
- features = 10
- blocks = 8
- rois = 360 # Added this since it was used but not defined
- # 绘图设置
- plt.figure(figsize=(8, 5))
- title_font = {'fontsize': 18, 'fontweight': 'bold'}
- label_font = {'fontsize': 18, 'fontweight': 'bold'}
- tick_font = {'fontsize': 18, 'fontweight': 'bold'}
- # 绘制均值线及误差线(这里使用标准误,如需标准差请替换为std_corr)
- plt.errorbar(
- range(1, 11),
- mean_corr,
- yerr=std_corr, # 误差线长度(标准误)
- fmt='-o', # 线型+标记
- linewidth=3,
- markersize=8,
- color='gray',
- capsize=5, # 误差线端帽长度
- capthick=2, # 端帽线宽
- ecolor='gray' # 误差线颜色
- )
- # 美化图形
- plt.xlabel('Number of Features', **label_font)
- plt.ylabel('Correlation (±SD)', **label_font)
- plt.xticks(range(1, 11), **tick_font)
- plt.yticks(**tick_font)
- plt.grid(False)
- ax = plt.gca()
- ax.spines['top'].set_visible(False)
- ax.spines['right'].set_visible(False)
- ax.spines['bottom'].set_linewidth(3)
- ax.spines['left'].set_linewidth(3)
- ax.spines['bottom'].set_color('black')
- ax.spines['left'].set_color('black')
- plt.tight_layout()
- plt.savefig(out_path + 'mean_correlation_plot_with_errorbars.png', dpi=300, bbox_inches='tight')
- plt.close()
- # Second plot: SHAP Heatmap
- plt.figure(figsize=(7, 4))
- im = plt.imshow(mean_shap.T, aspect='auto', cmap='viridis')
- #plt.title('Feature Importance by Number of Features', **title_font)
- plt.xlabel('Number of Features Used in Model', **label_font)
- #plt.ylabel('Gradient Feature', **label_font)
- plt.yticks(range(features), [f'G{i+1}' for i in range(10)], **tick_font)
- plt.xticks(range(features), range(1, features+1), **tick_font)
- cbar = plt.colorbar(im, pad=0.05)
- cbar.set_label('Mean SHAP Value', **label_font)
- cbar.ax.tick_params(
- labelsize=15,
- which='both',
- width=2,
- length=6
- )
- for label in cbar.ax.get_yticklabels():
- label.set_fontweight('bold')
- plt.tight_layout()
- plt.savefig(out_path + 'shap_heatmap.png', dpi=300, bbox_inches='tight')
- plt.close()
- # %%
- import numpy as np
- import matplotlib.pyplot as plt
- from matplotlib.colors import LinearSegmentedColormap
- from scipy.stats import linregress
- out_path = 'J:/HCP_analysis/DEAF/10_rest_predict_task/'
- corr = np.load(out_path + 'gradient_predict_task_by_feature_count.npy')[:, :, :, 0] # (10, 91, 8)
- # Define 10-step red gradient colormap
- red_gradient = [
- '#400000', # 深黑红
- '#800000', # 暗红
- '#b30000', # 标准红
- '#e60000', # 亮红
- '#ff3333', # 浅红
- '#ff6666', # 淡红
- '#ff9999', # 粉红
- '#ffb3b3', # 浅粉
- '#ffd6d6', # 极浅粉
- '#ffcccc' # 淡灰红
- ]
- n_dims = 10
- # Calculate statistics
- mean_corr = np.mean(corr, axis=(1, 2)) # Average across subjects and blocks
- std_corr = np.std(corr, axis=(1, 2)) # Standard deviation
- # Plot settings
- plt.figure(figsize=(8, 5))
- label_font = {'fontsize': 24, 'fontweight': 'bold'}
- tick_font = {'fontsize': 24, 'fontweight': 'bold'}
- # Plot jittered individual points with gradient colors
- for i in range(10):
- # Create jittered x positions
- x_jitter = np.random.normal(i+1, 0.08, size=corr[i].size)
- plt.scatter(
- x_jitter,
- corr[i].flatten(),
- color=red_gradient[i],
- alpha=0.7,
- s=25,
- edgecolor='white',
- linewidth=0.5,
- zorder=1
- )
- # Add boxplot with thicker elements and black borders
- box_data = [corr[i].flatten() for i in range(10)]
- box = plt.boxplot(
- box_data,
- positions=range(1, 11),
- widths=0.5,
- patch_artist=True,
- showfliers=False,
- medianprops={'color': 'black', 'linewidth': 3}, # Thicker median line
- boxprops={'color': 'black', 'linewidth': 3}, # Black border for box
- whiskerprops={'color': 'black', 'linewidth': 3}, # Black whiskers
- capprops={'color': 'black', 'linewidth': 3}, # Black caps
- zorder=2
- )
- # Color boxes with red gradient
- for patch, color in zip(box['boxes'], red_gradient):
- patch.set_facecolor(color)
- patch.set_alpha(0.4)
- # Calculate and plot regression lines
- x_vals = np.array(range(1, 11))
- # Regression for features 1-3 (dark red)
- x1 = x_vals[:3]
- y1 = mean_corr[:3]
- slope1, intercept1, _, _, _ = linregress(x1, y1)
- plt.plot(x1, intercept1 + slope1*x1,
- color='#800000', linewidth=5, linestyle='-',
- label='Features 1-3 Trend')
- # Regression for features 3-10 (pink)
- x2 = x_vals[2:] # From feature 3 to 10
- y2 = mean_corr[2:]
- slope2, intercept2, _, _, _ = linregress(x2, y2)
- plt.plot(x2, intercept2 + slope2*x2,
- color='#ff9999', linewidth=5, linestyle='-',
- label='Features 3-10 Trend')
- # Plot mean points without connecting line
- plt.scatter(
- range(1, 11),
- mean_corr,
- s=100, # Larger point size
- color='black',
- edgecolor='white',
- linewidth=2,
- zorder=4
- )
- # Add error bars separately (without connecting line)
- plt.errorbar(
- range(1, 11),
- mean_corr,
- fmt='none', # No markers or connecting line
- color='black',
- capsize=5,
- capthick=2,
- linewidth=1.5,
- zorder=3
- )
- # Formatting
- plt.xlabel('Number of Features', **label_font)
- plt.ylabel('Correlation (±SD)', **label_font)
- plt.xticks(range(1, 11), **tick_font)
- plt.yticks(**tick_font)
- plt.grid(False)
- ax = plt.gca()
- ax.spines['top'].set_visible(False)
- ax.spines['right'].set_visible(False)
- ax.spines['bottom'].set_linewidth(3)
- ax.spines['left'].set_linewidth(3)
- ax.spines['bottom'].set_color('black')
- ax.spines['left'].set_color('black')
- plt.tight_layout()
- plt.savefig(out_path + 'feature_correlation_plot.png', dpi=300, bbox_inches='tight', transparent=True)
- plt.close()
- # %%
- import numpy as np
- import matplotlib.pyplot as plt
- from matplotlib.colors import LinearSegmentedColormap
- from scipy.stats import linregress
- out_path = 'J:/HCP_analysis/DEAF/10_rest_predict_task/'
- corr = np.load(out_path + 'gradient_predict_task_by_feature_count.npy')[:, :, :, 0] # (10, 91, 4)
- # Define 10-step red gradient colormap
- red_gradient = [
- '#400000', # 深黑红
- '#800000', # 暗红
- '#b30000', # 标准红
- '#e60000', # 亮红
- '#ff3333', # 浅红
- '#ff6666', # 淡红
- '#ff9999', # 粉红
- '#ffb3b3', # 浅粉
- '#ffd6d6', # 极浅粉
- '#ffcccc' # 淡灰红
- ]
- n_dims = 10
- # Calculate statistics
- mean_corr = np.mean(corr, axis=(1, 2)) # Average across subjects and blocks
- std_corr = np.std(corr, axis=(1, 2)) # Standard deviation
- # Plot settings
- plt.figure(figsize=(8, 5))
- label_font = {'fontsize': 24, 'fontweight': 'bold'}
- tick_font = {'fontsize': 24, 'fontweight': 'bold'}
- # Plot jittered individual points with gradient colors
- for i in range(10):
- # Create jittered x positions
- x_jitter = np.random.normal(i+1, 0.08, size=corr[i].size)
- plt.scatter(
- x_jitter,
- corr[i].flatten(),
- color=red_gradient[i],
- alpha=0.7,
- s=25,
- edgecolor='white',
- linewidth=0.5,
- zorder=1
- )
- # Plot mean points with error bars showing standard deviation
- plt.errorbar(
- range(1, 11),
- mean_corr,
- yerr=std_corr,
- fmt='o',
- markersize=10,
- capsize=5,
- capthick=3,
- elinewidth=3,
- color='black',
- ecolor='black',
- markerfacecolor='black',
- markeredgecolor='white',
- markeredgewidth=2,
- zorder=4
- )
- # Calculate and plot regression lines
- x_vals = np.array(range(1, 11))
- # Regression for features 1-3 (dark red)
- x1 = x_vals[:3]
- y1 = mean_corr[:3]
- slope1, intercept1, _, _, _ = linregress(x1, y1)
- plt.plot(x1, intercept1 + slope1*x1,
- color='#800000', linewidth=5, linestyle='-',
- label='Features 1-3 Trend')
- # Regression for features 3-10 (pink)
- x2 = x_vals[2:] # From feature 3 to 10
- y2 = mean_corr[2:]
- slope2, intercept2, _, _, _ = linregress(x2, y2)
- plt.plot(x2, intercept2 + slope2*x2,
- color='#ff9999', linewidth=5, linestyle='-',
- label='Features 3-10 Trend')
- # Formatting
- plt.xlabel('Number of Features', **label_font)
- plt.ylabel('Correlation (±SD)', **label_font)
- plt.xticks(range(1, 11), **tick_font)
- plt.yticks(**tick_font)
- plt.grid(False)
- ax = plt.gca()
- ax.spines['top'].set_visible(False)
- ax.spines['right'].set_visible(False)
- ax.spines['bottom'].set_linewidth(3)
- ax.spines['left'].set_linewidth(3)
- ax.spines['bottom'].set_color('black')
- ax.spines['left'].set_color('black')
- plt.tight_layout()
- plt.savefig(out_path + 'feature_correlation_plot_mean_SD.png', dpi=300, bbox_inches='tight', transparent=True)
- plt.close()
- # %% [markdown]
- # # 统计检验
- # %%
- import numpy as np
- import matplotlib.pyplot as plt
- import os
- import pandas as pd
- import statsmodels.api as sm
- import statsmodels.formula.api as smf
- from scipy import stats
- # Set paths
- input_path = 'J:/HCP_analysis/Deaf/10_rest_predict_task/'
- output_path = 'J:/HCP_analysis/Deaf/10_rest_predict_task/results/'
- os.makedirs(output_path, exist_ok=True)
- # Load and prepare data
- corr_values_all = np.load(input_path + 'gradient_predict_task.npy') # shape: (91, 4, 3)
- corr_values_all = np.arctanh(corr_values_all)
- # Prepare DataFrame for mixed model
- data_list = []
- subjects = np.arange(corr_values_all.shape[0])
- blocks = np.arange(corr_values_all.shape[1])
- for subj in subjects:
- for block in blocks:
- group = 'Hearing' if subj < 34 else 'DNS'
- data_list.append({
- 'Subject': f'sub-{subj:03d}',
- 'Block': block,
- 'Group': group,
- 'Correlation': corr_values_all[subj, block, 0]
- })
- df = pd.DataFrame(data_list)
- # Fit mixed effects model
- model = smf.mixedlm("Correlation ~ Group",
- data=df,
- groups=df["Subject"],
- re_formula="~1").fit()
- # Get p-value for group effect
- p_value = model.pvalues['Group[T.Hearing]']
- # Prepare plotting data
- hearing = corr_values_all[:34,:,0].flatten()
- deaf = corr_values_all[34:,:,0].flatten()
- # Create figure
- plt.figure(figsize=(8, 6))
- plt.rcParams.update({
- 'font.size': 12,
- 'axes.linewidth': 1.5,
- 'xtick.major.width': 1.5,
- 'ytick.major.width': 1.5
- })
- # Plot boxplots with thicker borders (linewidth=3)
- boxprops = dict(linewidth=3, color='black') # Thicker borders
- whiskerprops = dict(linewidth=3, color='black') # Thicker whiskers
- capprops = dict(linewidth=3, color='black') # Thicker caps
- medianprops = dict(linewidth=3, color='black') # Thicker median line
- bp = plt.boxplot([hearing, deaf],
- labels=['Hearing', 'DNS'],
- patch_artist=True,
- widths=0.6,
- boxprops=boxprops,
- whiskerprops=whiskerprops,
- capprops=capprops,
- medianprops=medianprops)
- # Set box fill colors to #F08E64 (orange) and #5E93CB (blue)
- colors = ['#F08E64', '#5E93CB']
- for patch, color in zip(bp['boxes'], colors):
- patch.set_facecolor(color)
- patch.set_alpha(0.7)
- # Plot individual data points with jitter (larger size)
- def plot_jitter(data, x_pos, color, alpha=0.6):
- jitter = np.random.normal(0, 0.05, size=len(data))
- plt.scatter(x_pos + jitter, data, color=color, alpha=alpha, s=250, edgecolor='none')
- plot_jitter(hearing, 1, '#F08E64', alpha=0.6)
- plot_jitter(deaf, 2, '#5E93CB', alpha=0.6)
- # Calculate standard errors for error bars
- se_hearing = stats.sem(hearing)
- se_deaf = stats.sem(deaf)
- # Mark means with white diamonds and thicker error bars
- mean_hearing = np.mean(hearing)
- mean_deaf = np.mean(deaf)
- # Plot mean markers with thicker error bars (linewidth=3)
- plt.errorbar([1], [mean_hearing], #yerr=se_hearing,
- fmt='none', ecolor='black', elinewidth=3, capsize=10, capthick=3)
- plt.errorbar([2], [mean_deaf], #yerr=se_deaf,
- fmt='none', ecolor='black', elinewidth=3, capsize=10, capthick=3)
- plt.scatter(1, mean_hearing, color='white', s=250, edgecolor='black',
- marker='D', zorder=10, linewidth=2, label='Mean')
- plt.scatter(2, mean_deaf, color='white', s=250, edgecolor='black',
- marker='D', zorder=10, linewidth=2)
- # Add significance annotation
- y_max = max(np.max(hearing), np.max(deaf)) + 0.1
- plt.plot([1, 1, 2, 2], [y_max-0.05, y_max, y_max, y_max-0.05],
- color='black', lw=3) # Thicker significance line
- if p_value < 0.001:
- sig_text = '***'
- elif p_value < 0.01:
- sig_text = '**'
- elif p_value < 0.05:
- sig_text = '*'
- else:
- sig_text = 'n.s.'
- plt.text(1.5, y_max, sig_text,
- ha='center', va='bottom',
- fontsize=48, fontweight='bold')
- # Customize plot
- plt.xticks(fontsize=46, fontweight='bold')
- plt.yticks(fontsize=46, fontweight='bold')
- # Adjust spines (thicker)
- ax = plt.gca()
- ax.spines['top'].set_visible(False)
- ax.spines['right'].set_visible(False)
- ax.spines['bottom'].set_linewidth(4)
- ax.spines['left'].set_linewidth(4)
- ax.spines['bottom'].set_color('black')
- ax.spines['left'].set_color('black')
- plt.tight_layout()
- plt.savefig(output_path + 'hearing_vs_deaf_boxplot_thick_borders.png',
- dpi=300, bbox_inches='tight', transparent=True)
- plt.show()
- # Print model summary
- print(model.summary())
- # %%
- import numpy as np
- import os
- import matplotlib.pyplot as plt
- import seaborn as sns
- import pandas as pd
- import statsmodels.api as sm
- import statsmodels.formula.api as smf
- from scipy.stats import zscore
- from matplotlib.colors import LinearSegmentedColormap
- from statsmodels.stats.multitest import multipletests # For p-value correction
- # Set paths
- input_path = 'J:/HCP_analysis/Deaf/10_rest_predict_task/'
- output_path = 'J:/HCP_analysis/Deaf/10_rest_predict_task/results/'
- os.makedirs(output_path, exist_ok=True)
- # Define gradient color schemes
- hearing_colors = LinearSegmentedColormap.from_list('hearing', ['#F08E64', '#F8C8B0'])(np.linspace(0, 1, 10))
- deaf_colors = LinearSegmentedColormap.from_list('DNS', ['#5E93CB', '#B8D1E8'])(np.linspace(0, 1, 10))
- # Load and standardize data
- shap_values_all = np.load(input_path + 'shap_feature_importance.npy') # shape: (91, 4, 10) or (91, 8, 10)
- shap_values_all = zscore(shap_values_all, axis=2) # Standardize within each dimension
- # Define group sizes
- n_Hearing = 34
- n_Deaf = 27
- n_subjects = n_Hearing + n_Deaf
- n_blocks = 8
- n_dims = 10
- # Prepare DataFrame for mixed model
- data_list = []
- for subj in range(n_subjects):
- group = 'Hearing' if subj < n_Hearing else 'DNS'
- for block in range(n_blocks):
- for dim in range(n_dims):
- data_list.append({
- 'subject': f'subj_{subj}',
- 'group': group,
- 'block': f'block_{block}',
- 'dimension': dim,
- 'shap_value': shap_values_all[subj, block, dim]
- })
- df = pd.DataFrame(data_list)
- # Initialize storage for results
- lmm_results = []
- # Fit mixed models for each SHAP dimension
- for dim in range(n_dims):
- dim_df = df[df['dimension'] == dim].copy()
- # Linear Mixed Effects Model with subject random intercept
- model = smf.mixedlm(
- "shap_value ~ group",
- data=dim_df,
- groups=dim_df["subject"],
- re_formula="~1" # Random intercept per subject
- )
- try:
- result = model.fit()
- coef = result.fe_params['group[T.Hearing]'] # Effect of Hearing vs Deaf
- pval = result.pvalues['group[T.Hearing]']
- t_stat = result.tvalues['group[T.Hearing]']
- lmm_results.append({
- 'dimension': dim,
- 'coefficient': coef,
- 't_statistic': t_stat,
- 'p_value': pval,
- 'significant': pval < 0.05 # Direct significance without correction
- })
- except Exception as e:
- print(f"Failed to fit model for dimension {dim}: {str(e)}")
- lmm_results.append({
- 'dimension': dim,
- 'coefficient': np.nan,
- 't_statistic': np.nan,
- 'p_value': np.nan,
- 'significant': False
- })
- # Convert to DataFrame
- results_df = pd.DataFrame(lmm_results)
- # Apply p-value correction (FDR)
- pvals = results_df['p_value'].values
- rejected, pvals_corrected, _, _ = multipletests(pvals, alpha=0.05, method='fdr_bh')
- results_df['p_value_corrected'] = pvals_corrected
- results_df['significant_corrected'] = rejected # Update significance based on corrected p-values
- # Save corrected results
- results_df.to_csv(output_path + 'lmm_results_corrected.csv', index=False)
- # Visualization with more pronounced gradients
- plt.figure(figsize=(12, 6.5)) # Larger figure size
- # Calculate group means (averaged across blocks)
- group_means = df.groupby(['group', 'dimension'])['shap_value'].mean().unstack()
- group_sems = df.groupby(['group', 'dimension'])['shap_value'].sem().unstack()
- # ===================== 新增:计算“每个被试在每个维度”的单个点(跨block平均) =====================
- subj_means = df.groupby(['group', 'subject', 'dimension'])['shap_value'].mean()
- hearing_subjects = subj_means.loc['Hearing'].index.get_level_values('subject').unique()
- dns_subjects = subj_means.loc['DNS'].index.get_level_values('subject').unique()
- np.random.seed(0) # 抖动可复现
- # =============================================================================================
- # Plot with more pronounced gradient colors
- x = range(n_dims)
- for dim in range(n_dims):
- # ===================== 新增:叠加被试散点(颜色与对应维度一致,透明,不遮挡误差线) =====================
- # Hearing 所有被试点(向左轻微抖动)
- y_hearing_pts = np.array([subj_means.loc[('Hearing', s, dim)] for s in hearing_subjects])
- x_hearing_pts = dim + np.random.uniform(-0.18, -0.06, size=len(y_hearing_pts))
- plt.scatter(x_hearing_pts, y_hearing_pts,
- s=75, color=hearing_colors[dim], alpha=0.88,
- edgecolors='none', zorder=1)
- # DNS 所有被试点(向右轻微抖动)
- y_dns_pts = np.array([subj_means.loc[('DNS', s, dim)] for s in dns_subjects])
- x_dns_pts = dim + np.random.uniform(0.06, 0.18, size=len(y_dns_pts))
- plt.scatter(x_dns_pts, y_dns_pts,
- s=75, color=deaf_colors[dim], alpha=0.88,
- edgecolors='none', zorder=1)
- # ==========================================================================================
- # Hearing markers - darker to lighter
- plt.errorbar(dim, group_means.loc['Hearing', dim],
- yerr=group_sems.loc['Hearing', dim],
- fmt='o', color=hearing_colors[dim],
- markersize=20, capsize=6, capthick=3,
- elinewidth=3, markeredgewidth=2,
- markeredgecolor='black', zorder=7)
- # Deaf markers - darker to lighter
- plt.errorbar(dim, group_means.loc['DNS', dim],
- yerr=group_sems.loc['DNS', dim],
- fmt='s', color=deaf_colors[dim],
- markersize=20, capsize=6, capthick=3,
- elinewidth=3, markeredgewidth=2,
- markeredgecolor='black', zorder=7)
- # Connect the dots with gradient-colored lines
- for dim in range(n_dims-1):
- plt.plot([dim, dim+1],
- [group_means.loc['Hearing', dim], group_means.loc['Hearing', dim+1]],
- '-', color=hearing_colors[dim], linewidth=4, alpha=0.8)
- plt.plot([dim, dim+1],
- [group_means.loc['DNS', dim], group_means.loc['DNS', dim+1]],
- '-', color=deaf_colors[dim], linewidth=4, alpha=0.8)
- # Mark significant dimensions with larger stars (based on corrected p-values)
- sig_dims_corrected = results_df[results_df['significant_corrected']]['dimension']
- for dim in sig_dims_corrected:
- y_pos = max(group_means.loc['Hearing', dim], group_means.loc['DNS', dim]) + 0.15
- plt.scatter(dim, y_pos, marker='*', color='black', s=600, zorder=10)
- # Customize plot appearance
- plt.ylabel('Standardized SHAP Value', fontsize=29, fontweight='bold', labelpad=15)
- plt.xticks(range(10), [f'G{i+1}' for i in range(10)], fontsize=30, fontweight='bold')
- plt.yticks(fontsize=30, fontweight='bold')
- # Create custom legend
- from matplotlib.lines import Line2D
- legend_elements = [
- Line2D([0], [0], marker='o', color='w', label='Hearing',
- markerfacecolor=hearing_colors[0], markersize=25, markeredgewidth=2),
- Line2D([0], [0], marker='s', color='w', label='DNS',
- markerfacecolor=deaf_colors[0], markersize=25, markeredgewidth=2)
- ]
- plt.legend(handles=legend_elements, fontsize=48, prop={'weight':'bold', 'size':26},
- framealpha=0.9, loc='upper right')
- # Customize spines
- ax = plt.gca()
- ax.spines['top'].set_visible(False)
- ax.spines['right'].set_visible(False)
- ax.spines['bottom'].set_linewidth(4)
- ax.spines['left'].set_linewidth(4)
- ax.spines['bottom'].set_color('black')
- ax.spines['left'].set_color('black')
- plt.grid(False)
- plt.tight_layout()
- plt.savefig(output_path + 'shap_comparison_gradient_colors_corrected.png',
- dpi=300, bbox_inches='tight', transparent=True)
- plt.close()
- print("Analysis complete. Results saved to:", output_path)
- # %% [markdown]
- # # 对比有无语言经验的差异
- # %%
- import numpy as np
- import matplotlib.pyplot as plt
- import os
- import pandas as pd
- import statsmodels.api as sm
- import statsmodels.formula.api as smf
- from scipy import stats
- # Set paths
- input_path = 'J:/HCP_analysis/Deaf/10_rest_predict_task/'
- output_path = 'J:/HCP_analysis/Deaf/10_rest_predict_task/results_lan_ELA/'
- os.makedirs(output_path, exist_ok=True)
- # Load and prepare data
- corr_values_all = np.load(input_path + 'gradient_predict_task.npy') # shape: (91, 4, 3)
- corr_values_all = np.arctanh(corr_values_all)
- # Prepare DataFrame for mixed model
- data_list = []
- subjects = np.arange(34, corr_values_all.shape[0]) # Only deaf subjects (34-90)
- blocks = np.arange(corr_values_all.shape[1])
- for i, subj in enumerate(subjects):
- for block in blocks:
- group = 'ELA' if i < 27 else 'Non_ELA' # ELA:34-60 (27), Non_ELA:61-90 (30)
- data_list.append({
- 'Subject': f'sub-{subj:03d}',
- 'Block': block,
- 'Group': group,
- 'Correlation': corr_values_all[subj, block, 0]
- })
- df = pd.DataFrame(data_list)
- # Fit mixed effects model
- model = smf.mixedlm("Correlation ~ Group",
- data=df,
- groups=df["Subject"],
- re_formula="~1").fit()
- # Get p-value for group effect
- p_value = model.pvalues['Group[T.Non_ELA]'] # Reference is ELA
- # Prepare plotting data
- ELA = corr_values_all[34:61,:,0].flatten()
- Non_ELA = corr_values_all[61:,:,0].flatten()
- # Create figure with larger size
- plt.figure(figsize=(8, 6))
- plt.rcParams.update({
- 'font.size': 12,
- 'axes.linewidth': 2,
- 'xtick.major.width': 2,
- 'ytick.major.width': 2
- })
- # Plot boxplots with thicker elements (linewidth=3)
- boxprops = dict(linewidth=3, color='black') # Thicker box borders
- whiskerprops = dict(linewidth=3, color='black') # Thicker whiskers
- capprops = dict(linewidth=3, color='black') # Thicker caps
- medianprops = dict(linewidth=3, color='black') # Thicker median line
- bp = plt.boxplot([ELA, Non_ELA],
- labels=['DNS', 'DLS'],
- patch_artist=True,
- widths=0.6,
- boxprops=boxprops,
- whiskerprops=whiskerprops,
- capprops=capprops,
- medianprops=medianprops)
- # Set box fill colors with new color scheme
- colors = ['#5E93CB', '#9A4942'] # DNS and DLS colors '#5E93CB' '#79902D'
- for patch, color in zip(bp['boxes'], colors):
- patch.set_facecolor(color)
- patch.set_alpha(0.7)
- # Plot individual data points with jitter (larger size)
- def plot_jitter(data, x_pos, color, alpha=0.6):
- jitter = np.random.normal(0, 0.05, size=len(data))
- plt.scatter(x_pos + jitter, data, color=color, alpha=alpha, s=250, edgecolor='none')
- plot_jitter(ELA, 1, '#5E93CB')
- plot_jitter(Non_ELA, 2, '#9A4942')
- # Calculate standard errors for error bars
- se_ELA = stats.sem(ELA)
- se_Non_ELA = stats.sem(Non_ELA)
- # Mark means with larger diamond shapes (s=150) and thicker error bars
- mean_ELA = np.mean(ELA)
- mean_Non_ELA = np.mean(Non_ELA)
- # Plot error bars with thicker lines (linewidth=3)
- plt.errorbar([1], [mean_ELA], #yerr=se_ELA,
- fmt='none', ecolor='black', elinewidth=3, capsize=12, capthick=3)
- plt.errorbar([2], [mean_Non_ELA], #yerr=se_Non_ELA,
- fmt='none', ecolor='black', elinewidth=3, capsize=12, capthick=3)
- # 显著增大均值标记的大小到s=300
- plt.scatter(1, mean_ELA, color='white', s=250, edgecolor='black', # 增大到300
- marker='D', zorder=10, linewidth=3, label='Mean') # 同时加粗边框到3
- plt.scatter(2, mean_Non_ELA, color='white', s=250, edgecolor='black',
- marker='D', zorder=10, linewidth=3)
- # Add significance annotation with thicker line
- y_max = max(np.max(ELA), np.max(Non_ELA)) + 0.1
- plt.plot([1, 1, 2, 2], [y_max-0.05, y_max, y_max, y_max-0.05],
- color='black', lw=3) # Thicker significance line
- if p_value < 0.001:
- sig_text = '***'
- elif p_value < 0.01:
- sig_text = '**'
- elif p_value < 0.05:
- sig_text = '*'
- else:
- sig_text = 'n.s.'
- plt.text(1.5, y_max, sig_text,
- ha='center', va='bottom',
- fontsize=48, fontweight='bold')
- # Customize plot with larger fonts
- plt.xticks(fontsize=48, fontweight='bold')
- plt.yticks(fontsize=48, fontweight='bold')
- # Adjust spines (thicker)
- ax = plt.gca()
- ax.spines['top'].set_visible(False)
- ax.spines['right'].set_visible(False)
- ax.spines['bottom'].set_linewidth(3)
- ax.spines['left'].set_linewidth(3)
- ax.spines['bottom'].set_color('black')
- ax.spines['left'].set_color('black')
- plt.tight_layout()
- plt.savefig(output_path + 'ELA_vs_Non_ELA_boxplot_enhanced.png',
- dpi=300, bbox_inches='tight', transparent=True)
- plt.show()
- # Print model summary
- print("Mixed Effects Model Results:")
- print(model.summary())
- print(f"\nGroup difference p-value: {p_value:.4f}")
- # %%
- import numpy as np
- import os
- import matplotlib.pyplot as plt
- import seaborn as sns
- import pandas as pd
- import statsmodels.api as sm
- import statsmodels.formula.api as smf
- from scipy.stats import zscore
- from statsmodels.stats.multitest import multipletests # For p-value correction
- # Set paths
- input_path = 'J:/HCP_analysis/deaf/10_rest_predict_task/'
- output_path = 'J:/HCP_analysis/deaf/10_rest_predict_task/results_lan_DNS/'
- os.makedirs(output_path, exist_ok=True)
- # Load and standardize data
- shap_values_all = np.load(input_path + 'shap_feature_importance.npy') # shape: (91, 4, 10)
- shap_values_all = zscore(shap_values_all, axis=2) # Standardize within each dimension
- # Define group sizes
- n_DNS = 27
- n_Non_DNS = 30
- n_subjects = n_DNS + n_Non_DNS
- n_blocks = 4
- n_dims = 10
- # Prepare DataFrame for mixed model
- data_list = []
- for subj in range(n_subjects):
- group = 'DNS' if subj < n_DNS else 'DLS'
- actual_subj_idx = 34 + subj # Adjust index since DNS group starts at position 34
- for block in range(n_blocks):
- for dim in range(n_dims):
- data_list.append({
- 'subject': f'subj_{actual_subj_idx}',
- 'group': group,
- 'block': block, # Changed to numeric
- 'dimension': dim,
- 'shap_value': shap_values_all[actual_subj_idx, block, dim]
- })
- df = pd.DataFrame(data_list)
- # Ensure group is categorical and set reference level
- df['group'] = pd.Categorical(df['group'], categories=['DLS', 'DNS'])
- df['block'] = pd.Categorical(df['block']) # Make block categorical
- # Initialize storage for results
- lmm_results = []
- # Fit mixed models for each SHAP dimension
- for dim in range(n_dims):
- dim_df = df[df['dimension'] == dim].copy()
- try:
- model = smf.mixedlm(
- "shap_value ~ C(group, Treatment('DLS'))",
- data=dim_df,
- groups=dim_df["subject"],
- re_formula="~1"
- )
- result = model.fit(reml=True)
- coef = result.fe_params["C(group, Treatment('DLS'))[T.DNS]"]
- pval = result.pvalues["C(group, Treatment('DLS'))[T.DNS]"]
- t_stat = result.tvalues["C(group, Treatment('DLS'))[T.DNS]"]
- lmm_results.append({
- 'dimension': dim,
- 'coefficient': coef,
- 't_statistic': t_stat,
- 'p_value': pval,
- 'significant': pval < 0.05,
- 'random_effect_variance': result.cov_re.iloc[0, 0]
- })
- except Exception as e:
- print(f"Failed to fit model for dimension {dim}: {str(e)}")
- lmm_results.append({
- 'dimension': dim,
- 'coefficient': np.nan,
- 't_statistic': np.nan,
- 'p_value': np.nan,
- 'significant': False,
- 'random_effect_variance': np.nan
- })
- # Convert to DataFrame
- results_df = pd.DataFrame(lmm_results)
- # Apply p-value correction (FDR)
- pvals = results_df['p_value'].values
- rejected, pvals_corrected, _, _ = multipletests(pvals, alpha=0.05, method='fdr_bh')
- results_df['p_value_corrected'] = pvals_corrected
- results_df['significant_corrected'] = rejected
- # Save corrected results
- results_df.to_csv(output_path + 'lmm_results_DNS_vs_DLS_corrected.csv', index=False)
- # Visualization with gradient colors and black borders
- plt.figure(figsize=(12, 6.5))
- # Calculate group means (averaged across blocks)
- # 用“被试层面均值”(跨 4 个 block 平均)来计算组均值与SEM,避免SEM过小
- df_subj = df.groupby(['group', 'subject', 'dimension'], as_index=False)['shap_value'].mean()
- group_means = df_subj.groupby(['group', 'dimension'])['shap_value'].mean().unstack()
- group_sems = df_subj.groupby(['group', 'dimension'])['shap_value'].sem().unstack()
- # Create color gradients for each group
- dns_base = np.array([0.3686, 0.5765, 0.7961]) # base blue
- dls_base = np.array([0.6039, 0.2863, 0.2588]) # base red
- dns_gradient = [dns_base * (1 - i*0.08) + np.array([1, 1, 1]) * (i*0.08) for i in range(10)]
- dls_gradient = [dls_base * (1 - i*0.08) + np.array([1, 1, 1]) * (i*0.08) for i in range(10)]
- # ===================== 新增:计算“每个被试在每个维度”的单个点(跨block平均) =====================
- # 这就是你说的 shap_feature_importance.npy 里对应条件的“被试点”
- subj_means = df.groupby(['group', 'subject', 'dimension'])['shap_value'].mean()
- dns_subjects = subj_means.loc['DNS'].index.get_level_values('subject').unique()
- dls_subjects = subj_means.loc['DLS'].index.get_level_values('subject').unique()
- np.random.seed(0) # 仅用于抖动可复现(不想固定可删)
- # =============================================================================================
- # Plot each dimension with its own color from the gradient and black borders
- for dim in range(10):
- # ===================== 新增:叠加“所有被试点”(颜色与条件/维度一致,透明不遮挡误差线) =====================
- # DNS 所有被试
- y_dns_pts = np.array([subj_means.loc[('DNS', s, dim)] for s in dns_subjects])
- x_dns_pts = dim + np.random.uniform(-0.18, -0.06, size=len(y_dns_pts))
- plt.scatter(x_dns_pts, y_dns_pts,
- s=85, color=dns_gradient[dim], alpha=0.88,
- edgecolors='white', zorder=1)
- # DLS 所有被试
- y_dls_pts = np.array([subj_means.loc[('DLS', s, dim)] for s in dls_subjects])
- x_dls_pts = dim + np.random.uniform(0.06, 0.18, size=len(y_dls_pts))
- plt.scatter(x_dls_pts, y_dls_pts,
- s=85, color=dls_gradient[dim], alpha=0.88,
- edgecolors='white', zorder=1)
- # ====================================================================================================
- # DNS plot with black borders
- plt.errorbar(dim, group_means.loc['DNS', dim],
- yerr=group_sems.loc['DNS', dim],
- fmt='o', zorder=5, capsize=6, linewidth=3, markersize=20,
- color=dns_gradient[dim], ecolor='black',
- elinewidth=2,
- markeredgecolor='black', markeredgewidth=2,
- label='DNS' if dim == 0 else "")
- # DLS plot with black borders
- plt.errorbar(dim, group_means.loc['DLS', dim],
- yerr=group_sems.loc['DLS', dim],
- fmt='s', zorder=5, capsize=6, linewidth=3, markersize=20,
- color=dls_gradient[dim], ecolor='black',
- elinewidth=2,
- markeredgecolor='black', markeredgewidth=2,
- label='DLS' if dim == 0 else "")
- # Connect the dots with lines in the gradient colors
- plt.plot(range(10), group_means.loc['DNS'],
- color='#5E93CB', linewidth=3, alpha=1)
- plt.plot(range(10), group_means.loc['DLS'],
- color='#9A4942', linewidth=3, alpha=1)
- # Mark significant differences (corrected p < 0.05)
- for i in range(10):
- if results_df['significant_corrected'].iloc[i]:
- y_pos = max(group_means.loc['DNS', i], group_means.loc['DLS', i]) + 0.03
- plt.scatter(i, y_pos + 0.2, marker='*', color='black', s=600, zorder=10)
- plt.ylabel('Standardized SHAP Value', fontsize=29, fontweight='bold', labelpad=10)
- plt.xticks(range(10), [f'G{i+1}' for i in range(10)], fontsize=30, fontweight='bold')
- plt.yticks(fontsize=30, fontweight='bold')
- # Create custom legend with black borders
- from matplotlib.lines import Line2D
- legend_elements = [
- Line2D([0], [0], marker='o', color='w', label='DNS',
- markerfacecolor='#5E93CB', markersize=25,
- markeredgecolor='black', markeredgewidth=2),
- Line2D([0], [0], marker='s', color='w', label='DLS',
- markerfacecolor='#9A4942', markersize=25,
- markeredgecolor='black', markeredgewidth=2)
- ]
- plt.legend(handles=legend_elements, fontsize=26,
- prop={'weight': 'bold', 'size': 26},
- framealpha=1, loc='upper right')
- # Customize spines
- ax = plt.gca()
- ax.spines['top'].set_visible(False)
- ax.spines['right'].set_visible(False)
- ax.spines['bottom'].set_linewidth(4)
- ax.spines['left'].set_linewidth(4)
- ax.spines['bottom'].set_color('black')
- ax.spines['left'].set_color('black')
- plt.tight_layout()
- plt.savefig(output_path + 'shap_comparison_gradient_DNS_DLS_bordered_corrected.png',
- dpi=300, bbox_inches='tight', transparent=True)
- plt.close()
- print("Analysis complete. Results saved to:", output_path)
- # %%
S05_the_rsFC_gradient_rest_predict_task_activation.ipynb, no license · at the source
Overview
- Faculty of Psychology, Beijing Normal University,Beijing, China
- State Key Laboratory of Cognitive Neuroscience and Learning & IDG/McGovern Institute for Brain Research, Beijing Normal University,Beijing, China
- State Key Laboratory of Cognitive Science and Mental Health, Institute of Psychology, Chinese Academy of Sciences,Beijing, China
- Department of Psychology, University of Chinese Academy of Sciences,Beijing, China
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
Availability: 1 check, the latest on 30 September 2026: the link answers (HTTP 200)
- 30 September 2026: the link answers (HTTP 200)
6 files
- Code/
S01_Calculate_the_restin , Jupyter, 888 lines, 2 matchesg_state_gradient_2group. ipynb - Code/
S02_Calculate_the_rsFC_g , Jupyter, 514 lines, 1 matchradient_2group_classify_ model.ipynb - Code/
S03_stats_the_rsFC_gradi , Jupyter, 1,571 lines, 2 matchesent_2group_model_AD_effe ct.ipynb - Code/
S04_stats_the_rsFC_gradi , Jupyter, 1,886 lines, 2 matchesent_2group_model_ELD_eff ect.ipynb - Code/
S05_the_rsFC_gradient_re , Jupyter, 1,605 lines, 3 matchesst_predict_task_activati on.ipynb - Code/
S06_the_rsFC_gradient_st , Jupyter, 2,689 linesats_allmodels.ipynb
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:
- it points to the authors' code: OSF ebsvz
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://
BibTeX
@article{liu2026multidim
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/
url = {https://
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/
VL - 9
IS - 1
SP - 703
SN - 2399-3642
PB - Nature Publishing Group
DO - 10.1038/
UR - https://
LA - en
ER -
CSL-JSON
{
"id": "10.1038/
"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":
"volume": "9",
"issue": "1",
"page": "703",
"DOI": "10.1038/
"PMID": "41912615",
"PMCID": "PMC13199478",
"ISSN": "2399-3642",
"publisher": "Nature Publishing Group",
"URL": "https://
"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 brainJournal: 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 brainJournal: 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: eLifeIn 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: eLifeIn 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 communicationsIn 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 communicationsIn 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 communicationsIn 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.
Claim this paper
Correct its record
Say what each link of this record is, remove the ones that are not the paper's, add the ones that are missing. The correction becomes a new version of the record, in its Versions section.
Validate its tracing map
You validate the map as this page shows it: 1 repository of the authors' code, each at its verified commit and with its license, 6 scripts, and 10 matches between paragraphs and code (see the Code and Map sections). It then receives a DOI on Zenodo, with you (your ORCID iD) and OSCR as its creators; the code itself is not deposited.
The map's fingerprint: sha256:836c4160330d4943…
Add the badge to the code's README
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 -->
[](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:endHTML
<!-- 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.
