OSCR

Anterior insular co-activation patterns associated with stress markers in chronic primary pain.

Code ↔ Paper

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

The 10 matches
  1. [1] § Materials and methods › Resting-state functional dynamics › Co-activation patterns ↔ 02_CAPs/01_Analysis/Script_twopop_PCA_HC_ref_SH.m, lines 824–916 · score 0.87 · consensus clustering, activation patterns, reference population, events, PAC, retained frames
  2. [2] § Materials and methods › Demographic and clinical characteristics ↔ 01_Clinical_Measures/Demographics_Table.R, lines 87–127 · score 0.70 · hormonal contraceptives, psychotropic medications, corticosteroids, analgesics, sex, demographic
  3. [3] § Results › Identified aIC-based CAPs in HC ↔ 02_CAPs/01_Analysis/Script_twopop_PCA_HC_ref_SH.m, lines 824–916 · score 0.69 · MNI space, co activation, reference population, retained frames, fraction, maps
  4. [4] § Materials and methods › Statistical analysis ↔ 02_CAPs/02_Statistics/02_CAPs_Stat.Rmd, lines 315–334 · score 0.68 · Post hoc, linear mixed, interaction term, ID, FDR, BDI
  5. [5] § Materials and methods › Statistical analysis ↔ 01_Clinical_Measures/Demographics_Table.R, lines 129–167 · score 0.64 · Wilcoxon rank sum, Shapiro Wilk, Welch, variances, demographic, clinical
  6. [6] § Materials and methods › Demographic and clinical characteristics › Pain provocation test ↔ 01_Clinical_Measures/Demographics_Table.R, lines 211–249 · score 0.60 · peg algometry, pain intensity, ear, Algopeg
  7. [7] § Materials and methods › Statistical analysis ↔ 01_Clinical_Measures/Demographics_Table.R, lines 211–249 · score 0.60 · BPI severity, Peg algometry, Alpha, pain, CPP
  8. [8] § Materials and methods › Demographic and clinical characteristics › Salivary cortisol and alpha-amylase ↔ 01_Clinical_Measures/Cortisol_AUC_Analysis.R, lines 69–156 · score 0.58 · post awakening, cortisol, concentrations, curve, AUCI, 45 min
  9. [9] § Materials and methods › MRI data acquisition and preprocessing ↔ 02_CAPs/01_Analysis/Script_twopop_PCA_HC_ref_SH.m, lines 68–134 · score 0.56 · motion parameters, SPM, FD, voxel, brain
  10. [10] § Materials and methods › Resting-state functional dynamics › Co-activation patterns ↔ 02_CAPs/01_Analysis/Script_twopop_PCA_HC_ref_SH.m, lines 136–178 · score 0.51 · consensus clustering, selected frames, algorithm, threshold, activations, HC

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

