OSCR

Dynamic multivariate patterns of brain structure-neuropsychiatric symptom associations in long COVID.

Code ↔ Paper

The paper beside its authors' code: matches between them have not been computed for this paper yet.

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 · 520 lines · 17 KB · GPL-3.0

  1. function cfg = cfg_defaults(cfg, varargin)
  2. % cfg_defaults
  3. %
  4. % Set defaults in your configuration (`cfg`) structure which will define
  5. % the settings of your analysis (e.g., machine, framework, statistical
  6. % inference). Use this function to update and add all necessary defaults to
  7. % your `cfg`. If you defined anything in your `cfg` before calling the
  8. % function, it won't overwrite those values. The path to the project folder
  9. % should be always defined in your `cfg` or passed as varargin, otherwise
  10. % the function throws an error. All the other fields are optional and can
  11. % be filled up by `cfg_defaults`.
  12. %
  13. % No results will be stored in the cfg structure. See [res_defaults](../res_defaults)
  14. % for more information on results.
  15. %
  16. % !!! note "Warning"
  17. % We strongly advise to inspect the output of `cfg_defaults` to make
  18. % sure that the defaults are set as expected.
  19. %
  20. % # Syntax
  21. % cfg = cfg_defaults(cfg, varargin)
  22. %
  23. % # Inputs
  24. % cfg:: struct
  25. % varargin:: name-value pairs
  26. % additional parameters can be set via name-value pairs with dot notation
  27. % supported (e.g., 'frwork.split.nout', 5)
  28. %
  29. % # Outputs
  30. % cfg:: struct
  31. % configuration structure that has been updated with defaults
  32. %
  33. % # Examples
  34. %
  35. % % Example 1
  36. % [X, Y, wX, wY] = generate_data(1000, 100, 100, 10, 10, 1);
  37. %
  38. % ---
  39. % See also: [cfg](../../cfg), [res_defaults](../res_defaults/)
  40. %
  41. %_______________________________________________________________________
  42. % Copyright (C) 2022 University College London
  43. % Written by Agoston Mihalik ([email hidden])
  44. % $Id$
  45. % This file is part of CCA/PLS Toolkit.
  46. %
  47. % CCA/PLS Toolkit is free software: you can redistribute it and/or modify
  48. % it under the terms of the GNU General Public License as published by
  49. % the Free Software Foundation, either version 3 of the License, or
  50. % (at your option) any later version.
  51. %
  52. % CCA/PLS Toolkit is distributed in the hope that it will be useful,
  53. % but WITHOUT ANY WARRANTY; without even the implied warranty of
  54. % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  55. % GNU General Public License for more details.
  56. %
  57. % You should have received a copy of the GNU General Public License
  58. % along with CCA/PLS Toolkit. If not, see <https://www.gnu.org/licenses/>.
  59. def = parse_input([], varargin{:});
  60. % Initialize cfg
  61. if isempty(cfg)
  62. cfg = struct();
  63. end
  64. cfg = assign_defaults(cfg, def);
  65. %----- Primary defaults
  66. % Get toolkit version from git commit
  67. [~, def.env.commit] = system('git rev-parse HEAD');
  68. % Framework
  69. def.frwork.name = 'holdout'; % holdout/permutation
  70. def.frwork.flag = ''; % string to specify analysis in folder name
  71. % Machine
  72. def.machine.name = 'spls';
  73. % Computer environment
  74. def.env.comp = 'local'; % local/cluster
  75. if ismac
  76. def.env.OS = 'mac';
  77. elseif isunix
  78. def.env.OS = 'unix';
  79. elseif ispc
  80. def.env.OS = 'pc';
  81. end
  82. % Verbosity level
  83. % 1: detailed progress update with elapsed time info
  84. % 2: detailed progress update
  85. % 3: minimal progress update
  86. def.env.verbose = 2;
  87. % Data block structure (see exchangeability blocks below)
  88. def.data.block = 0;
  89. % Data modalities and confounds
  90. def.data.mod = {'X' 'Y'};
  91. def.data.conf = 0;
  92. % Update fields
  93. cfg = assign_defaults(cfg, def);
  94. % Check that path to project folder exists
  95. if ~isfield(cfg, 'dir') || ~isfield(cfg.dir, 'project')
  96. error('Path to project folder should be given.')
  97. end
  98. %----- Secondary defaults
  99. % Data train-test splitting
  100. switch cfg.frwork.name
  101. case 'holdout'
  102. % Multiple holdout framework (see Monteiro et al 2016 J Neurosci Methods)
  103. def.frwork.split.nout = 5;
  104. def.frwork.split.propout = 0.2;
  105. def.frwork.split.nin = 5;
  106. def.frwork.split.propin = 0.2;
  107. case 'permutation'
  108. % Permutation framework (see Smith et al Nat Neurosci 2015)
  109. % without train-test splitting
  110. def.frwork.split.nout = 1;
  111. end
  112. % Number of permutations in statistical inference
  113. def.stat.nperm = 1000;
  114. % Metrics to evaluate machines
  115. def.machine.metric = {'trcorrel' 'correl'}; % correlation between projections
  116. if strcmp(cfg.machine.name, 'spls')
  117. def.machine.metric = [def.machine.metric {'simwx' 'simwy'}]; % stability of weights
  118. end
  119. % Update fields
  120. cfg = assign_defaults(cfg, def);
  121. % Similarity metric
  122. if any(contains(cfg.machine.metric, 'sim'))
  123. if strcmp(cfg.machine.name, 'spls')
  124. def.machine.simw = 'overlap-corrected';
  125. else
  126. def.machine.simw = 'correlation-Pearson';
  127. end
  128. end
  129. % Statistical inference
  130. if cfg.stat.nperm ~= 0
  131. def.stat.crit = 'correl';
  132. def.stat.perm = 'train+test'; % 'train'
  133. def.stat.alpha = 0.05;
  134. end
  135. % Update fields
  136. cfg = assign_defaults(cfg, def);
  137. % Deflation formulation
  138. if ~isfield(cfg.frwork, 'nlevel') || cfg.frwork.nlevel > 1
  139. if ismember(cfg.machine.name, {'pls' 'spls'})
  140. def.defl.name = 'pls-modeA';
  141. else
  142. cfg.defl.name = 'generalized'; % overwrite user's option to be safe
  143. end
  144. % Deflation strategy with data splitting
  145. def.defl.crit = 'correl';
  146. end
  147. % Filename suffix on cluster or set default
  148. if strcmp(cfg.env.comp, 'cluster') && ~isempty(getenv('SGE_TASK_ID')) ...
  149. && ~strcmp(getenv('SGE_TASK_ID'), 'undefined')
  150. def.env.fileend = ['_' num2str(getenv('SGE_TASK_ID'))];
  151. elseif strcmp(cfg.env.comp, 'cluster') && ~isempty(getenv('SLURM_ARRAY_TASK_ID'))
  152. def.env.fileend = ['_' num2str(getenv('SLURM_ARRAY_TASK_ID'))];
  153. else
  154. def.env.fileend = '_1';
  155. end
  156. % Compression setting for saving files
  157. def.env.save.compression = 1;
  158. % Exchangeability blocks (EB) for restricted partitioning and permutation
  159. % (see Winkler et al 2015 Neuroimage, https://fsl.fmrib.ox.ac.uk/fsl/fslwiki/PALM)
  160. if cfg.data.block
  161. load(fullfile(cfg.dir.project, 'data', 'EB.mat'))
  162. if ~exist('EB', 'var')
  163. error('EB matrix not available');
  164. end
  165. % Columns of EB for restricted partitioning
  166. def.data.EB.split = 1:size(EB, 2);
  167. % Columns of EB for restricted permutations
  168. def.data.EB.stat = 1:size(EB, 2);
  169. end
  170. % Data path and preprocessing
  171. if cfg.data.conf
  172. mod = [cfg.data.mod {'C'}]; % modalities including confound matrix
  173. else
  174. mod = cfg.data.mod;
  175. end
  176. for i=1:numel(mod)
  177. def.data.(mod{i}).fname = fullfile(cfg.dir.project, 'data', [mod{i} '.mat']);
  178. def.data.(mod{i}).preproc = {'impute' 'zscore'};
  179. end
  180. if cfg.data.conf
  181. for i=1:numel(cfg.data.mod)
  182. def.data.(cfg.data.mod{i}).preproc = [def.data.(cfg.data.mod{i}).preproc {'deconf'}];
  183. end
  184. end
  185. % Update fields
  186. cfg = assign_defaults(cfg, def);
  187. % Data processing in details
  188. for i=1:numel(mod)
  189. if ismember('impute', cfg.data.(mod{i}).preproc)
  190. def.data.(mod{i}).impute = 'median';
  191. end
  192. if ismember('deconf', cfg.data.(mod{i}).preproc)
  193. def.data.(mod{i}).deconf = 'standard';
  194. end
  195. end
  196. % Seed options for reproducibility
  197. % this is important in case multiple jobs are started simultaneously on a
  198. % cluster, avoids jobs running same hyperparameters and permutations
  199. % simply uses the number of the fileend as seed
  200. % default, shuffle, number or struct returned by rng
  201. def.env.seed.split = 'default';
  202. tmp = regexp(cfg.env.fileend, '_(\d+)\>', 'tokens');
  203. def.env.seed.model = cellfun(@str2num, tmp{1});
  204. def.env.seed.perm = 'default';
  205. % Load data
  206. if exist(cfg.data.X.fname, 'file') && exist(cfg.data.Y.fname, 'file')
  207. for m=1:numel(mod)
  208. % Access data without loading into memory
  209. matobj = matfile(cfg.data.(mod{m}).fname);
  210. if ismember(who(matobj), mod{m})
  211. data.(mod{m}) = matobj;
  212. else
  213. error('%s matrix not available in %s.', mod{m}, cfg.data.(mod{m}).fname);
  214. end
  215. end
  216. else
  217. error('X and Y input data cannot be found in path, check your data folder.');
  218. end
  219. % Update fields
  220. cfg = assign_defaults(cfg, def);
  221. %----- Defaults set based on X, Y
  222. % Maximum number of associative effects
  223. if strcmp(cfg.defl.name, 'pls-regression')
  224. def.frwork.nlevel = min(size(data.X, 'X'));
  225. else
  226. def.frwork.nlevel = min(cellfun(@(x) min(size(data.(x), x)), cfg.data.mod));
  227. end
  228. if isfield(cfg.frwork, 'nlevel') && cfg.frwork.nlevel > def.frwork.nlevel
  229. cfg.frwork.nlevel = def.frwork.nlevel;
  230. end
  231. % Data dimensionality
  232. for i=1:numel(cfg.data.mod)
  233. if ~isfield(cfg.data, 'nsubj')
  234. cfg.data.nsubj = size(data.(cfg.data.mod{i}), cfg.data.mod{i}, 1);
  235. elseif size(data.(cfg.data.mod{i}), cfg.data.mod{i}, 1) ~= cfg.data.nsubj
  236. error('The number of examples do not match across data modalities');
  237. end
  238. cfg.data.(cfg.data.mod{i}).nfeat = size(data.(cfg.data.mod{i}), cfg.data.mod{i}, 2);
  239. end
  240. % Initialize machine hyperparameters
  241. def.machine.param.name = {};
  242. % Update fields
  243. cfg = assign_defaults(cfg, def);
  244. % Grid search settings for machines
  245. for i=1:numel(cfg.data.mod)
  246. m = lower(cfg.data.mod{i}); % shorthand for modality in lowercase
  247. switch cfg.machine.name
  248. case {'pls' 'spls'}
  249. % Hyperparameter name
  250. if isempty(cfg.machine.param.name)
  251. cfg.machine.param.name = {['L1' m]};
  252. elseif ~ismember(['L1' m], cfg.machine.param.name)
  253. cfg.machine.param.name = [cfg.machine.param.name {['L1' m]}];
  254. end
  255. if strcmp(cfg.machine.name, 'pls')
  256. % Hyperparameter type
  257. cfg.machine.param.type = 'matched';
  258. % No grid search as L1 regularizaion used with fix
  259. % parameter outside of SPLS range
  260. elseif strcmp(cfg.machine.name, 'spls')
  261. % Hyperparameter type
  262. def.machine.param.type = 'factorial';
  263. % L1 regularization hyperparameter
  264. def.machine.param.(['rangeL1' m]) = [1 sqrt(size(data.(upper(m)), upper(m), 2))];
  265. end
  266. case 'cca'
  267. % Hyperparameter name and type
  268. if isempty(cfg.machine.param.name)
  269. cfg.machine.param.name = {['L2' m]};
  270. elseif ~ismember(['L2' m], cfg.machine.param.name)
  271. cfg.machine.param.name = [cfg.machine.param.name {['L2' m]}];
  272. end
  273. def.machine.param.type = 'factorial';
  274. % Explained variance treated as hyperparameter
  275. if ismember(['VAR' m], cfg.machine.param.name)
  276. def.machine.param.(['rangeVAR' m]) = [0.1 1];
  277. end
  278. % PCA components treated as hyperparameter
  279. if ismember(['PCA' m], cfg.machine.param.name)
  280. dim = size(data.(upper(m)), upper(m));
  281. if strcmp(cfg.frwork.name, 'holdout')
  282. dim(1) = dim(1) * (1 - cfg.frwork.split.propout) * (1 - cfg.frwork.split.propin);
  283. end
  284. def.machine.param.(['rangePCA' m]) = [1 floor(min(dim))];
  285. end
  286. case 'rcca'
  287. % Hyperparameter name and type
  288. if isempty(cfg.machine.param.name)
  289. cfg.machine.param.name = {['L2' m]};
  290. elseif ~ismember(['L2' m], cfg.machine.param.name)
  291. cfg.machine.param.name = [cfg.machine.param.name {['L2' m]}];
  292. end
  293. def.machine.param.type = 'factorial';
  294. % L2 regularization hyperparameter
  295. if strcmp(cfg.machine.name, 'rcca')
  296. def.machine.param.(['rangeL2' m]) = [1 size(data.(upper(m)), upper(m), 2)^2];
  297. end
  298. end
  299. end
  300. % Update fields
  301. cfg = assign_defaults(cfg, def);
  302. % Number of default hyperparameters
  303. for i=1:numel(cfg.machine.param.name)
  304. if isfield(cfg.machine.param, (['range' cfg.machine.param.name{i}]))
  305. def.machine.param.(['n' cfg.machine.param.name{i}]) = 10;
  306. end
  307. end
  308. % Update fields
  309. cfg = assign_defaults(cfg, def);
  310. % Hyperparameter settings for machines
  311. for i=1:numel(cfg.data.mod)
  312. m = lower(cfg.data.mod{i}); % shorthand for modality in lowercase
  313. switch cfg.machine.name
  314. case 'pls'
  315. % Uses SPLS with L1 regularization outside of range (see below)
  316. cfg.machine.param.(['L1' m]) = size(data.(upper(m)), upper(m), 2);
  317. case 'spls'
  318. % L1 regularization hyperparameter for sparsity
  319. % Note: logarithmic space for efficient L1 norm
  320. if ismember(['L1' m], cfg.machine.param.name)
  321. def.machine.param.(['L1' m]) = logspace(log10(cfg.machine.param.(['rangeL1' m])(1)), ...
  322. log10(cfg.machine.param.(['rangeL1' m])(2)), cfg.machine.param.(['nL1' m]));
  323. end
  324. case 'cca'
  325. % RCCA with L2 regularization set to 0 (see above)
  326. cfg.machine.param.(['L2' m]) = 0;
  327. % Explained variance treated as hyperparameter
  328. if ismember(['VAR' m], cfg.machine.param.name)
  329. def.machine.param.(['VAR' m]) = linspace(cfg.machine.param.(['rangeVAR' m])(1), ...
  330. cfg.machine.param.(['rangeVAR' m])(end), cfg.machine.param.(['nVAR' m]));
  331. end
  332. % PCA components treated as hyperparameter
  333. if ismember(['PCA' m], cfg.machine.param.name)
  334. def.machine.param.(['PCA' m]) = logspace(log10(cfg.machine.param.(['rangePCA' m])(1)), ...
  335. log10(cfg.machine.param.(['rangePCA' m])(2)), cfg.machine.param.(['nPCA' m]));
  336. def.machine.param.(['PCA' m]) = unique(round(def.machine.param.(['PCA' m])));
  337. end
  338. case 'rcca'
  339. % L2 regularization hyperparameter for smoothing between CCA (l2=0) and PLS (l2=1)
  340. % Note: 1 - logarithmic space for efficient L2 norm
  341. def.machine.param.(['L2' m]) = 1 - logspace(-log10(cfg.machine.param.(['rangeL2' m])(1)), ...
  342. -log10(cfg.machine.param.(['rangeL2' m])(2)), cfg.machine.param.(['nL2' m]));
  343. end
  344. end
  345. % Criterion for hyperparameter selection
  346. def.machine.param.crit = 'correl';
  347. % Additional settings for machines
  348. if ismember(cfg.machine.name, {'pls' 'spls'})
  349. % Tolerance and maximum number of iterations
  350. def.machine.spls.tol = 1e-5;
  351. def.machine.spls.maxiter = 100;
  352. else
  353. % Tolerance
  354. def.machine.svd.tol = 1e-10;
  355. % Explained variance
  356. if strcmp(cfg.machine.name, 'cca')
  357. def.machine.svd.varx = 1; % Note that it can be effectively overwritten by hyperparameter
  358. def.machine.svd.vary = 1;
  359. elseif strcmp(cfg.machine.name, 'rcca')
  360. def.machine.svd.varx = 0.99;
  361. def.machine.svd.vary = 0.99; % No hyperparameter here, so it always has an effect
  362. end
  363. end
  364. % Update fields
  365. cfg = assign_defaults(cfg, def);
  366. % Sanity checks for hyperparameter settings
  367. for i=1:numel(cfg.data.mod)
  368. m = lower(cfg.data.mod{i}); % shorthand for modality in lowercase
  369. % Check if L1 regularization obeys limits
  370. if strcmp(cfg.machine.name, 'spls') && (cfg.machine.param.(['rangeL1' m])(1) < 1 || ...
  371. cfg.machine.param.(['rangeL1' m])(2) > sqrt(cfg.data.(upper(m)).nfeat))
  372. error('L1 regularization is out of interval: [1, sqrt(size(%s, 2)].', upper(m));
  373. end
  374. end
  375. % Check and update machine parameter fields
  376. fields = fieldnames(cfg.machine.param);
  377. for i=1:numel(fields)
  378. if ~isempty(regexp(fields{i}, 'range')) || ~isempty(regexp(fields{i}, 'n.*(x|y)'))
  379. try
  380. def.machine.param = rmfield(def.machine.param, fields{i});
  381. catch; end
  382. cfg.machine.param = rmfield(cfg.machine.param, fields{i});
  383. end
  384. end
  385. % Check if grid search needed
  386. param = get_hyperparam(cfg, 'default');
  387. % Check and update framework settings
  388. if numel(param) == 1
  389. if isfield(def.frwork.split, 'nin')
  390. def.frwork.split = rmfield(def.frwork.split, 'nin');
  391. end
  392. if isfield(cfg.frwork.split, 'nin')
  393. cfg.frwork.split = rmfield(cfg.frwork.split, 'nin');
  394. end
  395. if isfield(def.frwork.split, 'propin')
  396. def.frwork.split = rmfield(def.frwork.split, 'propin');
  397. end
  398. if isfield(cfg.frwork.split, 'propin')
  399. cfg.frwork.split = rmfield(cfg.frwork.split, 'propin');
  400. end
  401. end
  402. % Project subdirectories
  403. switch cfg.frwork.name
  404. case 'holdout'
  405. if numel(param) > 1
  406. def.dir.frwork = sprintf('%s_holdout%d-%.2f_subsamp%d-%.2f', cfg.machine.name, ...
  407. cfg.frwork.split.nout, cfg.frwork.split.propout, cfg.frwork.split.nin, cfg.frwork.split.propin);
  408. else
  409. def.dir.frwork = sprintf('%s_holdout%d-%.2f', cfg.machine.name, cfg.frwork.split.nout, ...
  410. cfg.frwork.split.propout);
  411. end
  412. case 'permutation'
  413. def.dir.frwork = sprintf('%s_permutation', cfg.machine.name);
  414. end
  415. if all(isfield(cfg.machine.param, {'PCAx' 'PCAy'}))
  416. if numel(cfg.machine.param.PCAx) == 1 && numel(cfg.machine.param.PCAy) == 1
  417. if cfg.machine.param.PCAx == cfg.machine.param.PCAy
  418. def.dir.frwork = strrep(def.dir.frwork, 'cca', sprintf('cca_pca%d', cfg.machine.param.PCAx));
  419. else
  420. def.dir.frwork = strrep(def.dir.frwork, 'cca', sprintf('cca_pca%d-%d', ...
  421. cfg.machine.param.PCAx, cfg.machine.param.PCAy));
  422. end
  423. else
  424. def.dir.frwork = strrep(def.dir.frwork, 'cca', 'cca_pca');
  425. end
  426. end
  427. def.dir.frwork = [fullfile(cfg.dir.project, 'framework', def.dir.frwork) cfg.frwork.flag];
  428. def.dir.load = fullfile(def.dir.frwork, 'load');
  429. % Update fields
  430. cfg = assign_defaults(cfg, def);
  431. % Check if statistical inference is supported
  432. if cfg.stat.nperm > 0
  433. if strcmp(cfg.machine.name, 'pls') && ~ismember(cfg.stat.crit, {'correl' 'covar'})
  434. error('Statistical inference should be based on correlation or covariance.')
  435. elseif ~strcmp(cfg.stat.crit, 'correl')
  436. error('Statistical inference should be based on correlation.')
  437. end
  438. end
  439. %----- Save cfg
  440. if ~isdir(cfg.dir.frwork)
  441. mkdir(cfg.dir.frwork)
  442. end
  443. savemat(cfg, fullfile(cfg.dir.frwork, 'cfg.mat'), 'cfg', cfg);

cfg_defaults.m at commit 6e1ef1e, under GPL-3.0 · at the source

Overview

Authors: Wenrui Bao1,2, Gengchen Ye1, Tao Wang3,4,5, Xingpu Quan1, Qiange Zhu1, Liming Fan6, Haining Li7, Wentao Zeng1, Junya Mu1, Ruiting Zhu1,2, Jixin Liu8, Yuchen Zhang9, Xuan Niu1
ORCID iDs: Liming Fan, Xuan Niu
  1. Department of Medical Imaging, the First Affiliated Hospital of Xi’an Jiaotong University, Xi’an, Shaanxi Province 710061, China
  2. School of Future Technology, Xi’an Jiaotong University, Xi’an, Shaanxi Province 710049, China
  3. Key Laboratory of Shaanxi Province for Craniofacial Precision Medicine Research, College of Stomatology, Xi’an Jiaotong University, Xi’an, Shaanxi Province 710004, China
  4. Laboratory Center of Stomatology, College of Stomatology, Xi’an Jiaotong University, Xi’an, Shaanxi Province 710004, China
  5. Department of Medical Imaging, College of Stomatology, Xi’an Jiaotong University, Xi'an, Shaanxi Province 710004, China
  6. The Key Laboratory of Biomedical Information Engineering of Ministry of Education, Institute of Health and Rehabilitation Science, Xi’an Jiaotong University School of Life Science and Technology, Xi’an, Shaanxi Province 710049, China
  7. PET/CT Center, the First Affiliated Hospital of Xi’an Jiaotong University, Xi’an, Shaanxi Province 710061, China
  8. School of Life Science and Technology, Xidian University, Xi'an Key Laboratory of Intelligent Sensing and Regulation of Trans-Scale Life Information, Xi’an, Shaanxi 710126, China
  9. Department of Nuclear Medicine, the First Affiliated Hospital of Xi’an Jiaotong University, Xi’an, Shaanxi Province 710061, China
Journal: Brain communications, volume 8, issue 4, article fcag232
Dates: received 16 December 2025; accepted 27 May 2026; published online 18 June 2026
Type: Research article · Language: English
License: CC BY
Identifiers: DOI 10.1093/braincomms/fcag232 · PMID 42422532 · PMCID PMC13343389 · OpenAlex W7165172786
Open access: gold, a free copy (OpenAlex)
Status: code verified
Categories: structural MRI / diffusion (modality), human (organism), other condition (population), clinical / translational (subfield)
Methods: Statistics, Machine learning, fMRI & imaging, Smoothing, state filtering, decompositions, Preprocessing
Keywords: long COVID, neuropsychiatric symptoms, cortical thickness, grey matter volume, regularized canonical correlation analysis
Topic: Long-Term Effects of COVID-19 (Neurology, Medicine), according to OpenAlex
Citations: not cited yet (Europe PMC); 65 references in the paper

Abstract

Long COVID presents with heterogeneous and persistent neuropsychiatric symptoms, suggesting possible shared neural underpinnings. However, the dynamic brain structure–symptom relationships and their potential for predicting long-term outcomes remain unclear. We conducted a longitudinal study of 144 individuals with long COVID (mean age: 37.8 ± 10.1 years, 48.6% male). All participants experienced mild COVID-19 and were not hospitalized. Structural MRI and comprehensive psychiatric and cognitive assessments were performed at 1, 2 and 12 months post-infection. A cohort of 68 healthy controls (mean age: 36.0 ± 10.3 years; 41.2% male) completed the same assessment protocol at baseline. Regularized canonical correlation analysis was employed to identify multivariate associations between 13 psychiatric and cognitive measures and both grey matter volume and cortical thickness, and to assess whether early structural features predicted symptom outcomes at 1 year. Neuropsychiatric symptoms were linked to coordinated structural covariance patterns across distributed brain regions in long COVID; these associations strengthened from 1 to 3 months post-infection and were absent in controls. A stable cognitive-affective symptom dimension showed the strongest brain–behaviour coupling. Notably, the neural substrates of this coupling diverged over time: grey matter volume associations remained localized to prefrontal-limbic circuits, whereas cortical thickness associations expanded to frontoparietal regions. Critically, reduced grey matter volume in the right cuneus and superior frontal gyri, along with decreased cortical thickness in the left supramarginal gyrus at 3 months post-infection, were significantly linked to poorer executive function and greater fatigue 1 year later. Our findings delineate evolving neuroanatomical signature of long COVID, where distinct patterns of grey matter volume and cortical thickness underpin a core symptom profile and predict long-term neuropsychiatric symptoms. These results provide insight into the neural mechanisms of long COVID and identify specific targets for monitoring and early intervention.

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

Repository

Its files are read in the Code ↔ Paper reader above.

anaston/cca_pls_toolkit

License: GPL-3.0
State: the link answers, verified on 27 September 2026
Evidence: files inventoried
Commit: 6e1ef1e04c58984b1e9e8aa22dd5aabe490fb4de, 21 November 2022
Languages: MATLAB (72), JavaScript (28), Python (2)
Size: 275 files, 102 scripts
Software Heritage: archived
Found in: the text, “Regularized canonical correlation analysis”
Holds: README, license file, tests, continuous integration, documentation
Not found: CITATION.cff, environment file
Tools: Statistics and Machine Learning Toolbox (13 files), SPM (4 files)
Availability: 1 check, the latest on 27 September 2026: the link answers
  • 27 September 2026: the link answers
104 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;
  • 102 scripts, each with its path and the digest of its content;
  • no match between paragraphs and code yet;
  • 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

To get access to the data and comply with the terms of our research ethics committee approval, an application to the corresponding author will be required, specifying the geographical extent of sharing.

The regularized canonical correlation analysis (RCCA) was performed using the publicly available CCA/PLS toolkit developed by the Machine Learning & Neuroimaging Laboratory, University College London (https://github.com/anaston/cca_pls_toolkit), which is openly accessible.

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

Recorded: type, language, journal, volume, issue, pages, dates, 13 authors, 5 keywords, 5 funders, 65 references.

Cite

This paper

Bao, W., Ye, G., Wang, T., Quan, X., Zhu, Q., Fan, L., Li, H., Zeng, W., Mu, J., Zhu, R., Liu, J., Zhang, Y., & Niu, X. (2026). Dynamic multivariate patterns of brain structure-neuropsychiatric symptom associations in long COVID. Brain communications, 8(4), fcag232. https://doi.org/10.1093/braincomms/fcag232

BibTeX

@article{bao2026dynamic,
author = {Bao, Wenrui and Ye, Gengchen and Wang, Tao and Quan, Xingpu and Zhu, Qiange and Fan, Liming and Li, Haining and Zeng, Wentao and Mu, Junya and Zhu, Ruiting and Liu, Jixin and Zhang, Yuchen and Niu, Xuan},
title = {{Dynamic multivariate patterns of brain structure-neuropsychiatric symptom associations in long COVID}},
journal = {Brain communications},
year = {2026},
month = jun,
volume = {8},
number = {4},
pages = {fcag232},
publisher = {Oxford University Press},
issn = {2632-1297},
doi = {10.1093/braincomms/fcag232},
url = {https://doi.org/10.1093/braincomms/fcag232},
pmid = {42422532},
pmcid = {PMC13343389}
}

RIS

TY - JOUR
AU - Bao, Wenrui
AU - Ye, Gengchen
AU - Wang, Tao
AU - Quan, Xingpu
AU - Zhu, Qiange
AU - Fan, Liming
AU - Li, Haining
AU - Zeng, Wentao
AU - Mu, Junya
AU - Zhu, Ruiting
AU - Liu, Jixin
AU - Zhang, Yuchen
AU - Niu, Xuan
TI - Dynamic multivariate patterns of brain structure-neuropsychiatric symptom associations in long COVID
T2 - Brain communications
J2 - Brain Commun
PY - 2026
DA - 2026/06/18
VL - 8
IS - 4
SP - fcag232
SN - 2632-1297
PB - Oxford University Press
DO - 10.1093/braincomms/fcag232
UR - https://doi.org/10.1093/braincomms/fcag232
LA - en
ER -

CSL-JSON

{
"id": "10.1093/braincomms/fcag232",
"type": "article-journal",
"title": "Dynamic multivariate patterns of brain structure-neuropsychiatric symptom associations in long COVID",
"container-title": "Brain communications",
"author": [
{
"family": "Bao",
"given": "Wenrui"
},
{
"family": "Ye",
"given": "Gengchen"
},
{
"family": "Wang",
"given": "Tao"
},
{
"family": "Quan",
"given": "Xingpu"
},
{
"family": "Zhu",
"given": "Qiange"
},
{
"family": "Fan",
"given": "Liming"
},
{
"family": "Li",
"given": "Haining"
},
{
"family": "Zeng",
"given": "Wentao"
},
{
"family": "Mu",
"given": "Junya"
},
{
"family": "Zhu",
"given": "Ruiting"
},
{
"family": "Liu",
"given": "Jixin"
},
{
"family": "Zhang",
"given": "Yuchen"
},
{
"family": "Niu",
"given": "Xuan"
}
],
"container-title-short": "Brain Commun",
"volume": "8",
"issue": "4",
"page": "fcag232",
"DOI": "10.1093/braincomms/fcag232",
"PMID": "42422532",
"PMCID": "PMC13343389",
"ISSN": "2632-1297",
"publisher": "Oxford University Press",
"URL": "https://doi.org/10.1093/braincomms/fcag232",
"language": "en",
"issued": {
"date-parts": [
[
2026,
6,
18
]
]
}
}

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.bbih.2026.101274 [code]
Brain dynamics of attentional, default-mode and limbic networks are disrupted at rest in post-COVID-19 syndrome.
Journal: Brain, behavior, & immunity - health
In common: SPM, Statistics and Machine Learning Toolbox, other condition, 3 references
[2] doi:10.1007/s11682-026-01175-1
Longitudinal surface-based morphometry reveals potential MRI biomarkers correlated with multidimensional brain health measures.
Journal: Brain imaging and behavior
In common: structural MRI / diffusion, clinical / translational, 3 references
[3] doi:10.3389/fimmu.2026.1776555 [code]
Multi-omics analysis of long COVID (post-COVID-19 condition) reveals persistent mitochondrial dysfunction, suppressed oxidative phosphorylation, and immune dysregulation.
Journal: Frontiers in immunology
In common: other condition, 3 references
[4] doi:10.3390/brainsci16040410
LearningRx Cognitive Training for Workplace Self-Efficacy in Adults with Post-COVID-19 Brain Fog: A Mixed-Methods Pilot Study.
Journal: Brain sciences
In common: other condition, 3 references
[5] doi:10.1038/s41467-026-74099-5 [code]
Right amygdala ablation reduces maladaptive negative interpretation bias and symptoms in a patient with post-traumatic stress disorder.
Journal: Nature communications
In common: SPM, Statistics and Machine Learning Toolbox, clinical / translational, other condition, 1 reference
[6] doi:10.1038/s41467-026-76156-5 [code]
Longitudinal analysis reveals myeloid cell contributions to murine neuroPASC pathogenesis.
Journal: Nature communications
In common: other condition, 3 references
[7] doi:10.1093/braincomms/fcag045 [code]
Examining neuroimaging biomarkers, plasma biomarkers and cognitive functions in patients with recovered COVID-19 infection: a multicentre study using 7T MRI.
Journal: Brain communications
In common: structural MRI / diffusion, clinical / translational, other condition, 2 references
[8] doi:10.1016/j.bbih.2026.101299 [code]
Multimodal approach to identify neuropsychophysiological subgroups in myalgic encephalomyelitis/chronic fatigue syndrome and their relevance for rehabilitation: protocol for a mechanistic cross-sectional and longitudinal study.
Journal: Brain, behavior, & immunity - health
In common: SPM, Statistics and Machine Learning Toolbox, clinical / translational, 1 reference
[9] doi:10.1038/s41597-026-07676-4 [code]
A neuroimaging dataset combining movie-watching, eye-tracking, sensorimotor mapping, and cognitive tasks.
Journal: Scientific data
In common: SPM, Statistics and Machine Learning Toolbox, structural MRI / diffusion, 1 reference
[10] doi:10.1038/s41593-026-02359-0 [code]
The cross-site reproducibility of MRI morphometric phenotypes in psychiatric disorders.
Journal: Nature neuroscience
In common: SPM, Statistics and Machine Learning Toolbox, structural MRI / diffusion, 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.

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.