Distinct Physiological Mechanisms Drive Grey Matter Plasticity in Complex Versus Simple Sequence Learning.
The 7 matches
- [1] § Results › GMV ROI ~ Behaviour Correlation Analysis ↔ ROI_Bx_T1_correlation.ipynb, lines 744–783 · score 0.66 · GMV change scores, Block12 Block3, d5 d2, LOSO, CI, Pearsons
- [2] § Statistical Analyses › ROI Analyses ↔ ROI_Bx_T1_correlation.ipynb, lines 744–783 · score 0.65 · Block12 Block3, change scores, GMV change, Pearson, correlation, behavioural
- [3] § Statistical Analyses › ROI Analyses ↔ ROI_Bx_T1_correlation.ipynb, lines 457–567 · score 0.60 · GM mask, GM ROI, WM, TFCE, correlation, clusters
- [4] § Methods › Voxel‐Based Morphometry ↔ longitudinal_segmentation_all40subjects.m, lines 14–49 · score 0.58 · shooting, template, CAT12, modulated, SPM12, segmentation
- [5] § Statistical Analyses › GM Volume Change During MSL Across Learning Stages ↔ ROI_Bx_T1_correlation.ipynb, lines 457–567 · score 0.57 · GM voxels, modulated, threshold, mask, tissue, TFCE
- [6] § Results › T1 ROI ~ Behaviour Relationship ↔ ROI_Bx_T1_correlation.ipynb, lines 605–699 · score 0.55 · SYN changes, left SPC, modalities, CI, VBM, correlation
- [7] § Statistical Analyses › GM Volume Change During MSL Across Learning Stages ↔ flexible_factorial_design_withbinmask.m, lines 421–507 · score 0.53 · flexible factorial design, threshold, mask, voxels, d1, d2
Paper
Loaded from Europe PMC by your browser, not stored by OSCR: doi.org · Europe PMC
The paper is loaded when this pane is shown.
The authors' code
Jupyter notebook · 875 lines · 37 KB · no license · 5 matches
- # %%
- import os
- from os.path import join
- from glob import glob
- import csv
- import nibabel as nb
- import numpy as np
- import nilearn
- import pandas as pd
- from nilearn.image import threshold_img
- from nilearn import image, plotting
- from nilearn.maskers import NiftiMasker
- from scipy.ndimage import binary_dilation
- from scipy import stats
- from scipy.stats import pearsonr,chi2
- import scipy.stats.mstats as mstats
- import statsmodels.formula.api as smf
- from statsmodels.stats.multitest import multipletests
- import statsmodels.api as sm
- from statsmodels.stats.anova import AnovaRM
- from statsmodels.stats.multitest import multipletests
- from matplotlib import pyplot as plt
- import seaborn as sns
- import warnings
- warnings.filterwarnings('ignore')
- from sklearn.model_selection import LeaveOneOut
- # %%
- ##### Fisher's z test for T1 and Bx between LRN adn SMP correlations.#####
- ##### LRN n=19 and SMP n= 20
- z1 = 0.5 * np.log((1 + -0.65) / (1 - -0.65))
- z2 = 0.5 * np.log((1 + 0.18) / (1 - 0.18))
- SE = np.sqrt(1/(19-3) + 1/(20-3))
- Z = (z1 - z2) / SE
- p = 2 * (1 - stats.norm.cdf(abs(Z)))
- print(f"Z = {Z:.3f}, p = {p:.4f}")
- # %%
- #### Effect sizes for Table 2 of ms ######
- data1 = {
- 'LRN_mean': [0.0622, 0.0470, 0.0639, 0.1181, 0.0690],
- 'LRN_sem': [0.0210, 0.0375, 0.0244, 0.0631, 0.0455],
- 'SMP_mean': [-0.0558, -0.1071, -0.0819, -0.0890, -0.1097],
- 'SMP_sem': [0.0233, 0.0348, 0.0195, 0.0312, 0.0269]
- }
- df1 = pd.DataFrame(data1)
- n_lrn = 19
- n_smp = 20
- # Convert SEM to SD
- df1['LRN_sd'] = df1['LRN_sem'] * np.sqrt(n_lrn)
- df1['SMP_sd'] = df1['SMP_sem'] * np.sqrt(n_smp)
- # Weighted pooled SD (correct for unequal n)
- df1['SD_pooled'] = np.sqrt(
- (((n_lrn - 1) * df1['LRN_sd']**2) + ((n_smp - 1) * df1['SMP_sd']**2)) /
- (n_lrn + n_smp - 2)
- )
- # Mean difference
- df1['Mean_diff'] = df1['LRN_mean'] - df1['SMP_mean']
- # Cohen's d
- df1['Cohens_d'] = df1['Mean_diff'] / df1['SD_pooled']
- # Display
- print(df1[['LRN_mean', 'SMP_mean', 'Mean_diff', 'Cohens_d']].round(2))
- # %%
- df = pd.read_csv('/data/neuralabc/paujhe/mMPI/Bx/SYN_Scores_by_block_Jhelum.csv')
- df = df[df['PID'] != 'P11']
- n_lrn = df[df['Group'] == 'LRN']['PID'].nunique()
- n_smp = df[df['Group'] == 'SMP']['PID'].nunique()
- day_columns = ['Day1', 'Day2', 'Day3', 'Day4', 'Day5', 'Day17']
- lrn_averages = []
- smp_averages = []
- sem_LRN =[]
- sem_SMP =[]
- for day in day_columns:
- lrn_avg = df[df['Group'] == 'LRN'][day].mean()
- lrn_checkstd = df[df['Group'] == 'LRN'][day].std()
- lrn_checksem = lrn_checkstd/np.sqrt(n_lrn-1)
- smp_avg = df[df['Group'] == 'SMP'][day].mean()
- smp_checkstd = df[df['Group'] == 'SMP'][day].std()
- smp_checksem = smp_checkstd/np.sqrt(n_smp-1)
- lrn_averages.append(lrn_avg)
- smp_averages.append(smp_avg)
- sem_LRN.append(lrn_checksem)
- sem_SMP.append(smp_checksem)
- plt.figure(figsize=(10,7))
- day_split_index = day_columns.index('Day5')
- plt.errorbar(day_columns[:day_split_index + 1],
- lrn_averages[:day_split_index + 1],
- yerr=sem_LRN[:day_split_index + 1],
- capsize=3, marker='o', label='LRN', linewidth=2, color='#004586')
- plt.errorbar(day_columns[:day_split_index + 1],
- smp_averages[:day_split_index + 1],
- yerr=sem_SMP[:day_split_index + 1],
- capsize=3, marker='s', label='SMP', linewidth=2, color='#FF420E')
- plt.errorbar(day_columns[day_split_index:],
- lrn_averages[day_split_index:],
- yerr=sem_LRN[day_split_index:],
- capsize=3, marker='o', linestyle='dotted', linewidth=2, color='#004586')
- plt.errorbar(day_columns[day_split_index:],
- smp_averages[day_split_index:],
- yerr=sem_SMP[day_split_index:],
- capsize=3, marker='s', linestyle='dotted', linewidth=2, color='#FF420E')
- plt.legend(fontsize=14)
- plt.xlabel('Day', fontsize=18)
- plt.ylabel('SYN Score (in ms)', fontsize=18)
- plt.ylim(0,230)
- plt.yticks(np.arange(0, 201, 50), fontsize=16)
- plt.xticks(fontsize=16)
- plt.tight_layout()
- #plt.savefig('bx_adjusted_current.png', dpi=600)
- plt.show()
- # %%
- # df is already loaded with dataset for SYN block by block, excluding the outlier subject of LRN group P11
- data_long = df.melt(
- id_vars=['PID', 'Group'],
- value_vars=day_columns,
- var_name='Day',
- value_name='SYN')
- data_long['SYN'] = pd.to_numeric(data_long['SYN'], errors='coerce')
- data_long = data_long.dropna(subset=['SYN'])
- data_long['Group'] = data_long['Group'].astype('category')
- data_long['Day'] = pd.Categorical(data_long['Day'],
- categories=['Day1','Day2','Day3','Day4','Day5','Day17'],
- ordered=True)
- data_long['PID'] = data_long['PID'].astype('category')
- print(f"\nSample sizes:")
- print(f" LRN: {data_long[data_long['Group']=='LRN']['PID'].nunique()} participants")
- print(f" SMP: {data_long[data_long['Group']=='SMP']['PID'].nunique()} participants")
- print(f" Total: {data_long['PID'].nunique()} participants")
- print(f" Total rows: {len(data_long)}\n")
- lrn = data_long[data_long['Group'] == 'LRN']
- pairs = [('Day1','Day2'), ('Day2','Day3'), ('Day3','Day4'), ('Day4','Day5'), ('Day5','Day17')]
- pvals, tvals, gvals = [], [], []
- def hedges_g(x, y):
- n = len(x)
- d = (np.mean(x) - np.mean(y)) / np.std(np.concatenate([x, y]), ddof=1)
- return d * (1 - (3 / (4 * n - 9)))
- for a, b in pairs:
- vals_a = lrn[lrn['Day'] == a]['SYN'].values
- vals_b = lrn[lrn['Day'] == b]['SYN'].values
- t, p = stats.ttest_rel(vals_a, vals_b)
- g = hedges_g(vals_a, vals_b)
- tvals.append(t)
- pvals.append(p)
- gvals.append(g)
- rej, p_corr, _, _ = multipletests(pvals, alpha=0.05, method='bonferroni')
- for i, (a, b) in enumerate(pairs):
- sig = '***' if p_corr[i] < 0.001 else '**' if p_corr[i] < 0.01 else '*' if p_corr[i] < 0.05 else 'n.s.'
- print(f"{a} vs {b}: t={tvals[i]:6.2f}, p_raw={pvals[i]:.4f}, p_corr={p_corr[i]:.4f} ({sig}), Hedges' g={gvals[i]:5.2f}")
- # %%
- # COMPREHENSIVE DESCRIPTIVE STATISTICS
- # Calculate statistics for each Group × Day combination
- # Filter the data_long to exclude the 'LRN SMP task' group
- data_long_filtered = data_long[data_long['Group'].isin(['LRN', 'SMP'])].copy()
- data_long_filtered['Group'] = data_long_filtered['Group'].cat.remove_unused_categories()
- stats_summary = []
- for group in ['LRN', 'SMP']:
- for day in ['Day1', 'Day2', 'Day3', 'Day4', 'Day5', 'Day17']:
- subset = data_long_filtered[(data_long_filtered['Group'] == group) &
- (data_long_filtered['Day'] == day)]['SYN']
- if len(subset) > 0:
- stats_dict = {
- 'Group': group,
- 'Day': day,
- 'N': len(subset),
- 'Mean': subset.mean(),
- 'SD': subset.std(),
- 'SEM': subset.sem(),
- 'Median': subset.median(),
- 'Q1': subset.quantile(0.25),
- 'Q3': subset.quantile(0.75),
- 'IQR': subset.quantile(0.75) - subset.quantile(0.25),
- 'Min': subset.min(),
- 'Max': subset.max(),
- 'Range': subset.max() - subset.min(),
- 'Skewness': stats.skew(subset),
- 'Kurtosis': stats.kurtosis(subset)
- }
- stats_summary.append(stats_dict)
- stats_df = pd.DataFrame(stats_summary)
- print("\n CENTRAL TENDENCY AND VARIABILITY")
- for group in ['LRN', 'SMP']:
- print(f"\n{group} GROUP:")
- group_data = stats_df[stats_df['Group'] == group]
- print(f"{'Day':<8} {'N':<4} {'Mean±SD':<20} {'Median (IQR)':<25} {'Range':<15}")
- print("-" * 72)
- for _, row in group_data.iterrows():
- mean_sd = f"{row['Mean']:.2f} ± {row['SD']:.2f}"
- median_iqr = f"{row['Median']:.2f} ({row['Q1']:.2f}-{row['Q3']:.2f})"
- range_str = f"{row['Min']:.2f}-{row['Max']:.2f}"
- print(f"{row['Day']:<8} {int(row['N']):<4} {mean_sd:<20} {median_iqr:<25} {range_str:<15}")
- print("\n DISTRIBUTION CHARACTERISTICS")
- for group in ['LRN', 'SMP']:
- print(f"\n{group} GROUP:")
- group_data = stats_df[stats_df['Group'] == group]
- print(f"{'Day':<8} {'Skewness':<12} {'Kurtosis':<12} {'Distribution Shape':<30}")
- print("-" * 62)
- for _, row in group_data.iterrows():
- if abs(row['Skewness']) < 0.5:
- skew_interp = "Approximately symmetric"
- elif row['Skewness'] > 0:
- skew_interp = "Right-skewed (positive)"
- else:
- skew_interp = "Left-skewed (negative)"
- if abs(row['Kurtosis']) < 0.5:
- kurt_interp = "Mesokurtic (normal)"
- elif row['Kurtosis'] > 0:
- kurt_interp = "Leptokurtic (heavy-tailed)"
- else:
- kurt_interp = "Platykurtic (light-tailed)"
- distribution = f"{skew_interp}, {kurt_interp}"
- print(f"{row['Day']:<8} {row['Skewness']:>6.2f} {row['Kurtosis']:>6.2f} {distribution}")
- print("\n OVERALL SUMMARY ACROSS ALL DAYS")
- for group in ['LRN', 'SMP']:
- group_all = data_long_filtered[data_long_filtered['Group'] == group]['SYN']
- print(f"\n{group} GROUP (N={len(group_all)} observations):")
- print(f" Overall Mean ± SD: {group_all.mean():.2f} ± {group_all.std():.2f} ms")
- print(f" Overall Median: {group_all.median():.2f} ms")
- print(f" Overall Range: {group_all.min():.2f} - {group_all.max():.2f} ms")
- print(f" Interquartile Range: {group_all.quantile(0.25):.2f} - {group_all.quantile(0.75):.2f} ms")
- palette = {
- 'LRN': '#004586',
- 'SMP': '#FF420E'
- }
- sns.set(style='whitegrid', font_scale=1.3)
- plt.figure(figsize=(14, 7))
- sns.violinplot(data=data_long_filtered, x='Day', y='SYN', hue='Group', palette=palette,
- inner=None, cut=0, alpha=0.5)
- sns.boxplot(data=data_long_filtered, x='Day', y='SYN', hue='Group', palette=palette,
- showcaps=False, boxprops={'facecolor':'none', 'zorder':2},
- showfliers=False, whiskerprops={'linewidth':0})
- sns.stripplot(data=data_long_filtered, x='Day', y='SYN', hue='Group',
- dodge=True, jitter=True, alpha=0.5, size=5, color='k')
- plt.title('Raincloud Plot of SYN Scores - LRN vs SMP', fontsize=16)
- plt.xlabel('Training Day', fontsize=16)
- plt.ylabel('SYN (ms)', fontsize=16)
- handles, labels = plt.gca().get_legend_handles_labels()
- plt.legend(handles[:2], labels[:2], title='Group', bbox_to_anchor=(1.05, 1), loc='upper left')
- plt.tight_layout()
- #plt.savefig('raincloud_graph_allsubs_current.png', dpi=600, bbox_inches='tight')
- plt.show()
- # %% [markdown]
- # # DF FOR VBM CLUSTERS
- # %%
- #cluster D- slow learning L SPC
- dfvbm_LRN_D = pd.read_csv('/data/neuralabc/paujhe/mMPI/Bx/clusterD_VBM.csv',usecols=['LRN_d1','LRN_d2','LRN_d5', 'LRN_d6'])
- dfvbm_SMP_D = pd.read_csv('/data/neuralabc/paujhe/mMPI/Bx/clusterD_VBM.csv',usecols=['SMP_d1','SMP_d2','SMP_d5','SMP_d6'])
- synscores_LRN = pd.read_csv('/data/neuralabc/paujhe/mMPI/Bx/syn_score_25feb2023.csv',usecols=['Block1','Block3','Block12'])
- synB12minusB3 = pd.read_csv('/data/neuralabc/paujhe/mMPI/Bx/syn_score_25feb2023.csv',usecols=['B12minusB3']) #d2 vs d5 slow learning -> Cluster D LEFT SPC
- synB3minusB1 = pd.read_csv('/data/neuralabc/paujhe/mMPI/Bx/syn_score_25feb2023.csv',usecols=['B3minusB1']) #d2 vs d5 slow learning -> Cluster D LEFT SPC
- synscores_SMP = pd.read_csv('/data/neuralabc/paujhe/mMPI/Bx/SYN_BLOCKS_SMP.csv',usecols=['Block 1','Block 3','Block 12','B12minusB3'])
- # %%
- # Change in vbm for learning stages
- dfvbm_LRN_D['d5minusd2'] = dfvbm_LRN_D['LRN_d5'] - dfvbm_LRN_D['LRN_d2'] #cluster D- slow learning
- new_dfvbm_LRN_D = dfvbm_LRN_D['d5minusd2'] #cluster D- slow learning
- var_vec_d = new_dfvbm_LRN_D.copy()
- var_vec_d = var_vec_d[~np.isnan(var_vec_d)]
- pearsonr( var_vec_d, synB12minusB3['B12minusB3'])
- # %%
- # SMP group GMV vs SYN
- dfvbm_SMP_D['d5minusd2'] = dfvbm_SMP_D['SMP_d5'] - dfvbm_SMP_D['SMP_d2']
- new_dfvbm_SMP_D = dfvbm_SMP_D['d5minusd2'] #cluster D- slow learning
- var_vec_d_SMP = new_dfvbm_SMP_D.copy()
- var_vec_d_SMP = var_vec_d_SMP[~np.isnan(var_vec_d_SMP)]
- pearsonr( var_vec_d_SMP, synscores_SMP['B12minusB3'])
- # %%
- slope2, intercept2, r2, p2, stderr2 = mstats.linregress(var_vec_d, synB12minusB3['B12minusB3'])
- line2 = f'Regression line: y={intercept2:.2f}+{slope2:.2f}x'
- r2_value = r2
- p2_value = p2
- # Calculate CI
- def correlation_ci(r, n, confidence=0.95):
- """Calculate confidence interval for correlation coefficient"""
- from scipy.stats import norm
- z = np.arctanh(r)
- se = 1 / np.sqrt(n - 3)
- z_crit = norm.ppf((1 + confidence) / 2)
- ci_lower_z = z - z_crit * se
- ci_upper_z = z + z_crit * se
- ci_lower = np.tanh(ci_lower_z)
- ci_upper = np.tanh(ci_upper_z)
- return ci_lower, ci_upper
- n_samples = len(var_vec_d)
- ci_lower, ci_upper = correlation_ci(r2_value, n_samples)
- print(f"r = {r2_value:.2f}, 95% CI [{ci_lower:.2f}, {ci_upper:.2f}], p = {p2_value:.3f}, n = {n_samples}")
- line2 = f'Regression line: y={intercept2:.2f}+{slope2:.2f}x'
- r2 = f'r = {r2_value:.2f}'
- p2 = f'p = {p2_value:.2f}'
- # %%
- x_vals2 = np.array([var_vec_d.min(), var_vec_d.max()])
- y_vals2 = intercept2 + slope2 * x_vals2
- angle2 = np.degrees(np.arctan2(y_vals2[1] - y_vals2[0], x_vals2[1] - x_vals2[0]))
- x_text2 = x_vals2[0] + 0.054 # adjust as needed
- y_text2 = (intercept2+ 8) + slope2 * x_text2
- x_text3 = x_vals2[0] + 0.055 # adjust as needed
- y_text3 = (intercept2+ -15) + slope2 * x_text3
- fig, ax = plt.subplots()
- ax.plot(var_vec_d, synB12minusB3['B12minusB3'], linewidth=0, marker='o', label='Participants')
- ax.plot(var_vec_d, intercept2 + slope2 * var_vec_d, label=line2)
- ax.set_xlabel('Change in mean GM (d5-d2)',fontsize=18)
- ax.set_ylabel('SYN score (B12-B3)',fontsize=18)
- ax.legend(loc= 2, facecolor='white')
- plt.title('Left Superior Parietal Cortex', fontsize=18)
- plt.text(x_text2, y_text2, r2, fontsize=12, rotation=angle2, rotation_mode='anchor', transform_rotates_text=True)
- plt.text(x_text3, y_text3, p2, fontsize=12, rotation=angle2, rotation_mode='anchor', transform_rotates_text=True)
- ax.yaxis.grid(True) # Enables horizontal grid lines
- ax.xaxis.grid(False)
- plt.ylim(-150,100)
- plt.xticks(fontsize=14)
- plt.yticks(fontsize=16)
- plt.tight_layout()
- #plt.savefig('L_SPC_slow_cluster_D.png', dpi=600)
- plt.show()
- # %% [markdown]
- # # T1 mean value extraction from all subjects and each day
- # %%
- ## load the subject ids here ##
- LRN = ['P05','P06','P07','P08','P09', 'P10', 'P12', 'P14', 'P16', 'P17','P18', 'P20', 'P21', 'P26', 'P28','P31', 'P36', 'P37', 'P38']
- SMP = ['P13','P15','P22','P23','P24', 'P25', 'P27', 'P30', 'P32', 'P33', 'P34','P35', 'P39', 'P40', 'P41', 'P42','P43', 'P44', 'P45', 'P46']
- # %%
- #Gather the participants file names for GM and WM d1/d2/d5 in LRN group
- Pname_LRN_GM_d1 = sorted(list(set(glob("/data/neuralabc/paujhe/mMPI/data/Learning/P*/d1/mri/mwp1r*.nii"))-set(glob("/data/neuralabc/paujhe/mMPI/data/Learning/P11/d1/mri/mwp1r*.nii"))))
- Pname_LRN_GM_d2 = sorted(list(set(glob("/data/neuralabc/paujhe/mMPI/data/Learning/P*/d2/mri/mwp1r*.nii"))-set(glob("/data/neuralabc/paujhe/mMPI/data/Learning/P11/d2/mri/mwp1r*.nii"))))
- Pname_LRN_GM_d5 = sorted(list(set(glob("/data/neuralabc/paujhe/mMPI/data/Learning/P*/d5/mri/mwp1r*.nii"))-set(glob("/data/neuralabc/paujhe/mMPI/data/Learning/P11/d5/mri/mwp1r*.nii"))))
- Pname_LRN_WM_d1 = sorted(list(set(glob("/data/neuralabc/paujhe/mMPI/data/Learning/P*/d1/mri/mwp2r*.nii"))-set(glob("/data/neuralabc/paujhe/mMPI/data/Learning/P11/d1/mri/mwp2r*.nii"))))
- Pname_LRN_WM_d2 = sorted(list(set(glob("/data/neuralabc/paujhe/mMPI/data/Learning/P*/d2/mri/mwp2r*.nii"))-set(glob("/data/neuralabc/paujhe/mMPI/data/Learning/P11/d2/mri/mwp2r*.nii"))))
- Pname_LRN_WM_d5 = sorted(list(set(glob("/data/neuralabc/paujhe/mMPI/data/Learning/P*/d5/mri/mwp2r*.nii"))-set(glob("/data/neuralabc/paujhe/mMPI/data/Learning/P11/d5/mri/mwp2r*.nii"))))
- #Gather the participants file names for GM and WM d1/d2/d5 in SMP group
- Pname_SMP_GM_d1 = sorted(glob("/data/neuralabc/paujhe/mMPI/data/Control/P*/d1/mri/mwp1r*.nii"))
- Pname_SMP_GM_d2 = sorted(glob("/data/neuralabc/paujhe/mMPI/data/Control/P*/d2/mri/mwp1r*.nii"))
- Pname_SMP_GM_d5 = sorted(glob("/data/neuralabc/paujhe/mMPI/data/Control/P*/d5/mri/mwp1r*.nii"))
- Pname_SMP_WM_d1 = sorted(glob("/data/neuralabc/paujhe/mMPI/data/Control/P*/d1/mri/mwp2r*.nii"))
- Pname_SMP_WM_d2 = sorted(glob("/data/neuralabc/paujhe/mMPI/data/Control/P*/d2/mri/mwp2r*.nii"))
- Pname_SMP_WM_d5 = sorted(glob("/data/neuralabc/paujhe/mMPI/data/Control/P*/d5/mri/mwp2r*.nii"))
- # %%
- #Gather the participants file names for FA/MD d1/d2/d5 in LRN group
- files1 = []
- files2 = []
- files3 = []
- files4 = []
- files5 = []
- files6 = []
- for participant in LRN:
- files1.extend(glob(f"/data/neuralabc/treste/mMPI_DWI/processing/SPM_Analyses/All_maps_MNI/FA/{participant}_d1_*_FA.nii"))
- files2.extend(glob(f"/data/neuralabc/treste/mMPI_DWI/processing/SPM_Analyses/All_maps_MNI/FA/{participant}_d2_*_FA.nii"))
- files3.extend(glob(f"/data/neuralabc/treste/mMPI_DWI/processing/SPM_Analyses/All_maps_MNI/FA/{participant}_d5_*_FA.nii"))
- files4.extend(glob(f"/data/neuralabc/treste/mMPI_DWI/processing/SPM_Analyses/All_maps_MNI/MD/{participant}_d1_*_MD.nii"))
- files5.extend(glob(f"/data/neuralabc/treste/mMPI_DWI/processing/SPM_Analyses/All_maps_MNI/MD/{participant}_d2_*_MD.nii"))
- files6.extend(glob(f"/data/neuralabc/treste/mMPI_DWI/processing/SPM_Analyses/All_maps_MNI/MD/{participant}_d5_*_MD.nii"))
- Pname_LRN_FA_d1 = sorted(files1)
- Pname_LRN_FA_d2 = sorted(files2)
- Pname_LRN_FA_d5 = sorted(files3)
- Pname_LRN_MD_d1 = sorted(files4)
- Pname_LRN_MD_d2 = sorted(files5)
- Pname_LRN_MD_d5 = sorted(files6)
- # %%
- #Gather the participants file names for FA/MD d1/d2/d5 in SMP group
- files1 = []
- files2 = []
- files3 = []
- files4 = []
- files5 = []
- files6 = []
- for participant in SMP:
- files1.extend(glob(f"/data/neuralabc/treste/mMPI_DWI/processing/SPM_Analyses/All_maps_MNI/FA/{participant}_d1_*_FA.nii"))
- files2.extend(glob(f"/data/neuralabc/treste/mMPI_DWI/processing/SPM_Analyses/All_maps_MNI/FA/{participant}_d2_*_FA.nii"))
- files3.extend(glob(f"/data/neuralabc/treste/mMPI_DWI/processing/SPM_Analyses/All_maps_MNI/FA/{participant}_d5_*_FA.nii"))
- files4.extend(glob(f"/data/neuralabc/treste/mMPI_DWI/processing/SPM_Analyses/All_maps_MNI/MD/{participant}_d1_*_MD.nii"))
- files5.extend(glob(f"/data/neuralabc/treste/mMPI_DWI/processing/SPM_Analyses/All_maps_MNI/MD/{participant}_d2_*_MD.nii"))
- files6.extend(glob(f"/data/neuralabc/treste/mMPI_DWI/processing/SPM_Analyses/All_maps_MNI/MD/{participant}_d5_*_MD.nii"))
- Pname_SMP_FA_d1 = sorted(files1)
- Pname_SMP_FA_d2 = sorted(files2)
- Pname_SMP_FA_d5 = sorted(files3)
- Pname_SMP_MD_d1 = sorted(files4)
- Pname_SMP_MD_d2 = sorted(files5)
- Pname_SMP_MD_d5 = sorted(files6)
- # %%
- #Gather the participants file names for qT1map d1/d2/d5 in LRN group
- Pname_LRN_T1_d1 = sorted(list(set(glob("/data/neuralabc/giachi/mMPI/processing/T1m/brain/GR1_*_d1_*.nii"))-set(glob("/data/neuralabc/giachi/mMPI/processing/T1m/brain/GR1_P11_d1_*.nii"))))
- Pname_LRN_T1_d2 = sorted(list(set(glob("/data/neuralabc/giachi/mMPI/processing/T1m/brain/GR1_*_d2_*.nii"))-set(glob("/data/neuralabc/giachi/mMPI/processing/T1m/brain/GR1_P11_d2_*.nii"))))
- Pname_LRN_T1_d5 = sorted(list(set(glob("/data/neuralabc/giachi/mMPI/processing/T1m/brain/GR1_*_d5_*.nii"))-set(glob("/data/neuralabc/giachi/mMPI/processing/T1m/brain/GR1_P11_d5_*.nii"))))
- #Gather the participants file names for qT1map d1/d2/d5 in SMP group
- #Gather the participants file names for qT1map d1/d2/d5 in LRN group
- Pname_SMP_T1_d1 = sorted(glob("/data/neuralabc/giachi/mMPI/processing/T1m/brain/GR2_*_d1_*.nii"))
- Pname_SMP_T1_d2 = sorted(glob("/data/neuralabc/giachi/mMPI/processing/T1m/brain/GR2_*_d2_*.nii"))
- Pname_SMP_T1_d5 = sorted(glob("/data/neuralabc/giachi/mMPI/processing/T1m/brain/GR2_*_d5_*.nii"))
- # %%
- def metric_extract_ROI_gm_wm_gmwm_cut(metric_f, original_ROI_f, gm_seg_f, wm_seg_f, tfce_sig_results,tfce_cut=1.3,
- orig_ROI_dil_iterations=3,ext_WM_dil_iterations=1, cut=0,verbosity=0,working_dir='./',
- return_testing_images=False):
- '''
- ext_WM_dil_iterations should likely stay between 1 and 2, CHECK YOUR OUTPUT!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! <---------------------------!!!!
- Both dil_iterations must be >0
- ext_WM_dil_iterations will remove voxels from gm_wm_interface if grows too large (as we are not using a distance based approach)
- '''
- # the input GM mask is actually a modulated VBM, so we take it at >0 to form a binary GM mask, and use this to then define WM
- import subprocess
- from os.path import join, basename
- #convert all masks to the same space as the metric, store in working_dir
- tmp_ROI_fname = join(working_dir,'XXX_tmp_ROI.nii.gz')
- cmd = ['mrgrid',original_ROI_f, 'regrid','-template',metric_f,'-interp','nearest',tmp_ROI_fname,'-force']
- subprocess.run(cmd)
- tmp_gm_fname = join(working_dir,'XXX_tmp_gm.nii.gz')
- cmd = ['mrgrid',gm_seg_f, 'regrid','-template',metric_f,'-interp','nearest',tmp_gm_fname,'-force']
- subprocess.run(cmd)
- tmp_wm_fname = join(working_dir,'XXX_tmp_wm.nii.gz')
- cmd = ['mrgrid',wm_seg_f, 'regrid','-template',metric_f,'-interp','nearest',tmp_wm_fname,'-force']
- subprocess.run(cmd)
- tmp_tfce_fname = join(working_dir,'XXX_tmp_tfce.nii.gz')
- cmd = ['mrgrid',tfce_sig_results, 'regrid','-template',metric_f,'-interp','nearest',tmp_tfce_fname,'-force']
- subprocess.run(cmd)
- # load masks and ROI
- ROI_img = nb.load(tmp_ROI_fname)
- ROI = ROI_img.get_fdata().astype(bool)
- ROI_dil = binary_dilation(ROI,iterations=orig_ROI_dil_iterations) #iteration is what we include when calling the function
- #tfce sig results, convert to mask
- tfce_mask = nb.load(tmp_tfce_fname).get_fdata()>tfce_cut #tfce_cut is fixed at 1.3 to get p<0.05
- # load metric data
- metric_d = nb.load(metric_f).get_fdata()
- gm = nb.load(tmp_gm_fname).get_fdata()
- gm = gm>cut # taking all the values in the gm which are above cut, eg.cut here is 0.
- gm_ROI = (gm)*ROI_dil*tfce_mask #these are the voxels in sig GM
- gm_ROI_dil = binary_dilation((gm_ROI),iterations=1)
- # gm_dil = binary_dilation((gm*ROI_dil),iterations=1) #this dilation count is different to the ROI dilation, only used for gm_wm_int and wm
- wm = nb.load(tmp_wm_fname).get_fdata()
- wm = wm>0 #this is very liberal if using vbm outputs to be sure everything is captured.
- # wm = binary_dilation((wm*ROI_dil),iterations=1) #JP
- # gm_wm_int = gm_dil*np.logical_not(gm) * np.logical_not(wm) #JP
- gm_wm_int = gm_ROI_dil * np.logical_not(gm_ROI) * wm
- wm = wm * np.logical_not(gm_wm_int)*np.logical_not(gm) #refine WM to remove interface
- gm_wm_ROI = gm_wm_int # this is the interface, NOT masked by tfce region
- # gm_wm_ROI = gm_wm_int*ROI_dil*tfce_mask #interface mask within tfce region
- # wm_ROI_tfce = (wm)*tfce_mask*np.logical_not(gm_wm_ROI) #mask by tfce, likely to have very few voxels (maybe none)
- wm_ROI_ext = (wm)*binary_dilation((gm_wm_ROI),iterations=ext_WM_dil_iterations)*np.logical_not(gm_wm_ROI) #wm external to the GM, no matter if it is in the tfce or not
- gm_wm_ROI = gm_wm_ROI * (binary_dilation(wm_ROI_ext,iterations=1)*np.logical_not(wm_ROI_ext)) #refine based on external WM to remove any potential GM voxels b/c of tissue thresholding issues
- ## WM_ROI_ext extraction is based on double dilated gm_ROI
- ROI_dil_subset = ROI_dil*tfce_mask #this is just extracting ROI_dil within the tfce significant cluster
- # gwm_ROI = (((gm>0)*(~(gm_ROI)))*((wm>0)*(~(wm_ROI))))*ROI_dil #THIS INTERFACE IS NOT CORRECT, can include other regions as well
- if verbosity>0:
- print(ROI_dil.sum())
- print('number vox above cutoff in ROI for gm and wm')
- print(np.sum(gm[ROI_dil]))
- print(np.sum(wm[ROI_dil]))
- print(np.sum(gm_wm_int[ROI_dil]))
- print('after masking by sig result')
- print(f'gm:\t{gm_ROI.sum()}')
- print(f'wm_ext:\t{wm_ROI_ext.sum()}')
- # print(f'wm_tfce:\t{wm_ROI_tfce.sum()}')
- print(f'gm_wm:\t{gm_wm_ROI.sum()}')
- # print(gwm_ROI.sum())
- gm_cnt = (gm_ROI.sum())
- # wm_cnt = (wm_ROI_tfce.sum())
- wm_ext_cnt = (wm_ROI_ext.sum())
- gm_wm_cnt = (gm_wm_ROI.sum())
- #do they share the same vox?
- #this can never happen in this implementation, as we explicitly remove GM from WM
- if ((gm_ROI*wm_ROI_ext).sum() > 0):
- print("There is overlap between WM and GM, this should not happen!!!!!")
- return None
- elif ((wm_ROI_ext*gm_wm_ROI).sum() > 0) or ((gm_ROI*gm_wm_ROI).sum() > 0):
- print("There is overlap between WM/GM interface and WM and/or GM, this should not happen!!!!!")
- return None
- print(tmp_ROI_fname)
- img_gm = nb.Nifti1Image(gm_ROI,affine=ROI_img.affine,header=ROI_img.header)
- # img_wm = nb.Nifti1Image(wm_ROI_tfce,affine=ROI_img.affine,header=ROI_img.header) #thresholded by tfce sig result
- img_wm_ext = nb.Nifti1Image(wm_ROI_ext,affine=ROI_img.affine,header=ROI_img.header) #defined only in WM, not thresholded by tfce sig result
- img_gmwm = nb.Nifti1Image(gm_wm_ROI,affine=ROI_img.affine,header=ROI_img.header)
- if return_testing_images:
- return img_gm,img_wm_ext, img_gmwm
- else:
- return {'ROI_dil_cnt':ROI_dil_subset.sum(), 'ROI_dil_mean':np.mean(metric_d[ROI_dil_subset]),
- 'gm_cnt':gm_cnt, 'gm_mean':np.mean(metric_d[gm_ROI]),
- 'wm_ext_cnt':wm_ext_cnt, 'wm_ext_mean':np.mean(metric_d[wm_ROI_ext]),
- 'gm_wm_interface_cnt':gm_wm_cnt, 'gm_wm_interface_mean':np.mean(metric_d[gm_wm_ROI])}
- # %%
- original_ROI_f = '/data/neuralabc/paujhe/mMPI/results/4mm_flexi_ownbinmask_09062022/updatedroi_0006_D.nii.gz'
- tfce_sig_results = '/data/neuralabc/paujhe/mMPI/results/4mm_flexi_ownbinmask_09062022/tfce_0006_d5mored2.nii'
- # %%
- ##loop for gm_seg_f, wm_seg_f##
- ## follow below for d1, d2,d5 for LRN and SMP
- dict = {}
- res = {}
- for i in range(len(LRN)):
- gm_seg_f = Pname_LRN_GM_d1[i]
- wm_seg_f = Pname_LRN_WM_d1[i]
- metric_f = Pname_LRN_T1_d1[i]
- res[LRN[i]] = metric_extract_ROI_gm_wm_gmwm_cut(metric_f, original_ROI_f, gm_seg_f, wm_seg_f, tfce_sig_results,tfce_cut=1.3,
- orig_ROI_dil_iterations=3,ext_WM_dil_iterations=2,cut=0, verbosity=1)
- # %%
- df = pd.DataFrame(res)
- df = df.T
- #df.to_csv('/data/neuralabc/paujhe/mMPI/Bx/Cluster_D/august01_2024/T1mean_d1_LRN_clusterD_august01_2024.csv', index=True)
- # %% [markdown]
- # ## to check relationship between T1 values and VBM values in SPC for d1,d2,d5
- # %%
- ##### T1 values of the GM region to see associationw ith Bx
- dfT1_LRN_D = pd.read_csv('/data/neuralabc/paujhe/mMPI/Bx/Cluster_D/august01_2024/clusterD_T1_Bx.csv') #, usecols=['T1_GM_LRN_d2','T1_GM_LRN_d5'])
- # %%
- dfT1_LRN_D['d5minusd2'] = dfT1_LRN_D['T1_GM_LRN_d5']-dfT1_LRN_D['T1_GM_LRN_d2'] #cluster D- slow learning
- new_dfT1_LRN_D = dfT1_LRN_D['d5minusd2']
- var_vec_d_T1 = new_dfT1_LRN_D.copy()
- var_vec_d_T1 = var_vec_d_T1[~np.isnan(var_vec_d_T1)]
- pearsonr(var_vec_d_T1, synB12minusB3['B12minusB3'])
- # %%
- #cluster D- left SPC
- T1_D_LRN_d1 = dfT1_LRN_D['T1_GM_LRN_d1']
- T1_D_LRN_d2 = dfT1_LRN_D['T1_GM_LRN_d2']
- T1_D_LRN_d5 = dfT1_LRN_D['T1_GM_LRN_d5']
- T1_D_SMP_d1 = dfT1_LRN_D['T1_GM_SMP_d1']
- T1_D_SMP_d2 = dfT1_LRN_D['T1_GM_SMP_d2']
- T1_D_SMP_d5 = dfT1_LRN_D['T1_GM_SMP_d5']
- dfvbm_D = pd.read_csv('/data/neuralabc/paujhe/mMPI/Bx/clusterD_VBM.csv')
- VBM_D_LRN_d1 = dfvbm_D['LRN_d1']
- VBM_D_LRN_d2 = dfvbm_D['LRN_d2']
- VBM_D_LRN_d5 = dfvbm_D['LRN_d5']
- VBM_D_SMP_d1 = dfvbm_D['SMP_d1']
- VBM_D_SMP_d2 = dfvbm_D['SMP_d2']
- VBM_D_SMP_d5 = dfvbm_D['SMP_d5']
- days = ['d5-d1','d5-d2']
- modality = ['gm','t1']
- groups = ['lrn','smp']
- gm_lrn_D_d1 = VBM_D_LRN_d1.copy()
- gm_lrn_D_d1 = gm_lrn_D_d1[~np.isnan(gm_lrn_D_d1)]
- gm_lrn_D_d2 = VBM_D_LRN_d2.copy()
- gm_lrn_D_d2 = gm_lrn_D_d2[~np.isnan(gm_lrn_D_d2)]
- gm_lrn_D_d5 = VBM_D_LRN_d5.copy()
- gm_lrn_D_d5 = gm_lrn_D_d5[~np.isnan(gm_lrn_D_d5)]
- gm_smp_D_d1 = VBM_D_SMP_d1.copy()
- gm_smp_D_d1 = gm_smp_D_d1[~np.isnan(gm_smp_D_d1)]
- gm_smp_D_d2 = VBM_D_SMP_d2.copy()
- gm_smp_D_d2 = gm_smp_D_d2[~np.isnan(gm_smp_D_d2)]
- gm_smp_D_d5 = VBM_D_SMP_d5.copy()
- gm_smp_D_d5 = gm_smp_D_d5[~np.isnan(gm_smp_D_d5)]
- t1_lrn_D_d1 = T1_D_LRN_d1.copy()
- t1_lrn_D_d1 = t1_lrn_D_d1[~np.isnan(t1_lrn_D_d1)]
- t1_lrn_D_d2 = T1_D_LRN_d2.copy()
- t1_lrn_D_d2 = t1_lrn_D_d2[~np.isnan(t1_lrn_D_d2)]
- t1_lrn_D_d5 = T1_D_LRN_d5.copy()
- t1_lrn_D_d5 = t1_lrn_D_d5[~np.isnan(t1_lrn_D_d5)]
- t1_smp_D_d1 = T1_D_SMP_d1.copy()
- t1_smp_D_d1 = t1_smp_D_d1[~np.isnan(t1_smp_D_d1)]
- t1_smp_D_d2 = T1_D_SMP_d2.copy()
- t1_smp_D_d2 = t1_smp_D_d2[~np.isnan(t1_smp_D_d2)]
- t1_smp_D_d5 = T1_D_SMP_d5.copy()
- t1_smp_D_d5 = t1_smp_D_d5[~np.isnan(t1_smp_D_d5)]
- gm_lrn_change = gm_lrn_D_d5 - gm_lrn_D_d2
- t1_lrn_change = t1_lrn_D_d5 - t1_lrn_D_d2
- min_len = min(len(gm_lrn_change), len(t1_lrn_change))
- gm_lrn_change = gm_lrn_change[:min_len]
- t1_lrn_change = t1_lrn_change[:min_len]
- r_lrn, p_lrn = pearsonr(gm_lrn_change, t1_lrn_change)
- ci_lower_lrn, ci_upper_lrn = correlation_ci(r_lrn, min_len)
- print(f"\n LRN Group (d5-d2 slow learning):")
- print(f" r = {r_lrn:.2f}, 95% CI [{ci_lower_lrn:.2f}, {ci_upper_lrn:.2f}], p = {p_lrn:.4f}, n = {min_len}")
- gm_smp_change = gm_smp_D_d5 - gm_smp_D_d2
- t1_smp_change = t1_smp_D_d5 - t1_smp_D_d2
- min_len_smp = min(len(gm_smp_change), len(t1_smp_change))
- gm_smp_change = gm_smp_change[:min_len_smp]
- t1_smp_change = t1_smp_change[:min_len_smp]
- r_smp, p_smp = pearsonr(gm_smp_change, t1_smp_change)
- ci_lower_smp, ci_upper_smp = correlation_ci(r_smp, min_len_smp)
- print(f"\nSMP Group (d5-d2):")
- print(f" r = {r_smp:.2f}, 95% CI [{ci_lower_smp:.2f}, {ci_upper_smp:.2f}], p = {p_smp:.4f}, n = {min_len_smp}")
- # T1 change vs SYN change for LRN group (slow learning, d5-d2)
- bx_data = synB12minusB3['B12minusB3'].dropna().values
- t1_change_bx = t1_lrn_D_d5 - t1_lrn_D_d2
- t1_change_bx = t1_change_bx[~np.isnan(t1_change_bx)]
- min_len_bx = min(len(t1_change_bx), len(bx_data))
- t1_change_bx = t1_change_bx[:min_len_bx]
- bx_data = bx_data[:min_len_bx]
- r_bx, p_bx = pearsonr(t1_change_bx, bx_data)
- ci_lower_bx, ci_upper_bx = correlation_ci(r_bx, min_len_bx)
- print(f"\nLeft SPC - T1 change vs SYN change (LRN, slow learning d5-d2):")
- print(f" r = {r_bx:.2f}, 95% CI [{ci_lower_bx:.2f}, {ci_upper_bx:.2f}], p = {p_bx:.4f}, n = {min_len_bx}")
- # T1 change vs SYN change for SMP group (slow learning, d5-d2) in Left SPC
- SMP_bx_data = synscores_SMP['B12minusB3'].dropna().values
- SMP_t1_change_bx = t1_smp_D_d5 - t1_smp_D_d2
- SMP_t1_change_bx = SMP_t1_change_bx[~np.isnan(SMP_t1_change_bx)]
- SMP_min_len_bx = min(len(SMP_t1_change_bx), len(SMP_bx_data))
- SMP_t1_change_bx = SMP_t1_change_bx[:SMP_min_len_bx]
- SMP_bx_data = SMP_bx_data[:SMP_min_len_bx]
- SMP_r_bx, SMP_p_bx = pearsonr(SMP_t1_change_bx, SMP_bx_data)
- SMP_ci_lower_bx, SMP_ci_upper_bx = correlation_ci(SMP_r_bx, SMP_min_len_bx)
- print(f"\nLeft SPC - T1 change vs SYN change (SMP, slow learning d5-d2):")
- print(f" r = {SMP_r_bx:.2f}, 95% CI [{SMP_ci_lower_bx:.2f}, {SMP_ci_upper_bx:.2f}], p = {SMP_p_bx:.4f}, n = {SMP_min_len_bx}")
- # %% [markdown]
- # # LOSO (LEAVE ONE SUBJECT OUT )
- # %%
- print("DIAGNOSTIC: Checking data dimensions")
- print(f"VBM file length: {len(dfvbm_LRN_D)}")
- print(f"T1 file length: {len(dfT1_LRN_D)}")
- print(f"Behavior file length: {len(synscores_LRN)}")
- print("\nChecking for missing values in each file:")
- print(f"VBM NaNs:\n{dfvbm_LRN_D.isnull().sum()}")
- print(f"\nT1 NaNs:\n{dfT1_LRN_D.isnull().sum()}")
- print(f"\nBehavior NaNs:\n{synscores_LRN.isnull().sum()}")
- if not (len(dfvbm_LRN_D) == len(dfT1_LRN_D) == len(synscores_LRN)):
- print("\n WARNING: Files have different lengths!")
- print("This will cause misalignment. Please check your CSV files.")
- min_len = min(len(dfvbm_LRN_D), len(dfT1_LRN_D), len(synscores_LRN))
- print(f"\nTruncating all to shortest length: {min_len}")
- dfvbm_LRN_D = dfvbm_LRN_D.iloc[:min_len]
- #dfT1_LRN_D = dfT1_LRN_D.iloc[:min_len]
- synscores_LRN = synscores_LRN.iloc[:min_len]
- data = pd.DataFrame({
- # VBM GMV values
- 'gmv_d1': dfvbm_LRN_D['LRN_d1'],
- 'gmv_d2': dfvbm_LRN_D['LRN_d2'],
- 'gmv_d5': dfvbm_LRN_D['LRN_d5'],
- 'gmv_d6': dfvbm_LRN_D['LRN_d6'],
- 'gmv_d1_SMP': dfvbm_SMP_D['SMP_d1'],
- 'gmv_d2_SMP': dfvbm_SMP_D['SMP_d2'],
- 'gmv_d5_SMP': dfvbm_SMP_D['SMP_d5'],
- 'gmv_d6_SMP': dfvbm_SMP_D['SMP_d6'],
- 't1_gmv_d1': dfT1_LRN_D['T1_GM_LRN_d1'],
- 't1_gmv_d2': dfT1_LRN_D['T1_GM_LRN_d2'],
- 't1_gmv_d5': dfT1_LRN_D['T1_GM_LRN_d5'],
- 't1_gmv_d1_SMP': dfT1_LRN_D['T1_GM_SMP_d1'],
- 't1_gmv_d2_SMP': dfT1_LRN_D['T1_GM_SMP_d2'],
- 't1_gmv_d5_SMP': dfT1_LRN_D['T1_GM_SMP_d5'],
- 'syn_b1': synscores_LRN['Block1'],
- 'syn_b3': synscores_LRN['Block3'],
- 'syn_b12': synscores_LRN['Block12']
- })
- # %%
- # SMP GROUP: T1 GMV Change (D5-D2) vs Behavior (Block12-Block3)
- data_SMP = pd.DataFrame({
- 't1_gmv_d2_SMP': dfT1_LRN_D['T1_GM_SMP_d2'],
- 't1_gmv_d5_SMP': dfT1_LRN_D['T1_GM_SMP_d5'],
- 'SMP_syn_b3': synscores_SMP['Block 3'],
- 'SMP_syn_b12': synscores_SMP['Block 12']
- }).reset_index(drop=True)
- print(f"SMP group n before dropna: {len(data_SMP)}")
- print(data_SMP.isnull().sum())
- data_SMP = data_SMP.dropna()
- print(f"SMP group n after dropna: {len(data_SMP)}")
- # Change scores
- data_SMP['t1_change_SMP'] = data_SMP['t1_gmv_d5_SMP'] - data_SMP['t1_gmv_d2_SMP']
- data_SMP['bx_change_SMP'] = data_SMP['SMP_syn_b12'] - data_SMP['SMP_syn_b3']
- X_t1_SMP = data_SMP['t1_change_SMP'].values
- y_SMP = data_SMP['bx_change_SMP'].values
- # --- Biased (standard) Pearson ---
- r_SMP, p_SMP = stats.pearsonr(X_t1_SMP, y_SMP)
- print(f"\nSMP: T1 GMV Change (D5-D2) vs Behavior Change (B12-B3)")
- print(f" Original (BIASED): r = {r_SMP:.3f}, p = {p_SMP:.4f}, n = {len(X_t1_SMP)}")
- # --- LOSO (unbiased) ---
- loo = LeaveOneOut()
- loso_SMP = []
- for train_idx, test_idx in loo.split(X_t1_SMP):
- r_train, _ = stats.pearsonr(X_t1_SMP[train_idx], y_SMP[train_idx])
- loso_SMP.append(r_train)
- mean_r_SMP = np.mean(loso_SMP)
- ci_lower_SMP = np.percentile(loso_SMP, 2.5)
- ci_upper_SMP = np.percentile(loso_SMP, 97.5)
- print(f" LOSO (UNBIASED): mean r = {mean_r_SMP:.3f}")
- print(f" 95% CI: [{ci_lower_SMP:.3f}, {ci_upper_SMP:.3f}]")
- print(f" SD = {np.std(loso_SMP):.3f}")
- # %%
- # Calculate changes (slow learning stage)
- data['gmv_change'] = data['gmv_d5'] - data['gmv_d2']
- data['t1_change'] = data['t1_gmv_d5'] - data['t1_gmv_d2']
- data['behavior_change'] = data['syn_b12'] - data['syn_b3']
- data['t1_change_SMP'] = data['t1_gmv_d5_SMP'] - data['t1_gmv_d2_SMP']
- data['gmv_change_SMP'] = data['gmv_d5_SMP'] - data['gmv_d2_SMP']
- if data.isnull().any().any():
- print("\n WARNING: Missing values detected")
- print(data.isnull().sum())
- data = data.dropna()
- print(f"After removing missing: n = {len(data)}")
- print("CORRELATION 1: VBM GMV Change (D5-D2) vs Behavior (Block12-Block3)")
- X_gmv_bx = data['gmv_change'].values
- y_bx = data['behavior_change'].values
- r_gmv_bx, p_gmv_bx = stats.pearsonr(X_gmv_bx, y_bx)
- print(f"\n Original (BIASED): r = {r_gmv_bx:.3f}, p = {p_gmv_bx:.4f}")
- # LOSO
- loo = LeaveOneOut()
- loso_gmv_bx = []
- for train_idx, test_idx in loo.split(X_gmv_bx):
- r_train, _ = stats.pearsonr(X_gmv_bx[train_idx], y_bx[train_idx])
- loso_gmv_bx.append(r_train)
- mean_r_gmv_bx = np.mean(loso_gmv_bx)
- ci_lower_gmv_bx = np.percentile(loso_gmv_bx, 2.5)
- ci_upper_gmv_bx = np.percentile(loso_gmv_bx, 97.5)
- print(f"\n LOSO (UNBIASED): mean r = {mean_r_gmv_bx:.3f}")
- print(f" 95% CI: [{ci_lower_gmv_bx:.3f}, {ci_upper_gmv_bx:.3f}]")
- print(f" SD = {np.std(loso_gmv_bx):.3f}")
- print("CORRELATION 2: T1 GMV Change vs VBM GMV Change (both D5-D2)")
- X_t1 = data['t1_change'].values
- X_gmv = data['gmv_change'].values
- r_t1_gmv, p_t1_gmv = stats.pearsonr(X_t1, X_gmv)
- print(f"\n Original (BIASED): r = {r_t1_gmv:.3f}, p = {p_t1_gmv:.4f}")
- # LOSO
- loso_t1_gmv = []
- for train_idx, test_idx in loo.split(X_t1):
- r_train, _ = stats.pearsonr(X_t1[train_idx], X_gmv[train_idx])
- loso_t1_gmv.append(r_train)
- mean_r_t1_gmv = np.mean(loso_t1_gmv)
- ci_lower_t1_gmv = np.percentile(loso_t1_gmv, 2.5)
- ci_upper_t1_gmv = np.percentile(loso_t1_gmv, 97.5)
- print(f"\n LOSO (UNBIASED): mean r = {mean_r_t1_gmv:.3f}")
- print(f" 95% CI: [{ci_lower_t1_gmv:.3f}, {ci_upper_t1_gmv:.3f}]")
- print(f" SD = {np.std(loso_t1_gmv):.3f}")
- print("SMP T1 GMV Change vs VBM GMV Change (both D5-D2)")
- X_t1_SMP = data['t1_change_SMP'].values
- X_gmv_SMP = data['gmv_change_SMP'].values
- r_t1_gmv_SMP, p_t1_gmv_SMP = stats.pearsonr(X_t1_SMP, X_gmv_SMP)
- print(f"\n Original (BIASED): r = {r_t1_gmv_SMP:.3f}, p = {p_t1_gmv_SMP:.4f}")
- # LOSO
- loso_t1_gmv_SMP = []
- for train_idx, test_idx in loo.split(X_t1_SMP):
- r_train_SMP, _ = stats.pearsonr(X_t1_SMP[train_idx], X_gmv_SMP[train_idx])
- loso_t1_gmv_SMP.append(r_train_SMP)
- mean_r_t1_gmv_SMP = np.mean(loso_t1_gmv_SMP)
- ci_lower_t1_gmv_SMP = np.percentile(loso_t1_gmv_SMP, 2.5)
- ci_upper_t1_gmv_SMP = np.percentile(loso_t1_gmv_SMP, 97.5)
- print(f"\n LOSO (UNBIASED): mean r = {mean_r_t1_gmv_SMP:.3f}")
- print(f" 95% CI: [{ci_lower_t1_gmv_SMP:.3f}, {ci_upper_t1_gmv_SMP:.3f}]")
- print(f" SD = {np.std(loso_t1_gmv_SMP):.3f}")
- print("CORRELATION 3: T1 GMV Change (D5-D2) vs Behavior (Block12-Block3)")
- X_t1_bx = data['t1_change'].values
- y_bx_t1 = data['behavior_change'].values
- r_t1_bx, p_t1_bx = stats.pearsonr(X_t1_bx, y_bx_t1)
- print(f"\n Original (BIASED): r = {r_t1_bx:.3f}, p = {p_t1_bx:.4f}")
- # LOSO
- loso_t1_bx = []
- for train_idx, test_idx in loo.split(X_t1_bx):
- r_train, _ = stats.pearsonr(X_t1_bx[train_idx], y_bx_t1[train_idx])
- loso_t1_bx.append(r_train)
- mean_r_t1_bx = np.mean(loso_t1_bx)
- ci_lower_t1_bx = np.percentile(loso_t1_bx, 2.5)
- ci_upper_t1_bx = np.percentile(loso_t1_bx, 97.5)
- print(f"\n LOSO (UNBIASED): mean r = {mean_r_t1_bx:.3f}")
- print(f" 95% CI: [{ci_lower_t1_bx:.3f}, {ci_upper_t1_bx:.3f}]")
- print(f" SD = {np.std(loso_t1_bx):.3f}")
ROI_Bx_T1_correlation.ipynb at commit dc8b802, no license · at the source
Overview
13 affiliations
- Department of Psychology Concordia University Montreal Québec Canada
- School of Health Concordia University Montréal Québec Canada
- Brain Language Lab Freie Universität Berlin Berlin Germany
- Charité Universitätsmedizin Berlin Germany
- Department of Neurology Max Planck Institute for Human Cognitive and Brain Sciences Leipzig Germany
- Department of Nuclear Medicine and Radiobiology Université de Sherbrooke Sherbrooke Québec Canada
- Department of Biomedical Engineering McGill University Montreal Québec Canada
- McConnell Brain Imaging Centre Montreal Neurological Institute Montreal Québec Canada
- Department of Neurology and Neurosurgery McGill University Montreal Québec Canada
- Clinic for Cognitive Neurology Leipzig Germany
- Department of Physics Concordia University Montreal Québec Canada
- Montreal Heart Institute Montreal Québec Canada
- Full Brain Picture Analytics Leidein the Netherlands
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 7 matches between paragraphs and lines of code.
neuralabc/Structural_Physiology_MSLplasticity
dc8b8028c55c9a2d24fb99c44173d520de00cf1e, 15 April 2026Availability: 1 check, the latest on 27 September 2026: the link answers
- 27 September 2026: the link answers
7 files
- ROI_Bx_T1_correlation.ip
ynb , Jupyter, 875 lines, 5 matches - TFCE_estimation.m, MATLAB, 14 lines
- flexible_factorial_desig
n_withbinmask.m , MATLAB, 507 lines, 1 match - longitudinal_segmentatio
n_all40subjects.m , MATLAB, 49 lines, 1 match - modelEstimation.m, MATLAB, 8 lines
- smooth_4mm_193images.m, MATLAB, 14 lines
- README.md, Text, 19 lines
The paper's code and data availability statement is in the Data section.
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;
- 7 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.
Code and data availability statement
The paper has a code and data 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: neuralabc/
Structural_Physiology_MS Lplasticity - it says that the data are available on request
Read it in the paper: doi.org/10.1002/hbm.70562.
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, 27 September 2026: the first record
Recorded: type, language, journal, volume, issue, pages, dates, 8 authors, 13 MeSH terms, 3 funders, 117 references.
Cite
This paper
Paul, J., Jäger, A. T. P., Huck, J., Tardif, C. L., Villringer, A., Gauthier, C. J., Bazin, P. L., & Steele, C. J. (2026). Distinct Physiological Mechanisms Drive Grey Matter Plasticity in Complex Versus Simple Sequence Learning. Human brain mapping, 47(8), e70562. https://
BibTeX
@article{paul2026distinc
author = {Paul, Jhelum and Jäger, A. T. P. and Huck, J. and Tardif, C. L. and Villringer, A. and Gauthier, C. J. and Bazin, P. L. and Steele, Christopher J.},
title = {{Distinct Physiological Mechanisms Drive Grey Matter Plasticity in Complex Versus Simple Sequence Learning}},
journal = {Human brain mapping},
year = {2026},
month = jun,
volume = {47},
number = {8},
pages = {e70562},
publisher = {Wiley},
issn = {1065-9471},
doi = {10.1002/
url = {https://
pmid = {42237744},
pmcid = {PMC13266411}
}
RIS
TY - JOUR
AU - Paul, Jhelum
AU - Jäger, A. T. P.
AU - Huck, J.
AU - Tardif, C. L.
AU - Villringer, A.
AU - Gauthier, C. J.
AU - Bazin, P. L.
AU - Steele, Christopher J.
TI - Distinct Physiological Mechanisms Drive Grey Matter Plasticity in Complex Versus Simple Sequence Learning
T2 - Human brain mapping
J2 - Hum Brain Mapp
PY - 2026
DA - 2026/
VL - 47
IS - 8
SP - e70562
SN - 1065-9471
PB - Wiley
DO - 10.1002/
UR - https://
LA - en
ER -
CSL-JSON
{
"id": "10.1002/
"type": "article-journal",
"title": "Distinct Physiological Mechanisms Drive Grey Matter Plasticity in Complex Versus Simple Sequence Learning",
"container-title": "Human brain mapping",
"author": [
{
"family": "Paul",
"given": "Jhelum"
},
{
"family": "Jäger",
"given": "A. T. P."
},
{
"family": "Huck",
"given": "J."
},
{
"family": "Tardif",
"given": "C. L."
},
{
"family": "Villringer",
"given": "A."
},
{
"family": "Gauthier",
"given": "C. J."
},
{
"family": "Bazin",
"given": "P. L."
},
{
"family": "Steele",
"given": "Christopher J."
}
],
"container-title-short":
"volume": "47",
"issue": "8",
"page": "e70562",
"DOI": "10.1002/
"PMID": "42237744",
"PMCID": "PMC13266411",
"ISSN": "1065-9471",
"publisher": "Wiley",
"URL": "https://
"language": "en",
"issued": {
"date-parts": [
[
2026,
6,
1
]
]
}
}
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.1038/s41467-026-73366-9 [code]
- Cortical and white matter myelination proceed in concert during early infancy.Journal: Nature communicationsIn common: MRtrix3, statsmodels, NiBabel, 6 other tools, 6 references
- [2] doi:10.1162/imag.a.1325 [code]
- Decoding everyday levels of musical training from subcortical white-matter architecture.Journal: Imaging neuroscience (Cambridge, Mass.)In common: MRtrix3, statsmodels, seaborn, 4 other tools, structural MRI / diffusion, 6 references
- [3] doi:10.1162/imag.a.1203 [code]
- Motor cortical areas facilitate schema-mediated integration of new motor information into memory.Journal: Imaging neuroscience (Cambridge, Mass.)In common: SPM, 8 references
- [4] doi:10.1162/imag.a.1174 [code]
- Retinal nerve fibre layer thickness reflects characteristics of brain grey and white matter.Journal: Imaging neuroscience (Cambridge, Mass.)In common: Nilearn, SPM, NiBabel, 2 other tools, structural MRI / diffusion, 2 references, author A. Villringer
- [5] doi:10.1038/s41467-026-71151-2 [code]
- Common and distinct neural correlates of social interaction processing and theory of mind in narratives.Journal: Nature communicationsIn common: MRtrix3, Nilearn, SPM, 8 other tools
- [6] doi:10.1038/s41467-026-71918-7 [code]
- Developmental disinhibition gates language lateralization in childhood.Journal: Nature communicationsIn common: MRtrix3, Nilearn, SPM, 7 other tools, 1 reference
- [7] doi:10.1162/imag.a.105 [code]
- Right posterior theta reflects human parahippocampal phase resetting by salient cues during goal-directed navigationJournal: n/aIn common: Nilearn, SPM, statsmodels, 6 other tools, 2 references
- [8] doi:10.1038/s41467-026-74566-z [code]
- Low-dimensional and optimised representations of high-level information in the expert brain.Journal: Nature communicationsIn common: Nilearn, SPM, statsmodels, 7 other tools, 1 reference
- [9] doi:10.1038/s41467-026-71568-9 [code]
- Convergent and selective representations of pain, appetitive processes, aversive processes, and cognitive control in the insula.Journal: Nature communicationsIn common: MRtrix3, Nilearn, SPM, 7 other tools
- [10] doi:10.7554/elife.107933 [code]
- Modality-agnostic decoding of vision and language from fMRI.Journal: eLifeIn common: Nilearn, SPM, statsmodels, 7 other tools, 1 reference
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 7 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:b1cc9e3743e95167…
Add the badge to its README
The badge links the code to this page. Copy one of these into the README of the paper's code: only you decide where it goes, and nothing is changed for you.
Markdown
[, paste the snippet at the top, then “Commit changes…” and, to review it first, “Create a new branch and start a pull request”. You open the pull request; OSCR asks for no permission.
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: questions and error reports about this paper and its code, from signed-in readers and its authors. It opens with sign-in.
Reproductions: reports from readers who ran the authors' code: what they reproduced, with which environment, commit and data. It opens with sign-in.
Activity: what happens around this paper: new versions of its record, its map's validation, discussions and reproductions. It opens with sign-in.