MATLAB · 922 lines · 33 KB · no license · 4 matches

  1. %% Script to run the CAPs analyses without the GUI
  2. % In this script, we assume HC as a reference population
  3. % PCA included
  4. % Adapt:
  5. % - Seed
  6. % - The parameters in section 2 can be adaped.
  7. % - K_range in section 4, as well as in the section 7
  8. % "Parameters.KMeansClustering.MaxClusterNumber = Kmax"
  9. % Funtion generated by Samantha Weber:
  10. % - createMask_CAP_SW
  11. % - loadData_SW
  12. % - loadseed_SW
  13. % - MakeViolin_SW
  14. % Remaining Functions are from the TbCAPs Toolbox (https://github.com/MIPLabCH/TbCAPs)
  15. % Adaptation and additions for the CAPs in CPP Project by Salome Häuselmann
  16. % ([email hidden]) 2024/2025
  17. clear; clc;close;
  18. addpath(genpath(pwd));
  19. %% 1. Loading the data files
  20. RootPath = '';
  21. SavePath = '';
  22. spmPath = '';
  23. mkdir(SavePath);
  24. %% 1.1 Define your variables
  25. prefix = 's5w*';
  26. selectMask = 'Population'; % make GM Population Mask based on data
  27. seedName = {'Anterior_Insula_BNA_mask.nii'};
  28. MasksPath = '/';
  29. fancyName = '';
  30. Group = {'HC', 'CPP'};
  31. n_datasets = 2;
  32. % load HC folder;
  33. filelist=dir(fullfile(RootPath,Group{1}, 'P*'));
  34. N_HC{1}=size(filelist,1);
  35. myHC=cell(1,N_HC{1});
  36. for f=1:N_HC{1}
  37. myHC{f}=filelist(f).name;
  38. end
  39. clear filelist f
  40. % load CPP folder;
  41. filelist=dir(fullfile(RootPath,Group{2}, 'P*'));
  42. N_CPP{1}=size(filelist,1);
  43. myCPP=cell(1,N_CPP{1});
  44. for f=1:N_CPP{1}
  45. myCPP{f}=filelist(f).name;
  46. end
  47. clear filelist f
  48. mySubj = [myHC, myCPP];
  49. N_Subj{1} = N_HC{1} + N_CPP{1};
  50. % Define the folders HC
  51. for i = 1:N_HC{1}
  52. functdir1{i} = fullfile(RootPath, Group{1}, myHC{i});
  53. end
  54. % Define the folders CPP
  55. for i = 1 : N_CPP{1}
  56. functdir2{i} = fullfile(RootPath, Group{2}, myCPP{i});
  57. end
  58. %% 1. Loading the data files
  59. mask ={};
  60. brain_info ={};
  61. n_dataset = 0;
  62. % Data: cell array, each cell of size n_TP x n_masked_voxels
  63. % Mask: n_voxels x 1 logical vector
  64. % Header: the header (obtained by spm_vol) of one NIFTI file with proper
  65. % data dimension and .mat information
  66. [mask, brain_info] = createMask_CAP_SW(functdir1, prefix, selectMask);
  67. Tstart = clock;
  68. % Data HC: cell array, each cell of size n_TP x n_masked_voxels
  69. if exist(fullfile(SavePath,fancyName,['HCloaded_' fancyName '.mat']))
  70. disp(['Data HC has been loaded already !'])
  71. load(fullfile(SavePath,fancyName,['HCloaded_' fancyName '.mat']));
  72. else
  73. TC ={};
  74. FD ={};
  75. [TC,brain,FD] = loadData_SW(functdir1, prefix, mask, brain_info); % here the motion parameters rp_*-txt file are loaded in
  76. FD1 = FD{:,:};
  77. TC1 = TC{:,:};
  78. % Save intermediate steps
  79. if ~exist (fullfile(SavePath,fancyName))
  80. mkdir(fullfile(SavePath,fancyName));
  81. end
  82. save(fullfile(SavePath,fancyName,['HCloaded_' fancyName '.mat']),'TC1','brain','FD1','-v7.3')
  83. end
  84. % Data CPP: cell array, each cell of size n_TP x n_masked_voxels
  85. if exist(fullfile(SavePath,fancyName,['CPPloaded_' fancyName '.mat']))
  86. disp(['Data CPP has been loaded already !'])
  87. load(fullfile(SavePath,fancyName,['CPPloaded_' fancyName '.mat']));
  88. else
  89. TC ={};
  90. FD={};
  91. [TC,brain,FD] = loadData_SW(functdir2, prefix, mask, brain_info); % here the motion parameters rp_*-txt file are loaded in
  92. FD2 = FD{:,:};
  93. TC2 = TC{:,:};
  94. % Save intermediate steps
  95. if ~exist (fullfile(SavePath,fancyName))
  96. mkdir(fullfile(SavePath,fancyName));
  97. end
  98. save(fullfile(SavePath,fancyName,['CPPloaded_' fancyName '.mat']),'TC2','brain','FD2','-v7.3')
  99. end
  100. % Seed: a n_masked_voxels x n_seed logical vector with seed information
  101. if exist(fullfile(SavePath,fancyName,['Seed_' fancyName '.mat']))
  102. disp(' ');
  103. disp('-----------------------------------------------------');
  104. disp(['Seed has been loaded already !'])
  105. load(fullfile(SavePath,fancyName,['Seed_' fancyName '.mat']));
  106. else
  107. disp(' ');
  108. disp('-----------------------------------------------------');
  109. disp('Load seed...');
  110. [Seed] = loadseed_SW(functdir1, prefix, mask, brain_info, seedName,MasksPath);
  111. save(fullfile(SavePath,fancyName,['Seed_' fancyName '.mat']),'Seed');
  112. disp('Seed successfully loaded!');
  113. end
  114. % Computes seed maps for each subject and for the population, using the
  115. % data from the chosen reference population
  116. TC = [TC1, TC2];
  117. [~,AvgSeedMap] = CAP_Compute_SeedMap(TC1,Seed,1);
  118. %% 2. Specifying the main parameters
  119. % Threshold above which to select frames
  120. T = 0.84;
  121. % Selection mode ('Threshold' or 'Percentage')
  122. SelMode = 'Threshold';
  123. % Threshold of FD above which to scrub out the frame and also the t-1 and
  124. % t+1 frames (if you want another scrubbing setting, directly edit the
  125. % code)
  126. Tmot = 0.5;
  127. % Type of used seed information: select between 'Average','Union' or
  128. % 'Intersection'
  129. SeedType = 'Average';
  130. % Contains the information, for each seed (each row), about whether to
  131. % retain activation (1 0) or deactivation (0 1) time points
  132. switch SeedType
  133. case 'Union'
  134. Activation = [1,0];
  135. for s = 1:size(seedName,2)
  136. SignMatrix(s,:) = Activation;
  137. end
  138. case 'Average'
  139. SignMatrix = [1 0];
  140. end
  141. % Percentage of frames to use in each fold of consensus clustering
  142. Pcc = 80;
  143. % Number of folds we run consensus clustering for
  144. N = 200;%50; %120;
  145. % Percentage of positive-valued voxels to retain for clustering
  146. Pp = 100;
  147. % Percentage of negative-valued voxels to retain for clustering
  148. Pn = 100;
  149. % Number of repetitions of the K-means clustering algorithm
  150. n_rep = 50;%50;
  151. %% 3. Selecting the frames to analyse
  152. % Xon will contain the retained frames, and Indices will tag the time
  153. % points associated to these frames, for each subject (it contains a
  154. % subfield for retained frames and a subfield for scrubbed frames)
  155. [Xon1,p1,Indices1,idx_sep_seeds1,Xonp_scrub1] = CAP_find_activity(TC1,Seed,T,FD1,Tmot,SelMode,SeedType,SignMatrix);
  156. [Xon2,p2,Indices2,idx_sep_seeds2,Xonp_scrub2] = CAP_find_activity(TC2,Seed,T,FD2,Tmot,SelMode,SeedType,SignMatrix);
  157. % Percentage of retained frames across subjects
  158. RetainedPercentage{1} = p1(3,:);
  159. RetainedPercentage{2} = p2(3,:);
  160. % Indices of the frames that have been retained (used later for metrics
  161. % computations)
  162. FrameIndices{1} = Indices1;
  163. FrameIndices{2} = Indices2;
  164. tmp_toplot1 = ConcatMat(RetainedPercentage(1),1,1,N_HC,'FD');
  165. tmp_toplot2 = ConcatMat(RetainedPercentage(2),1,1,N_CPP,'FD');
  166. tmp_toplot = zeros(2,N_CPP{1});
  167. tmp_toplot(1,1:N_HC{1}) = tmp_toplot1;
  168. tmp_toplot(2,1:N_CPP{1}) = tmp_toplot2;
  169. tmp_toplot(tmp_toplot == 0) = NaN;
  170. %% Quality Checks 1 - Visualization
  171. % 1. Percentage of Retained Frames
  172. % Perform two-sample t-test between the two groups
  173. %[~, p_value, ci, stats] = ttest2(tmp_toplot1, tmp_toplot2, 'Vartype', 'unequal');
  174. % Perform unpaired non-parametric t-test (Mann-Withney U)(since in the
  175. % graph the do not look nomrmally distributed)
  176. [p_value, h, stats] = ranksum(tmp_toplot1, tmp_toplot2);
  177. % Displays the violin plot of subject scrubbing percentage for the
  178. % reference population
  179. TPViolin = figure;
  180. axes1 = axes('Parent',TPViolin);
  181. % Colors used in plotting of all populations
  182. PopColor{1} = [255,255,180; 219,224,252; 188,252,188; 230,230,230]/255;
  183. PopColor{2} = [130,48,48; 51,75,163; 59,113,86; 0, 0, 0]/255;
  184. %Create plot
  185. [~,~,TPViolin] = MakeViolin_SW(tmp_toplot,axes1,{'HC' 'CPP'},'Frames ret. [%]',PopColor,1,2);
  186. set(TPViolin,'Visible','on');
  187. % Add t-test results as text on the plot
  188. xPosition = mean(xlim); % Centered on x-axis
  189. yPosition = max(ylim) - 0.05 * range(ylim); % Slightly below the top of the y-axis
  190. text(xPosition, yPosition, sprintf('W = %.2f, p = %.4f', stats.ranksum, p_value), ...
  191. 'FontSize', 12, 'FontWeight', 'bold', 'HorizontalAlignment', 'center', 'Color', 'k');
  192. %Save plot as .jpg and .fig
  193. saveas(gcf,fullfile(SavePath,fancyName,'RetainedFrames.jpg'));
  194. saveas(gcf,fullfile(SavePath,fancyName,'RetainedFrames.fig'));
  195. disp('-----------------------------------------------------');
  196. disp(' ');
  197. disp(['Figure Frames retained has been saved in ' SavePath]);
  198. close;
  199. % 2. Distribution of retained frames
  200. % Test of data distribution homogeneity (inter-subject variability)
  201. % Test normal distribution around mean % of retained frames value using Kolmogorov–Smirnov test.
  202. % Define the mean and standard deviation for both datasets
  203. mu_HC = mean(tmp_toplot1);
  204. sigma_HC = std(tmp_toplot1);
  205. mu_CPP = mean(tmp_toplot2);
  206. sigma_CPP = std(tmp_toplot2);
  207. % Standardize the data (convert to Z-scores)
  208. z_HC = (tmp_toplot1 - mu_HC) / sigma_HC;
  209. z_CPP = (tmp_toplot2 - mu_CPP) / sigma_CPP;
  210. % Perform Kolmogorov-Smirnov Test against the standard normal distribution
  211. [h_HC, p_HC] = kstest(z_HC);
  212. [h_CPP, p_CPP] = kstest(z_CPP);
  213. % Coefficient of Variation (CV)
  214. cv_HC = sigma_HC / mu_HC;
  215. cv_CPP = sigma_CPP / mu_CPP;
  216. % Define the normal distribution curves for plotting
  217. x_HC = linspace(mu_HC - 4*sigma_HC, mu_HC + 4*sigma_HC, 1000);
  218. x_CPP = linspace(mu_CPP - 4*sigma_CPP, mu_CPP + 4*sigma_CPP, 1000);
  219. pdf_HC = normpdf(x_HC, mu_HC, sigma_HC);
  220. pdf_CPP = normpdf(x_CPP, mu_CPP, sigma_CPP);
  221. % Plot histogram and fitted normal distribution curves
  222. figure;
  223. hold on;
  224. histogram(tmp_toplot1, 20, 'Normalization', 'pdf', 'FaceAlpha', 0.5, 'DisplayName', 'HC (Histogram)');
  225. histogram(tmp_toplot2, 20, 'Normalization', 'pdf', 'FaceAlpha', 0.5, 'DisplayName', 'CPP (Histogram)');
  226. plot(x_HC, pdf_HC, 'LineWidth', 2, 'DisplayName', sprintf('Normal Fit HC (KS p=%.3f)', p_HC));
  227. plot(x_CPP, pdf_CPP, 'LineWidth', 2, 'DisplayName', sprintf('Normal Fit CPP (KS p=%.3f)', p_CPP));
  228. xlabel('Retained Frames Value');
  229. ylabel('Density');
  230. title('Data Distribution and Normal Fit (HC vs. CPP)');
  231. legend;
  232. hold off;
  233. % Save plot as .jpg and .fig with a new name
  234. saveas(gcf, fullfile(SavePath, fancyName, 'HC_CPP_Distribution.jpg'));
  235. saveas(gcf, fullfile(SavePath, fancyName, 'HC_CPP_Distribution.fig'));
  236. % Display message confirming the save
  237. disp('-----------------------------------------------------');
  238. disp(' ');
  239. disp(['Figure "HC_CPP_Distribution" has been saved in ' SavePath]);
  240. % Close the figure
  241. close;
  242. %% 4. Consensus clustering (if wished to determine the optimum K)
  243. % The input to PCA should have a dimensionality n_dimensions x
  244. % n_datapoints; since we consider a population of subjects in a cell array
  245. % (each cell with size n_dims x n_samples_persubj), we want to concatenate
  246. % these cells into one giant data matrix, which we feed to the PCA
  247. % function. I will denote the number of dimensions (or voxels) by V, and
  248. % the number of total time points across subjects by T.
  249. % Change dimension of Xon1 to feed into PCA
  250. Xon1_pca = [];
  251. for i = 1:N_HC{1,1}
  252. Xon1_pca = [Xon1_pca, Xon1{1,i}];
  253. end
  254. [U, W,Eigenvals,mu] = ComputePCA(Xon1_pca);
  255. %save(fullfile(SavePath,fancyName,'PCA_Outputs.mat'), 'U', 'W', 'Eigenvals');
  256. %[U,W] = ComputePCA(cell2mat(Xon1_pca));
  257. % After the call, U will have size V x T, and W will have size T x T. Be
  258. % careful that in our function, row i of W contain the weights, for all
  259. % T frames, associated to the principal direction i (contained as the i-th
  260. % column in U).
  261. % Also, notice that we want to compute only one PCA on the
  262. % population-wise data, not one per subject! Otherwise, we would have a
  263. % different dimensionality reduction for each subject, which would make our
  264. % life complicated...
  265. % You want to input "{W}" (rows = dimensions, columns = data points) to
  266. % CAP_ConsensusClustering. The brackets are because the function wants a
  267. % cell input...
  268. % After the consensus clustering step, you will want to feed W to your
  269. % k-means clustering as well instead of "cell2mat(Xon1)". Your output CAP
  270. % matrix will have size K x T, with K the number of CAPs. In order to go
  271. % back to the original space, you will apply:
  272. % CAP_original = (U*CAP')'
  273. % This will give you CAPs with a dimensionality K x V, i.e., what you would
  274. % have obtained using CAP analysis without PCA
  275. % This specifies the range of values over which to perform consensus
  276. % clustering: if you want to run parallel consensus clustering processes,
  277. % you should feed in different ranges to each call of the function
  278. K_range = 2:6;
  279. if exist(fullfile(SavePath,fancyName,['ConsensusClustering_Range' num2str(K_range(1)) '_to_' num2str(K_range(end)) '_' fancyName '.mat']))
  280. disp('-----------------------------------------------------');
  281. disp('Consensus Clustering was performed already !')
  282. disp('Load data...');
  283. load(fullfile(SavePath,fancyName,['ConsensusClustering_Range' num2str(K_range(1)) '_to_' num2str(K_range(end)) '_' fancyName '.mat']))
  284. disp(' ');
  285. disp('Data loaded successfully!');
  286. else
  287. % Have each of these run in a separate process on the server =)
  288. disp('Running Consensus Clustering...')
  289. % Umcomment if no PCA is performed
  290. %[Consensus] = CAP_ConsensusClustering(Xon1,K_range,'items',Pcc/100,N,'correlation');
  291. %Consensus clustering using PCA reduced dataset
  292. [Consensus] = CAP_ConsensusClustering({W},K_range,'items',Pcc/100,N,'correlation');
  293. %Plot Consensus Matrix
  294. ConsensusMatrixPlot(Consensus,SavePath,fancyName, K_range)
  295. % Calculates the quality metrics
  296. [CDF,PAC] = ComputeClusteringQuality(Consensus,K_range);
  297. % % Calculates the quality metrics
  298. % [~,Qual] = ComputeClusteringQuality(Consensus,[]);
  299. save(fullfile(SavePath,fancyName,['ConsensusClustering_Range' num2str(K_range(1)) '_to_' num2str(K_range(end)) '_' fancyName '.mat']))
  300. disp(' ');
  301. disp('Consensus Cluster successfully performed!');
  302. end
  303. Ttotal=etime(clock, Tstart);
  304. disp(['** Consensus clustering completed. Total time: ' num2str(Ttotal/60,'%3.1f') ' min.']);
  305. % Qual should be inspected to determine the best cluster number(s)
  306. CCPlot = figure;
  307. ax1 = axes(CCPlot);
  308. %set(CCPlot,'Visible','on');
  309. tmp_plot = bar(2:K_range(end),1-PAC);
  310. xlabel(get(tmp_plot(1),'Parent'),'Cluster number K');
  311. ylabel(get(tmp_plot(1),'Parent'),'Stability');
  312. xlim(get(tmp_plot(1),'Parent'),[2-0.6,K_range(end)+0.6]);
  313. ylim(get(tmp_plot(1),'Parent'),[0,1]);
  314. set(get(tmp_plot(1),'Parent'),'Box','off');
  315. custom_cm = cbrewer('seq','Reds',25);
  316. colormap(CCPlot,custom_cm(6:25,:));
  317. saveas(gcf,fullfile(SavePath,fancyName,'Stability.jpg'));
  318. saveas(gcf,fullfile(SavePath,fancyName,'Stability.fig'));
  319. disp(' ');
  320. disp('-----------------------------------------------------');
  321. disp(['Figure stability measures has been saved in ' SavePath]);
  322. disp(' ');
  323. disp('Please check stability measures');
  324. % You should fill this with the actual value
  325. %K_opt = 3;
  326. prompt = 'What is the optimal cluster size? ';
  327. K_opt = input(prompt);
  328. close;
  329. %% 5. Clustering into CAPs
  330. %[CAP,Disp,Std_Clusters,idx1,CorrDist,sfrac] = Run_Clustering(cell2mat(Xon1),...
  331. % K_opt,mask{1},brain_info{1},Pp,Pn,n_rep,idx_sep_seeds1,SeedType);
  332. % CAP_raw = CAP;
  333. [CAP,Disp,Std_Clusters,idx1,CorrDist,sfrac] = Run_Clustering_PCA(W,...
  334. K_opt,mask{1},brain_info{1},Pp,Pn,n_rep,idx_sep_seeds1,SeedType);
  335. %Plot
  336. % Computation of the similarity
  337. SimMat = corr(CAP',CAP');
  338. SimMat(isnan(SimMat))=0;
  339. % Similarity Plot
  340. imagesc(SimMat);
  341. tmp_cb2 = cbrewer('div','RdBu',1000,'spline'); % had to ad 'spline', otherwise error message (SH)
  342. tmp_cb2(tmp_cb2 < 0) = 0;
  343. colormap(flipud(tmp_cb2));
  344. % Arbitrary setting of probability scale
  345. caxis([-1 1]);
  346. axis('square','on');
  347. axis('on');
  348. % Add colorbar to the figure
  349. colorbar; % This adds the color scale
  350. saveas(gcf,fullfile(SavePath,fancyName,'Similarity.jpg'));
  351. saveas(gcf,fullfile(SavePath,fancyName,'Similarity.fig'));
  352. disp(' ');
  353. disp('-----------------------------------------------------');
  354. disp(['Figure Similarity matrix has been saved in ' SavePath]);
  355. disp(' ');
  356. close;
  357. %% 5.1. PCA Reconstruction
  358. CAP_original = (U*CAP') + mu;
  359. CAP = CAP_original';
  360. %% 6. Assignment of the frames from population 2
  361. % Parameter that governs the stringency of assignment: if Ap = 5%, we
  362. % assign a frame to a CAP if spatial correlation exceeds the 5th percentile
  363. % of the distribution of spatial correlations between the CAP, and its
  364. % constituting frames
  365. Ap = 5;
  366. idx2 = CAP_AssignFrames(CAP,cell2mat(Xon2),CorrDist,Ap)';
  367. %% 7. Computing metrics
  368. % The TR of your data in seconds
  369. TR = 1.3;
  370. [ExpressionMap1,Counts1,Entries1,Avg_Duration1,Duration1,TransitionProbabilities1,...
  371. From_Baseline1,To_Baseline1,Baseline_resilience1,Resilience1,Betweenness1,...
  372. InDegree1,OutDegree1,SubjectEntries1] = Compute_Metrics_simpler(idx1,...
  373. Indices1.kept.active,Indices1.scrubbedandactive,K_opt,TR);
  374. [ExpressionMap2,Counts2,Entries2,Avg_Duration2,Duration2,TransitionProbabilities2,...
  375. From_Baseline2,To_Baseline2,Baseline_resilience2,Resilience2,Betweenness2,...
  376. InDegree2,OutDegree2,SubjectEntries2] = Compute_Metrics_simpler(idx2,...
  377. Indices2.kept.active,Indices2.scrubbedandactive,K_opt,TR);
  378. %% Transition Probability (Visualization and Statistics)
  379. % 1. Plot metrics Transition matrix for all HC
  380. tmp_toplot = squeeze(mean(TransitionProbabilities1,3));
  381. tmp_toplot = tmp_toplot(3:end-1,3:end-1);
  382. % Make graph visible and plotting
  383. TMGraph=imagesc(tmp_toplot);
  384. tmp_cb = cbrewer('seq','Greys',1000);
  385. colormap(flipud(tmp_cb));
  386. clear tmp_toplot
  387. % Arbitrary setting of probability scale from 0 to 0.03
  388. caxis([0 0.03]);
  389. axis('square','on');
  390. axis('on');
  391. % Add colorbar to the figure
  392. colorbar; % This adds the color scale
  393. saveas(gcf,fullfile(SavePath,fancyName,'TransitionProbabilityMatrix_HC.jpg'));
  394. saveas(gcf,fullfile(SavePath,fancyName,'TransitionProbabilityMatrix_HC.fig'));
  395. close;
  396. % 2. Plot metrics Transition matrix for all CPP
  397. tmp_toplot = squeeze(mean(TransitionProbabilities2,3));
  398. tmp_toplot = tmp_toplot(3:end-1,3:end-1);
  399. % Make graph visible and plotting
  400. TMGraph=imagesc(tmp_toplot);
  401. tmp_cb = cbrewer('seq','Greys',1000);
  402. colormap(flipud(tmp_cb));
  403. clear tmp_toplot
  404. % Arbitrary setting of probability scale from 0 to 0.03
  405. caxis([0 0.03]);
  406. axis('square','on');
  407. axis('on');
  408. % Add colorbar to the figure
  409. colorbar; % This adds the color scale
  410. saveas(gcf,fullfile(SavePath,fancyName,'TransitionProbabilityMatrix_CPP.jpg'));
  411. saveas(gcf,fullfile(SavePath,fancyName,'TransitionProbabilityMatrix_CPP.fig'));
  412. close;
  413. disp(' ');
  414. disp('-----------------------------------------------------');
  415. disp(['Figure Transition Probability Matrix has been saved in ' SavePath]);
  416. disp(' ');
  417. %% Visualization of CAP and Frame Dynamics
  418. % 1. Dynamic state plotting
  419. % Makes the graph visible
  420. % Concatenates information from the different datasets
  421. tmp_toplot = [];
  422. ExpressionMap{1}=ExpressionMap1;
  423. ExpressionMap{2}=ExpressionMap2;
  424. for i = 1:n_datasets
  425. tmp_toplot = [tmp_toplot; ExpressionMap{i}; 0*ones(5,size(TC{1},1))];
  426. end
  427. tmp_toplot = tmp_toplot(1:end-5,:); % combines HC and CPPs and but between the dataframes 5 rows with 0, that they can be visually seperated.
  428. % Define custom colormap: [black for scrubbed (-1), white for non-retained (0), then CAP colors]
  429. custom_cm = cbrewer('qual','Set1',K_opt+1);
  430. custom_cm = [0.05,0.05,0.05;1,1,1;custom_cm];
  431. %Plot it
  432. imagesc(tmp_toplot);
  433. colormap((custom_cm));
  434. xlabel('Time [s]');
  435. ylabel('Subjects [-]');
  436. caxis([-1,K_opt+1]); %Adjust color axis to include scrubbed, non-retained, CAPs, and unassigned
  437. clear tmp_toplot
  438. % Generate line objects for the legend and assign colors
  439. L = gobjects(1, K_opt + 3); % Preallocate for legend lines (CAPs + Scrubbed + Non-retained + Unassigned)
  440. % Loop to create legend lines for CAPs
  441. for cap_idx = 1:K_opt
  442. % Create line for CAPs
  443. L(cap_idx) = line(nan(4,1), nan(4,1), 'LineWidth', 2, 'Color', custom_cm(cap_idx + 2, :)); % +2 skips black and white
  444. end
  445. % Add lines for 'Scrubbed' (-1), 'Non-retained' (0), and 'Unassigned'
  446. L(K_opt + 1) = line(nan(4,1), nan(4,1), 'LineWidth', 2, 'Color', custom_cm(1, :)); % Black for scrubbed (-1)
  447. L(K_opt + 2) = line(nan(4,1), nan(4,1), 'LineWidth', 2, 'Color', custom_cm(2, :)); % White for non-retained (0)
  448. L(K_opt + 3) = line(nan(4,1), nan(4,1), 'LineWidth', 2, 'Color', custom_cm(end, :)); % Last color for unassigned
  449. % Create the legend dynamically based on K_opt
  450. legend_entries = cell(1, K_opt + 3); % Preallocate cell array for legend entries (CAPs + 3 categories)
  451. for cap_idx = 1:K_opt
  452. legend_entries{cap_idx} = sprintf('CAP%d', cap_idx); % Generate CAP labels
  453. end
  454. legend_entries{K_opt + 1} = 'Scrubbed'; % Black for scrubbed (-1)
  455. legend_entries{K_opt + 2} = 'Non-retained'; % White for non-retained (0)
  456. legend_entries{K_opt + 3} = 'Unassigned'; % Color from colormap for unassigned (K_opt + 1)
  457. % Create the legend
  458. lgd = legend(L, legend_entries{:}, 'Location', 'best');
  459. lgd.FontSize = 10;
  460. lgd.Position(1) = 0.65;
  461. lgd.Position(2) = 0.5;
  462. % Ensure the legend is shown
  463. legend show;
  464. saveas(gcf,fullfile(SavePath,fancyName,'DynamicStates.jpg'));
  465. saveas(gcf,fullfile(SavePath,fancyName,'DynamicStates.fig'));
  466. close;
  467. disp(' ');
  468. disp('-----------------------------------------------------');
  469. disp(['Figure Dynamic States has been saved in ' SavePath]);
  470. disp(' ');
  471. % 2. Averaged by CAP HC
  472. % Define custom colormap using cbrewer (for example, Set1 colormap)
  473. custom_cm = cbrewer('qual', 'Set1', K_opt + 1); % Add 1 for an additional color if needed
  474. % Find unique CAPs in the matrix
  475. CAPs = unique(ExpressionMap1);
  476. % Preallocate a matrix to store the normalized sums for each column
  477. normalizedSums = zeros(length(CAPs), size(ExpressionMap1, 2)); % CAPs x Columns
  478. % Loop through each column and calculate the normalized counts
  479. for col = 1:size(ExpressionMap1, 2)
  480. for i = 1:length(CAPs)
  481. CAP_value = CAPs(i);
  482. count = sum(ExpressionMap1(:, col) == CAP_value); % Count occurrences of CAP in this column
  483. normalizedSums(i, col) = count / size(ExpressionMap1, 1); % Normalize by dividing by the number of rows
  484. end
  485. end
  486. % Exclude CAP0 and CAP-1 (if they exist)
  487. excludedCAPs = [-1, 0];
  488. validCAPs = ~ismember(CAPs, excludedCAPs); % Find CAPs that are not -1 or 0
  489. % Filter out rows and CAPs
  490. filteredNormalizedSums = normalizedSums(validCAPs, :);
  491. filteredCAPs = CAPs(validCAPs); % Corresponding CAP values
  492. % Visualization: Line plot (Only lines, no markers)
  493. figure;
  494. hold on;
  495. % Use custom colormap for the lines
  496. for i = 1:length(filteredCAPs)
  497. plot(1:size(ExpressionMap1, 2), filteredNormalizedSums(i, :), '-', 'LineWidth', 1.5, ...
  498. 'Color', custom_cm(i + 1, :), 'DisplayName', sprintf('CAP%d', filteredCAPs(i))); % +1 to skip first color if needed
  499. end
  500. hold off;
  501. % Customize the plot
  502. xlabel('Frames');
  503. ylabel('Average CAP expression');
  504. title('HC');
  505. legend('Location', 'best');
  506. grid on;
  507. set(gca, 'FontSize', 12);
  508. saveas(gcf,fullfile(SavePath,fancyName,'AverageCAPExpressionHC.jpg'));
  509. saveas(gcf,fullfile(SavePath,fancyName,'AverageCAPExpressionHC.fig'));
  510. close;
  511. disp(' ');
  512. disp('-----------------------------------------------------');
  513. disp(['Figure Average CAP eypression HC has been saved in ' SavePath]);
  514. disp(' ');
  515. % 3. Averaged by CAP CPP
  516. custom_cm2 = cbrewer('qual', 'Set1', K_opt + 1); % Add 1 for an additional color if needed
  517. % Find unique CAPs in the matrix
  518. CAPs2 = unique(ExpressionMap2);
  519. % Preallocate a matrix to store the normalized sums for each column
  520. normalizedSums2 = zeros(length(CAPs2), size(ExpressionMap2, 2)); % CAPs x Columns
  521. % Loop through each column and calculate the normalized counts
  522. for col = 1:size(ExpressionMap2, 2)
  523. for i = 1:length(CAPs2)
  524. CAP_value2 = CAPs2(i);
  525. count2 = sum(ExpressionMap2(:, col) == CAP_value2); % Count occurrences of CAP in this column
  526. normalizedSums2(i, col) = count2 / size(ExpressionMap2, 1); % Normalize by dividing by the number of rows
  527. end
  528. end
  529. % Exclude CAP0 and CAP-1 (if they exist)
  530. excludedCAPs2 = [-1, 0, K_opt+1];
  531. validCAPs2 = ~ismember(CAPs2, excludedCAPs2); % Find CAPs that are not -1 or 0
  532. % Filter out rows and CAPs
  533. filteredNormalizedSums2 = normalizedSums2(validCAPs2, :);
  534. filteredCAPs2 = CAPs2(validCAPs2); % Corresponding CAP values
  535. % Visualization: Line plot (Only lines, no markers)
  536. figure;
  537. hold on;
  538. % Use custom colormap for the lines
  539. for i = 1:length(filteredCAPs2)
  540. plot(1:size(ExpressionMap2, 2), filteredNormalizedSums2(i, :), '-', 'LineWidth', 1.5, ...
  541. 'Color', custom_cm2(i + 1, :), 'DisplayName', sprintf('CAP%d', filteredCAPs2(i))); % +1 to skip first color if needed
  542. end
  543. hold off;
  544. % Customize the plot
  545. xlabel('Frames');
  546. ylabel('Average CAP expression');
  547. title('CPP');
  548. legend('Location', 'best');
  549. grid on;
  550. set(gca, 'FontSize', 12);
  551. saveas(gcf,fullfile(SavePath,fancyName,'AverageCAPExpressionCPP.jpg'));
  552. saveas(gcf,fullfile(SavePath,fancyName,'AverageCAPExpressionCPP.fig'));
  553. close;
  554. disp(' ');
  555. disp('-----------------------------------------------------');
  556. disp(['Figure Average CAP eypression CPP has been saved in ' SavePath]);
  557. disp(' ');
  558. %% Quality Check 2 - Visualization
  559. % Number of subjects in each group
  560. nHC = size(ExpressionMap{1}, 1); % Number of HC subjects
  561. nCPP = size(ExpressionMap{2}, 1); % Number of CPP subjects
  562. % Initialize vectors for subject-wise ratios
  563. ratio_HC = zeros(nHC, 1);
  564. ratio_CPP = zeros(nCPP, 1);
  565. % 1. Ration unnassigned frames to assigned frames (CAPs) in Population
  566. % Compute ratios for CPP subjects
  567. for i = 1:nCPP
  568. assigned_frames = sum(ismember(ExpressionMap{2}(i, :), 1:K_opt)); % Assigned frames
  569. unassigned_frames = sum(ExpressionMap{2}(i, :) == (K_opt+1)); % Unassigned frames
  570. ratio_CPP(i) = (unassigned_frames / assigned_frames)
  571. end
  572. % Perform a one-sample t-test to check if the mean differs from zero
  573. [h, p_value1, ci, stats] = ttest(ratio_CPP);
  574. % Create figure
  575. figure;
  576. hold on;
  577. % Set X-axis position to center
  578. boxplot(ratio_CPP, 'Positions', 1.5, 'Labels', {'CPP'}, 'Whisker', 1.5, 'Colors', 'r', 'Symbol', 'ro', 'Widths', 0.6);
  579. set(findobj(gca,'Type','Line','Tag','Median'), 'Color', 'k', 'LineWidth', 2); % Highlight median
  580. % Scatter individual points (improved jittering for better visibility)
  581. x_CPP = 1.5 + 0.08 * randn(nCPP, 1); % Adjust X position for centering
  582. scatter(x_CPP, ratio_CPP, 90, 'r', 'filled', 'MarkerFaceAlpha', 0.6, 'MarkerEdgeColor', 'k'); % Improved dot styling
  583. % Formatting improvements
  584. ylabel('Ratio of Unassigned to Assigned Frames', 'FontSize', 14, 'FontWeight', 'bold');
  585. title('Subject-Level Ratio of Unassigned to Assigned Frames (CPP)', 'FontSize', 16, 'FontWeight', 'bold');
  586. ylim([0 1]); % Set Y-axis limit for better readability
  587. % Center the X-axis
  588. xlim([1 2]); % Set range to center the boxplot
  589. % Annotate p-value on the plot
  590. text(1.5, 9, sprintf('p = %.4f', p_value1), 'HorizontalAlignment', 'center', 'FontSize', 12, 'FontWeight', 'bold', 'Color', 'blue');
  591. % Remove grid for cleaner look
  592. grid off;
  593. % Save figure
  594. saveas(gcf, fullfile(SavePath, fancyName, 'Unassigned_to_assigned_frames_CPP.jpg'));
  595. saveas(gcf, fullfile(SavePath, fancyName, 'Unassigned_to_assigned_frames_CPP.fig'));
  596. close;
  597. % 2. Ration scrubbed (but active) frames to assigned frames (CAPs)
  598. % Compute ratios for HC subjects
  599. for i = 1:nHC
  600. assigned_frames = sum(ismember(ExpressionMap{1}(i, :), 1:K_opt)); % Assigned frames
  601. scrubbed_frames = sum(ExpressionMap{1}(i, :) == -1); % Scrubbed frames
  602. ratio_HC(i) = (scrubbed_frames / assigned_frames) * 100; % Convert to percentage
  603. end
  604. % Compute ratios for CPP subjects
  605. for i = 1:nCPP
  606. assigned_frames = sum(ismember(ExpressionMap{2}(i, :), 1:K_opt)); % Assigned frames
  607. scrubbed_frames = sum(ExpressionMap{2}(i, :) == -1); % Scrubbed frames
  608. ratio_CPP(i) = (scrubbed_frames / assigned_frames) * 100; % Convert to percentage
  609. end
  610. % Combine data and create group labels
  611. all_ratios = [ratio_HC; ratio_CPP]; % Merge HC and CPP ratios
  612. group_labels = [ones(nHC, 1); 2 * ones(nCPP, 1)]; % 1 for HC, 2 for CPP
  613. % Non-parametric test (Mann-Whitney U test)
  614. [p_value2, h, stats] = ranksum(ratio_HC, ratio_CPP);
  615. % Create figure
  616. figure;
  617. hold on;
  618. % Corrected boxplot without manual 'positions' parameter
  619. boxplot(all_ratios, group_labels, 'Labels', {'HC', 'CPP'}, ...
  620. 'Whisker', 1.5, 'Colors', 'rb', 'Symbol', 'ro', 'Widths', 0.6);
  621. set(findobj(gca,'Type','Line','Tag','Median'), 'Color', 'k', 'LineWidth', 2); % Highlight median
  622. % Scatter individual points (jittered for better visibility)
  623. x_HC = 1 + 0.08 * randn(nHC, 1); % Jitter HC points
  624. x_CPP = 2 + 0.08 * randn(nCPP, 1); % Jitter CPP points
  625. scatter(x_HC, ratio_HC, 90, 'b', 'filled', 'MarkerFaceAlpha', 0.6, 'MarkerEdgeColor', 'k'); % HC points
  626. scatter(x_CPP, ratio_CPP, 90, 'r', 'filled', 'MarkerFaceAlpha', 0.6, 'MarkerEdgeColor', 'k'); % CPP points
  627. % Formatting improvements
  628. ylabel('Ratio of Scrubbed to Assigned Frames (%)', 'FontSize', 14, 'FontWeight', 'bold');
  629. title('Scrubbed (but active) to Assigned Frames (HC vs. CPP)', 'FontSize', 16, 'FontWeight', 'bold');
  630. ylim([0 100]); % Set Y-axis limit for better readability
  631. yticks(0:10:100); % Set ticks at intervals of 10%
  632. % Annotate p-value on the plot
  633. text(1.5, 90, sprintf('p = %.4f', p_value2), 'HorizontalAlignment', 'center', ...
  634. 'FontSize', 12, 'FontWeight', 'bold', 'Color', 'blue');
  635. % Remove grid for cleaner look
  636. grid off;
  637. % Save figure
  638. saveas(gcf, fullfile(SavePath, fancyName, 'Scrubbed_to_assigned_frames_HC_CPP.jpg'));
  639. saveas(gcf, fullfile(SavePath, fancyName, 'Scrubbed_to_assigned_frames_HC_CPP.fig'));
  640. close;
  641. %% 7. Save Metrics
  642. % General information on the project
  643. OverallInfo.ProjectTitle = fancyName;
  644. OverallInfo.NumberTimePoints = size(TC{1},1);%handles.SubjSize.TP;
  645. OverallInfo.NumberVoxels = size(TC{1},2); %handles.SubjSize.VOX;
  646. OverallInfo.NumberSubjects = N_Subj; %handles.n_subjects;
  647. OverallInfo.TR = TR; %handles.TR;
  648. Parameters.Inputs.DataHeader = brain_info;%handles.brain_info;
  649. Parameters.Inputs.Mask = mask;
  650. Parameters.Inputs.Seeds = Seed;
  651. Parameters.SpatioTemporalSelection.IsSeedFree = 0; %handles.is_seed_free;
  652. Parameters.SpatioTemporalSelection.NumberSeeds = size(seedName,2); %handles.n_seed;
  653. Parameters.SpatioTemporalSelection.TypeEventRetainedPerSeed = SignMatrix;
  654. Parameters.SpatioTemporalSelection.SeedType = SeedType;
  655. Parameters.SpatioTemporalSelection.MotionThreshold = Tmot;
  656. Parameters.SpatioTemporalSelection.SelectionMode = SelMode;
  657. Parameters.SpatioTemporalSelection.FrameSelectionParameter = T;
  658. Parameters.KMeansClustering.IsConsensusRun = 1;% handles.is_consensus_clustering;
  659. Parameters.KMeansClustering.MaxClusterNumber = 6; %handles.Kmax; change this to the respective Kmax.
  660. Parameters.KMeansClustering.PercentageDataPerFold = Pcc; %handles.PCC;
  661. Parameters.KMeansClustering.NumberRepetitions = n_rep;
  662. Parameters.KMeansClustering.NumberClusters = K_opt; %handles.K;
  663. Parameters.KMeansClustering.PercentagePositiveValuedVoxelsClustered = Pp;
  664. Parameters.KMeansClustering.PercentageNegativeValuedVoxelsClustered = Pn;
  665. Outputs.SpatioTemporalSelection.RetainedFramesPerSeed{1} = idx_sep_seeds1;
  666. Outputs.SpatioTemporalSelection.RetainedFramesPerSeed{2} = idx_sep_seeds2;
  667. Outputs.SpatioTemporalSelection.Indices{1}=Indices1;
  668. Outputs.SpatioTemporalSelection.Indices{2}=Indices2; %hier war vorher eine 1
  669. Outputs.SpatioTemporalSelection.PercentageRetainedFrames = RetainedPercentage;
  670. Outputs.SpatioTemporalSelection.AverageCorrelationMap = AvgSeedMap;
  671. Outputs.KMeansClustering.ConsensusQuality = PAC; %handles.ConsensusQuality; CHECK IF THAT'S TRUE
  672. Outputs.KMeansClustering.CoActivationPatternsDispersion = Disp;
  673. Outputs.KMeansClustering.CoActivationPatterns = CAP;
  674. Outputs.KMeansClustering.CoActivationPatternsZScored = CAP_Zscore(CAP);
  675. Outputs.KMeansClustering.CoActivationPatternsSTD = Std_Clusters; %handles.STDCAP;
  676. Outputs.KMeansClustering.AssignmentsToCAPs{1} = idx1;
  677. Outputs.KMeansClustering.AssignmentsToCAPs{2} = idx2;
  678. Outputs.Metrics.CAPExpressionIndices{1} = ExpressionMap1;
  679. Outputs.Metrics.CAPExpressionIndices{2} = ExpressionMap2;
  680. Outputs.Metrics.Occurrences{1} = Counts1;
  681. Outputs.Metrics.Occurrences{2} = Counts2;
  682. Outputs.Metrics.NumberEntries{1} = Entries1;
  683. Outputs.Metrics.NumberEntries{2} = Entries2;
  684. Outputs.Metrics.AverageExpressionDuration{1} = Avg_Duration1;
  685. Outputs.Metrics.AverageExpressionDuration{2} = Avg_Duration2;
  686. Outputs.Metrics.AllExpressionDurations{1} = Duration1;
  687. Outputs.Metrics.AllExpressionDurations{2} = Duration2;
  688. Outputs.Metrics.TransitionProbabilities{1} = TransitionProbabilities1;
  689. Outputs.Metrics.TransitionProbabilities{2} = TransitionProbabilities2;
  690. Outputs.Metrics.FractionCAPFramesPerSeedCombination = sfrac;
  691. Outputs.Metrics.CAPEntriesFromBaseline{1} = From_Baseline1;
  692. Outputs.Metrics.CAPEntriesFromBaseline{2} = From_Baseline2;
  693. Outputs.Metrics.CAPExitsToBaseline{1} = To_Baseline1;
  694. Outputs.Metrics.CAPExitsToBaseline{2} = To_Baseline2;
  695. Outputs.Metrics.CAPResilience{1} = Resilience1;
  696. Outputs.Metrics.CAPResilience{2} = Resilience2;
  697. Outputs.Metrics.BaselineResilience{1} = Baseline_resilience1;
  698. Outputs.Metrics.BaselineResilience{2} = Baseline_resilience2;
  699. Outputs.Metrics.BetweennessCentrality{1} = Betweenness1;
  700. Outputs.Metrics.BetweennessCentrality{2} = Betweenness2;
  701. Outputs.Metrics.CAPInDegree{1} = InDegree1;
  702. Outputs.Metrics.CAPInDegree{2} = InDegree2;
  703. Outputs.Metrics.CAPOutDegree{1} = OutDegree1;
  704. Outputs.Metrics.CAPOutDegree{2} = OutDegree2;
  705. Outputs.Metrics.SubjectCounts{1} = SubjectEntries1;
  706. Outputs.Metrics.SubjectCounts{2} = SubjectEntries2;
  707. HeavyOutputs.SpatioTemporalSelection.ClusteredFrames{1} = Xon1; % Are this 3 lines necessary to be saved?
  708. HeavyOutputs.SpatioTemporalSelection.ClusteredFrames{2} = Xon2;%Xonp?
  709. HeavyOutputs.KMeansClustering.Consensus = Consensus;
  710. % Saves NIFTI files storing the CAPs in MNI space
  711. ReferencePopulation = 1;
  712. CAPToNIFTI(CAP,...
  713. mask{ReferencePopulation},brain_info{ReferencePopulation},...
  714. fullfile(SavePath,fancyName),['CAP_NIFTI_',fancyName]);
  715. CAPToNIFTI(CAP_Zscore(CAP),...
  716. mask{ReferencePopulation},brain_info{ReferencePopulation},...
  717. fullfile(SavePath,fancyName),['CAP_NIFTI_ZScored_',fancyName]);
  718. % Saves the different variables from the program
  719. save(fullfile(SavePath,fancyName),'OverallInfo','Parameters','Outputs','HeavyOutputs','brain','-v7.3');
  720. %save(fullfile(SavePath,fancyName),'OverallInfo','Parameters','Outputs','brain','-v7.3');
  721. disp('-----------------------------------------------------');
  722. disp('CAPs computed and saved successfully!');
  723. disp(' ');
  724. disp('Results are saved in: ');
  725. disp([SavePath]);

Script_twopop_PCA_HC_ref_SH.m at commit 1240c94, no license · at the source

Overview

Authors: Salome Häuselmann1,2,3, Anna Wyss1,3, Samantha Weber1,4,5, Nicolas Gninenko1,6, Cristina Concetti6, Eliane Müller1,2,6, Rupert Bruckmaier7, Josef Gross7, Nina Bischoff1, Chantal Berna8, Martin grosse Holtforth1,9, Selma Aybek6
  1. Psychosomatic Medicine, Department of Neurology, Inselspital, Bern University Hospital, University of Bern, 3010 Bern, Switzerland
  2. Graduate School of Cellular and Biomedical Sciences (GCB), University of Bern, 3012 Bern, Switzerland
  3. Translational Imaging Center (TIC), Swiss Institute for Translational and Entrepreneurial Medicine, 3010 Bern, Switzerland
  4. Department of Adult Psychiatry and Psychotherapy, University Hospital of Psychiatry Zurich, University of Zurich, 8032 Zurich, Switzerland
  5. Faculty of Medicine, University of Zurich, 8032 Zurich, Switzerland
  6. Department of Neurology, Faculty of Science and Medicine, University of Fribourg, 1700 Fribourg, Switzerland
  7. Veterinary Physiology, Vetsuisse Faculty, University of Bern, 3012 Bern, Switzerland
  8. Center for Integrative and Complementary Medicine, Department of Anesthesiology, Lausanne University Hospital, 1011 Lausanne, Switzerland
  9. Institute of Psychology, University of Bern, 3012 Bern, Switzerland
Journal: Brain communications, volume 8, issue 2, article fcag121
Dates: received 25 October 2025; accepted 2 April 2026; published online 3 April 2026
Type: Research article · Language: English
License: CC BY
Identifiers: DOI 10.1093/braincomms/fcag121 · PMID 41978789 · PMCID PMC13070617 · OpenAlex W7149391556
Open access: gold, a free copy (OpenAlex)
Status: code verified
Categories: fMRI (modality), human (organism), pain (population), clinical / translational (subfield)
Methods: Connectivity, Spectral & time-frequency, Statistics, Smoothing, state filtering, decompositions, Machine learning, Preprocessing, fMRI & imaging
Keywords: chronic primary pain, functional MRI, co-activation patterns, brain dynamics, stress response
Topic: Pain Mechanisms and Treatments (Physiology, Medicine), according to OpenAlex
Funding: Swiss National Science Foundation (176985, PP00P3_176985)
Citations: cited by 1 paper (Europe PMC); 74 references in the paper

Abstract

Chronic primary pain occurs without an identifiable causal disease and is marked by persistent pain, emotional distress and functional disability. The anterior insular cortex, involved in salience processing and integration of sensory, emotional and cognitive aspects of pain, has been implicated in neural processes linking pain and stress responses. This study investigates whether specific brain state dynamics, using the anterior insula as a seed region, are associated with chronic primary pain and examines their associations with pain- and stress-related measures. Resting-state functional MRI, stress biomarkers (cortisol and alpha-amylase), a pain sensitivity test, as well as subjective measures of stress and pain were collected from patients with chronic primary pain (N = 30) and healthy controls (N = 30). Co-activation pattern analysis was used to identify brain states with the anterior insula as the seed region and to assess group differences in the temporal characteristics of these brain states. Partial least squares analysis was applied to investigate multivariate associations between specific temporal brain state characteristics and pain- and stress-related measures. Three anterior insula–seeded co-activation patterns (brain states) were identified in healthy controls. In the first co-activation pattern, the anterior insula co-activated with the default mode network; in the second, with the salience-somatomotor network; and in the third, with the visual network. Chronic primary pain patients and healthy controls differed significantly in temporal brain state characteristics, namely in the relative number of entries into co-activation pattern one (pFDR = 0.002) and two (pFDR = 0.022), and the relative occurrence of co-activation patterns one (pFDR = 0.022) and two (pFDR = 0.022). Furthermore, in chronic primary pain patients, perceived stress scores and cortisol were significantly associated with these specific temporal brain state characteristics (P = 0.002), whereas no associations were found with pain-related measures. Together, these findings suggest that in chronic primary pain, reduced coupling of the anterior insula with the default mode network and increased coupling of the anterior insula with salience-related networks are associated with psychophysiological stress markers. These brain state dynamics may potentially represent a neural correlate of altered stress processing in chronic primary pain.

Reproduced under the paper's license (CC BY), from the paper cited above.

Repository

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

FND-ResearchGroup/CAP_in_CPP

License: none: the authors keep all their rights
State: the link answers, verified on 28 September 2026
Evidence: files inventoried
Commit: 1240c94a8fdfea5a597d5aab584649140b820c0b, 30 March 2026
Languages: R (3), MATLAB (2), Jupyter (1)
Size: 10 files, 6 scripts
Software Heritage: not archived
Found in: “Data availability”
Holds: README, 2 notebooks
Not found: license file, CITATION.cff, environment file, tests, continuous integration, documentation
Tools: car (3 files), cowplot (3 files), ggplot2 (3 files), ggpubr (3 files), lme4 (3 files), lmerTest (3 files), multcomp (3 files), reshape2 (3 files), rstatix (3 files), tidyverse (3 files), easystats (1 file), Statistics and Machine Learning Toolbox (1 file), NiBabel (1 file), NumPy (1 file), pandas (1 file), Plotly (1 file), psych (1 file), SciPy (1 file)
Availability: 1 check, the latest on 28 September 2026: the link answers
  • 28 September 2026: the link answers
7 files

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;
  • 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

The data are not publicly available but can be shared upon request. The TbCAPs toolbox is publicly available at https://github.com/MIPLabCH/TbCAPs, and the PLS Toolbox can be accessed at https://github.com/FND-ResearchGroup/myPLS_SL. Additional codes used for data analysis are available at https://github.com/FND-ResearchGroup/CAP_in_CPP.

Reproduced under the paper's license (CC BY), from the paper cited above.

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, 28 September 2026: the first record

Recorded: type, language, journal, volume, issue, pages, dates, 12 authors, 5 keywords, 1 funder, 69 references.

Cite

This paper

Häuselmann, S., Wyss, A., Weber, S., Gninenko, N., Concetti, C., Müller, E., Bruckmaier, R., Gross, J., Bischoff, N., Berna, C., grosse Holtforth, M., & Aybek, S. (2026). Anterior insular co-activation patterns associated with stress markers in chronic primary pain. Brain communications, 8(2), fcag121. https://doi.org/10.1093/braincomms/fcag121

BibTeX

@article{hauselmann2026anterior,
author = {Häuselmann, Salome and Wyss, Anna and Weber, Samantha and Gninenko, Nicolas and Concetti, Cristina and Müller, Eliane and Bruckmaier, Rupert and Gross, Josef and Bischoff, Nina and Berna, Chantal and grosse Holtforth, Martin and Aybek, Selma},
title = {{Anterior insular co-activation patterns associated with stress markers in chronic primary pain}},
journal = {Brain communications},
year = {2026},
month = apr,
volume = {8},
number = {2},
pages = {fcag121},
publisher = {Oxford University Press},
issn = {2632-1297},
doi = {10.1093/braincomms/fcag121},
url = {https://doi.org/10.1093/braincomms/fcag121},
pmid = {41978789},
pmcid = {PMC13070617}
}

RIS

TY - JOUR
AU - Häuselmann, Salome
AU - Wyss, Anna
AU - Weber, Samantha
AU - Gninenko, Nicolas
AU - Concetti, Cristina
AU - Müller, Eliane
AU - Bruckmaier, Rupert
AU - Gross, Josef
AU - Bischoff, Nina
AU - Berna, Chantal
AU - grosse Holtforth, Martin
AU - Aybek, Selma
TI - Anterior insular co-activation patterns associated with stress markers in chronic primary pain
T2 - Brain communications
J2 - Brain Commun
PY - 2026
DA - 2026/04/03
VL - 8
IS - 2
SP - fcag121
SN - 2632-1297
PB - Oxford University Press
DO - 10.1093/braincomms/fcag121
UR - https://doi.org/10.1093/braincomms/fcag121
LA - en
ER -

CSL-JSON

{
"id": "10.1093/braincomms/fcag121",
"type": "article-journal",
"title": "Anterior insular co-activation patterns associated with stress markers in chronic primary pain",
"container-title": "Brain communications",
"author": [
{
"family": "Häuselmann",
"given": "Salome"
},
{
"family": "Wyss",
"given": "Anna"
},
{
"family": "Weber",
"given": "Samantha"
},
{
"family": "Gninenko",
"given": "Nicolas"
},
{
"family": "Concetti",
"given": "Cristina"
},
{
"family": "Müller",
"given": "Eliane"
},
{
"family": "Bruckmaier",
"given": "Rupert"
},
{
"family": "Gross",
"given": "Josef"
},
{
"family": "Bischoff",
"given": "Nina"
},
{
"family": "Berna",
"given": "Chantal"
},
{
"family": "grosse Holtforth",
"given": "Martin"
},
{
"family": "Aybek",
"given": "Selma"
}
],
"container-title-short": "Brain Commun",
"volume": "8",
"issue": "2",
"page": "fcag121",
"DOI": "10.1093/braincomms/fcag121",
"PMID": "41978789",
"PMCID": "PMC13070617",
"ISSN": "2632-1297",
"publisher": "Oxford University Press",
"URL": "https://doi.org/10.1093/braincomms/fcag121",
"language": "en",
"issued": {
"date-parts": [
[
2026,
4,
3
]
]
}
}

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.1016/j.nicl.2026.104012 [code]
Structural-functional multilayer brain network properties and outcome of combined repetitive transcranial magnetic stimulation and psychotherapy for obsessive-compulsive disorder.
Journal: NeuroImage. Clinical
In common: psych, rstatix, car, 11 other tools, fMRI, 1 reference
[2] doi:10.1093/bioinformatics/btag592 [code]
Network-based stratification of allele-specific expression reveals patient subgroups in Huntington's disease.
Journal: Bioinformatics (Oxford, England)
In common: multcomp, rstatix, car, 10 other tools
[3] doi:10.1162/imag.a.1245 [code]
Towards precision EEG connectomics: Evaluating the benefits of dense sampling.
Journal: Imaging neuroscience (Cambridge, Mass.)
In common: psych, rstatix, lmerTest, 11 other tools
[4] doi:10.1093/braincomms/fcag146 [code]
Convergent structural brain alterations in chronic pain: a multi-metric individual participant data meta-analysis.
Journal: Brain communications
In common: multcomp, psych, car, 5 other tools, pain, 2 references
[5] doi:10.1523/eneuro.0076-26.2026 [code]
Exogenously Driven Neural Reactivation of Spatially Matching Visual Working-Memory Contents.
Journal: eNeuro
In common: multcomp, rstatix, car, 9 other tools
[6] doi:10.1093/cercor/bhag077 [code]
The longitudinal development of intrinsic timescales in infancy and their relation to alpha brain rhythm.
Journal: Cerebral cortex (New York, N.Y. : 1991)
In common: multcomp, psych, easystats, 9 other tools
[7] doi:10.1016/j.neuroimage.2026.122115 [code]
Midfrontal theta power relates to response speeding following frustrative nonreward.
Journal: NeuroImage
In common: psych, rstatix, easystats, 8 other tools
[8] doi:10.1093/brain/awag080 [code]
Early glymphatic failure in AppNL-F knock-in mice is linked to parenchymal border macrophages loss.
Journal: Brain : a journal of neurology
In common: multcomp, psych, rstatix, 7 other tools
[9] doi:10.1162/imag.a.1321 [code]
Phase similarity between similar objects indicates representational merging across retrieval training but not sleep.
Journal: Imaging neuroscience (Cambridge, Mass.)
In common: rstatix, easystats, car, 9 other tools
[10] doi:10.1038/s41380-026-03694-1 [code]
Targeting cortico-striatal-amygdalar networks via theta-band frontoparietal synchronization in opioid use disorder: a randomized tACS-fMRI Trial.
Journal: Molecular psychiatry
In common: multcomp, lmerTest, lme4, 7 other tools, pain, fMRI, clinical / translational

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.

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.