Dynamic multivariate patterns of brain structure-neuropsychiatric symptom associations in long COVID.
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
- function cfg = cfg_defaults(cfg, varargin)
- % cfg_defaults
- %
- % Set defaults in your configuration (`cfg`) structure which will define
- % the settings of your analysis (e.g., machine, framework, statistical
- % inference). Use this function to update and add all necessary defaults to
- % your `cfg`. If you defined anything in your `cfg` before calling the
- % function, it won't overwrite those values. The path to the project folder
- % should be always defined in your `cfg` or passed as varargin, otherwise
- % the function throws an error. All the other fields are optional and can
- % be filled up by `cfg_defaults`.
- %
- % No results will be stored in the cfg structure. See [res_defaults](../res_defaults)
- % for more information on results.
- %
- % !!! note "Warning"
- % We strongly advise to inspect the output of `cfg_defaults` to make
- % sure that the defaults are set as expected.
- %
- % # Syntax
- % cfg = cfg_defaults(cfg, varargin)
- %
- % # Inputs
- % cfg:: struct
- % varargin:: name-value pairs
- % additional parameters can be set via name-value pairs with dot notation
- % supported (e.g., 'frwork.split.nout', 5)
- %
- % # Outputs
- % cfg:: struct
- % configuration structure that has been updated with defaults
- %
- % # Examples
- %
- % % Example 1
- % [X, Y, wX, wY] = generate_data(1000, 100, 100, 10, 10, 1);
- %
- % ---
- % See also: [cfg](../../cfg), [res_defaults](../res_defaults/)
- %
- %_______________________________________________________________________
- % Copyright (C) 2022 University College London
- % Written by Agoston Mihalik ([email hidden])
- % $Id$
- % This file is part of CCA/PLS Toolkit.
- %
- % CCA/PLS Toolkit is free software: you can redistribute it and/or modify
- % it under the terms of the GNU General Public License as published by
- % the Free Software Foundation, either version 3 of the License, or
- % (at your option) any later version.
- %
- % CCA/PLS Toolkit is distributed in the hope that it will be useful,
- % but WITHOUT ANY WARRANTY; without even the implied warranty of
- % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- % GNU General Public License for more details.
- %
- % You should have received a copy of the GNU General Public License
- % along with CCA/PLS Toolkit. If not, see <https://www.gnu.org/licenses/>.
- def = parse_input([], varargin{:});
- % Initialize cfg
- if isempty(cfg)
- cfg = struct();
- end
- cfg = assign_defaults(cfg, def);
- %----- Primary defaults
- % Get toolkit version from git commit
- [~, def.env.commit] = system('git rev-parse HEAD');
- % Framework
- def.frwork.name = 'holdout'; % holdout/permutation
- def.frwork.flag = ''; % string to specify analysis in folder name
- % Machine
- def.machine.name = 'spls';
- % Computer environment
- def.env.comp = 'local'; % local/cluster
- if ismac
- def.env.OS = 'mac';
- elseif isunix
- def.env.OS = 'unix';
- elseif ispc
- def.env.OS = 'pc';
- end
- % Verbosity level
- % 1: detailed progress update with elapsed time info
- % 2: detailed progress update
- % 3: minimal progress update
- def.env.verbose = 2;
- % Data block structure (see exchangeability blocks below)
- def.data.block = 0;
- % Data modalities and confounds
- def.data.mod = {'X' 'Y'};
- def.data.conf = 0;
- % Update fields
- cfg = assign_defaults(cfg, def);
- % Check that path to project folder exists
- if ~isfield(cfg, 'dir') || ~isfield(cfg.dir, 'project')
- error('Path to project folder should be given.')
- end
- %----- Secondary defaults
- % Data train-test splitting
- switch cfg.frwork.name
- case 'holdout'
- % Multiple holdout framework (see Monteiro et al 2016 J Neurosci Methods)
- def.frwork.split.nout = 5;
- def.frwork.split.propout = 0.2;
- def.frwork.split.nin = 5;
- def.frwork.split.propin = 0.2;
- case 'permutation'
- % Permutation framework (see Smith et al Nat Neurosci 2015)
- % without train-test splitting
- def.frwork.split.nout = 1;
- end
- % Number of permutations in statistical inference
- def.stat.nperm = 1000;
- % Metrics to evaluate machines
- def.machine.metric = {'trcorrel' 'correl'}; % correlation between projections
- if strcmp(cfg.machine.name, 'spls')
- def.machine.metric = [def.machine.metric {'simwx' 'simwy'}]; % stability of weights
- end
- % Update fields
- cfg = assign_defaults(cfg, def);
- % Similarity metric
- if any(contains(cfg.machine.metric, 'sim'))
- if strcmp(cfg.machine.name, 'spls')
- def.machine.simw = 'overlap-corrected';
- else
- def.machine.simw = 'correlation-Pearson';
- end
- end
- % Statistical inference
- if cfg.stat.nperm ~= 0
- def.stat.crit = 'correl';
- def.stat.perm = 'train+test'; % 'train'
- def.stat.alpha = 0.05;
- end
- % Update fields
- cfg = assign_defaults(cfg, def);
- % Deflation formulation
- if ~isfield(cfg.frwork, 'nlevel') || cfg.frwork.nlevel > 1
- if ismember(cfg.machine.name, {'pls' 'spls'})
- def.defl.name = 'pls-modeA';
- else
- cfg.defl.name = 'generalized'; % overwrite user's option to be safe
- end
- % Deflation strategy with data splitting
- def.defl.crit = 'correl';
- end
- % Filename suffix on cluster or set default
- if strcmp(cfg.env.comp, 'cluster') && ~isempty(getenv('SGE_TASK_ID')) ...
- && ~strcmp(getenv('SGE_TASK_ID'), 'undefined')
- def.env.fileend = ['_' num2str(getenv('SGE_TASK_ID'))];
- elseif strcmp(cfg.env.comp, 'cluster') && ~isempty(getenv('SLURM_ARRAY_TASK_ID'))
- def.env.fileend = ['_' num2str(getenv('SLURM_ARRAY_TASK_ID'))];
- else
- def.env.fileend = '_1';
- end
- % Compression setting for saving files
- def.env.save.compression = 1;
- % Exchangeability blocks (EB) for restricted partitioning and permutation
- % (see Winkler et al 2015 Neuroimage, https://fsl.fmrib.ox.ac.uk/fsl/fslwiki/PALM)
- if cfg.data.block
- load(fullfile(cfg.dir.project, 'data', 'EB.mat'))
- if ~exist('EB', 'var')
- error('EB matrix not available');
- end
- % Columns of EB for restricted partitioning
- def.data.EB.split = 1:size(EB, 2);
- % Columns of EB for restricted permutations
- def.data.EB.stat = 1:size(EB, 2);
- end
- % Data path and preprocessing
- if cfg.data.conf
- mod = [cfg.data.mod {'C'}]; % modalities including confound matrix
- else
- mod = cfg.data.mod;
- end
- for i=1:numel(mod)
- def.data.(mod{i}).fname = fullfile(cfg.dir.project, 'data', [mod{i} '.mat']);
- def.data.(mod{i}).preproc = {'impute' 'zscore'};
- end
- if cfg.data.conf
- for i=1:numel(cfg.data.mod)
- def.data.(cfg.data.mod{i}).preproc = [def.data.(cfg.data.mod{i}).preproc {'deconf'}];
- end
- end
- % Update fields
- cfg = assign_defaults(cfg, def);
- % Data processing in details
- for i=1:numel(mod)
- if ismember('impute', cfg.data.(mod{i}).preproc)
- def.data.(mod{i}).impute = 'median';
- end
- if ismember('deconf', cfg.data.(mod{i}).preproc)
- def.data.(mod{i}).deconf = 'standard';
- end
- end
- % Seed options for reproducibility
- % this is important in case multiple jobs are started simultaneously on a
- % cluster, avoids jobs running same hyperparameters and permutations
- % simply uses the number of the fileend as seed
- % default, shuffle, number or struct returned by rng
- def.env.seed.split = 'default';
- tmp = regexp(cfg.env.fileend, '_(\d+)\>', 'tokens');
- def.env.seed.model = cellfun(@str2num, tmp{1});
- def.env.seed.perm = 'default';
- % Load data
- if exist(cfg.data.X.fname, 'file') && exist(cfg.data.Y.fname, 'file')
- for m=1:numel(mod)
- % Access data without loading into memory
- matobj = matfile(cfg.data.(mod{m}).fname);
- if ismember(who(matobj), mod{m})
- data.(mod{m}) = matobj;
- else
- error('%s matrix not available in %s.', mod{m}, cfg.data.(mod{m}).fname);
- end
- end
- else
- error('X and Y input data cannot be found in path, check your data folder.');
- end
- % Update fields
- cfg = assign_defaults(cfg, def);
- %----- Defaults set based on X, Y
- % Maximum number of associative effects
- if strcmp(cfg.defl.name, 'pls-regression')
- def.frwork.nlevel = min(size(data.X, 'X'));
- else
- def.frwork.nlevel = min(cellfun(@(x) min(size(data.(x), x)), cfg.data.mod));
- end
- if isfield(cfg.frwork, 'nlevel') && cfg.frwork.nlevel > def.frwork.nlevel
- cfg.frwork.nlevel = def.frwork.nlevel;
- end
- % Data dimensionality
- for i=1:numel(cfg.data.mod)
- if ~isfield(cfg.data, 'nsubj')
- cfg.data.nsubj = size(data.(cfg.data.mod{i}), cfg.data.mod{i}, 1);
- elseif size(data.(cfg.data.mod{i}), cfg.data.mod{i}, 1) ~= cfg.data.nsubj
- error('The number of examples do not match across data modalities');
- end
- cfg.data.(cfg.data.mod{i}).nfeat = size(data.(cfg.data.mod{i}), cfg.data.mod{i}, 2);
- end
- % Initialize machine hyperparameters
- def.machine.param.name = {};
- % Update fields
- cfg = assign_defaults(cfg, def);
- % Grid search settings for machines
- for i=1:numel(cfg.data.mod)
- m = lower(cfg.data.mod{i}); % shorthand for modality in lowercase
- switch cfg.machine.name
- case {'pls' 'spls'}
- % Hyperparameter name
- if isempty(cfg.machine.param.name)
- cfg.machine.param.name = {['L1' m]};
- elseif ~ismember(['L1' m], cfg.machine.param.name)
- cfg.machine.param.name = [cfg.machine.param.name {['L1' m]}];
- end
- if strcmp(cfg.machine.name, 'pls')
- % Hyperparameter type
- cfg.machine.param.type = 'matched';
- % No grid search as L1 regularizaion used with fix
- % parameter outside of SPLS range
- elseif strcmp(cfg.machine.name, 'spls')
- % Hyperparameter type
- def.machine.param.type = 'factorial';
- % L1 regularization hyperparameter
- def.machine.param.(['rangeL1' m]) = [1 sqrt(size(data.(upper(m)), upper(m), 2))];
- end
- case 'cca'
- % Hyperparameter name and type
- if isempty(cfg.machine.param.name)
- cfg.machine.param.name = {['L2' m]};
- elseif ~ismember(['L2' m], cfg.machine.param.name)
- cfg.machine.param.name = [cfg.machine.param.name {['L2' m]}];
- end
- def.machine.param.type = 'factorial';
- % Explained variance treated as hyperparameter
- if ismember(['VAR' m], cfg.machine.param.name)
- def.machine.param.(['rangeVAR' m]) = [0.1 1];
- end
- % PCA components treated as hyperparameter
- if ismember(['PCA' m], cfg.machine.param.name)
- dim = size(data.(upper(m)), upper(m));
- if strcmp(cfg.frwork.name, 'holdout')
- dim(1) = dim(1) * (1 - cfg.frwork.split.propout) * (1 - cfg.frwork.split.propin);
- end
- def.machine.param.(['rangePCA' m]) = [1 floor(min(dim))];
- end
- case 'rcca'
- % Hyperparameter name and type
- if isempty(cfg.machine.param.name)
- cfg.machine.param.name = {['L2' m]};
- elseif ~ismember(['L2' m], cfg.machine.param.name)
- cfg.machine.param.name = [cfg.machine.param.name {['L2' m]}];
- end
- def.machine.param.type = 'factorial';
- % L2 regularization hyperparameter
- if strcmp(cfg.machine.name, 'rcca')
- def.machine.param.(['rangeL2' m]) = [1 size(data.(upper(m)), upper(m), 2)^2];
- end
- end
- end
- % Update fields
- cfg = assign_defaults(cfg, def);
- % Number of default hyperparameters
- for i=1:numel(cfg.machine.param.name)
- if isfield(cfg.machine.param, (['range' cfg.machine.param.name{i}]))
- def.machine.param.(['n' cfg.machine.param.name{i}]) = 10;
- end
- end
- % Update fields
- cfg = assign_defaults(cfg, def);
- % Hyperparameter settings for machines
- for i=1:numel(cfg.data.mod)
- m = lower(cfg.data.mod{i}); % shorthand for modality in lowercase
- switch cfg.machine.name
- case 'pls'
- % Uses SPLS with L1 regularization outside of range (see below)
- cfg.machine.param.(['L1' m]) = size(data.(upper(m)), upper(m), 2);
- case 'spls'
- % L1 regularization hyperparameter for sparsity
- % Note: logarithmic space for efficient L1 norm
- if ismember(['L1' m], cfg.machine.param.name)
- def.machine.param.(['L1' m]) = logspace(log10(cfg.machine.param.(['rangeL1' m])(1)), ...
- log10(cfg.machine.param.(['rangeL1' m])(2)), cfg.machine.param.(['nL1' m]));
- end
- case 'cca'
- % RCCA with L2 regularization set to 0 (see above)
- cfg.machine.param.(['L2' m]) = 0;
- % Explained variance treated as hyperparameter
- if ismember(['VAR' m], cfg.machine.param.name)
- def.machine.param.(['VAR' m]) = linspace(cfg.machine.param.(['rangeVAR' m])(1), ...
- cfg.machine.param.(['rangeVAR' m])(end), cfg.machine.param.(['nVAR' m]));
- end
- % PCA components treated as hyperparameter
- if ismember(['PCA' m], cfg.machine.param.name)
- def.machine.param.(['PCA' m]) = logspace(log10(cfg.machine.param.(['rangePCA' m])(1)), ...
- log10(cfg.machine.param.(['rangePCA' m])(2)), cfg.machine.param.(['nPCA' m]));
- def.machine.param.(['PCA' m]) = unique(round(def.machine.param.(['PCA' m])));
- end
- case 'rcca'
- % L2 regularization hyperparameter for smoothing between CCA (l2=0) and PLS (l2=1)
- % Note: 1 - logarithmic space for efficient L2 norm
- def.machine.param.(['L2' m]) = 1 - logspace(-log10(cfg.machine.param.(['rangeL2' m])(1)), ...
- -log10(cfg.machine.param.(['rangeL2' m])(2)), cfg.machine.param.(['nL2' m]));
- end
- end
- % Criterion for hyperparameter selection
- def.machine.param.crit = 'correl';
- % Additional settings for machines
- if ismember(cfg.machine.name, {'pls' 'spls'})
- % Tolerance and maximum number of iterations
- def.machine.spls.tol = 1e-5;
- def.machine.spls.maxiter = 100;
- else
- % Tolerance
- def.machine.svd.tol = 1e-10;
- % Explained variance
- if strcmp(cfg.machine.name, 'cca')
- def.machine.svd.varx = 1; % Note that it can be effectively overwritten by hyperparameter
- def.machine.svd.vary = 1;
- elseif strcmp(cfg.machine.name, 'rcca')
- def.machine.svd.varx = 0.99;
- def.machine.svd.vary = 0.99; % No hyperparameter here, so it always has an effect
- end
- end
- % Update fields
- cfg = assign_defaults(cfg, def);
- % Sanity checks for hyperparameter settings
- for i=1:numel(cfg.data.mod)
- m = lower(cfg.data.mod{i}); % shorthand for modality in lowercase
- % Check if L1 regularization obeys limits
- if strcmp(cfg.machine.name, 'spls') && (cfg.machine.param.(['rangeL1' m])(1) < 1 || ...
- cfg.machine.param.(['rangeL1' m])(2) > sqrt(cfg.data.(upper(m)).nfeat))
- error('L1 regularization is out of interval: [1, sqrt(size(%s, 2)].', upper(m));
- end
- end
- % Check and update machine parameter fields
- fields = fieldnames(cfg.machine.param);
- for i=1:numel(fields)
- if ~isempty(regexp(fields{i}, 'range')) || ~isempty(regexp(fields{i}, 'n.*(x|y)'))
- try
- def.machine.param = rmfield(def.machine.param, fields{i});
- catch; end
- cfg.machine.param = rmfield(cfg.machine.param, fields{i});
- end
- end
- % Check if grid search needed
- param = get_hyperparam(cfg, 'default');
- % Check and update framework settings
- if numel(param) == 1
- if isfield(def.frwork.split, 'nin')
- def.frwork.split = rmfield(def.frwork.split, 'nin');
- end
- if isfield(cfg.frwork.split, 'nin')
- cfg.frwork.split = rmfield(cfg.frwork.split, 'nin');
- end
- if isfield(def.frwork.split, 'propin')
- def.frwork.split = rmfield(def.frwork.split, 'propin');
- end
- if isfield(cfg.frwork.split, 'propin')
- cfg.frwork.split = rmfield(cfg.frwork.split, 'propin');
- end
- end
- % Project subdirectories
- switch cfg.frwork.name
- case 'holdout'
- if numel(param) > 1
- def.dir.frwork = sprintf('%s_holdout%d-%.2f_subsamp%d-%.2f', cfg.machine.name, ...
- cfg.frwork.split.nout, cfg.frwork.split.propout, cfg.frwork.split.nin, cfg.frwork.split.propin);
- else
- def.dir.frwork = sprintf('%s_holdout%d-%.2f', cfg.machine.name, cfg.frwork.split.nout, ...
- cfg.frwork.split.propout);
- end
- case 'permutation'
- def.dir.frwork = sprintf('%s_permutation', cfg.machine.name);
- end
- if all(isfield(cfg.machine.param, {'PCAx' 'PCAy'}))
- if numel(cfg.machine.param.PCAx) == 1 && numel(cfg.machine.param.PCAy) == 1
- if cfg.machine.param.PCAx == cfg.machine.param.PCAy
- def.dir.frwork = strrep(def.dir.frwork, 'cca', sprintf('cca_pca%d', cfg.machine.param.PCAx));
- else
- def.dir.frwork = strrep(def.dir.frwork, 'cca', sprintf('cca_pca%d-%d', ...
- cfg.machine.param.PCAx, cfg.machine.param.PCAy));
- end
- else
- def.dir.frwork = strrep(def.dir.frwork, 'cca', 'cca_pca');
- end
- end
- def.dir.frwork = [fullfile(cfg.dir.project, 'framework', def.dir.frwork) cfg.frwork.flag];
- def.dir.load = fullfile(def.dir.frwork, 'load');
- % Update fields
- cfg = assign_defaults(cfg, def);
- % Check if statistical inference is supported
- if cfg.stat.nperm > 0
- if strcmp(cfg.machine.name, 'pls') && ~ismember(cfg.stat.crit, {'correl' 'covar'})
- error('Statistical inference should be based on correlation or covariance.')
- elseif ~strcmp(cfg.stat.crit, 'correl')
- error('Statistical inference should be based on correlation.')
- end
- end
- %----- Save cfg
- if ~isdir(cfg.dir.frwork)
- mkdir(cfg.dir.frwork)
- end
- savemat(cfg, fullfile(cfg.dir.frwork, 'cfg.mat'), 'cfg', cfg);
cfg_defaults.m at commit 6e1ef1e, under GPL-3.0 · at the source
Overview
- Department of Medical Imaging, the First Affiliated Hospital of Xi’an Jiaotong University, Xi’an, Shaanxi Province 710061, China
- School of Future Technology, Xi’an Jiaotong University, Xi’an, Shaanxi Province 710049, China
- Key Laboratory of Shaanxi Province for Craniofacial Precision Medicine Research, College of Stomatology, Xi’an Jiaotong University, Xi’an, Shaanxi Province 710004, China
- Laboratory Center of Stomatology, College of Stomatology, Xi’an Jiaotong University, Xi’an, Shaanxi Province 710004, China
- Department of Medical Imaging, College of Stomatology, Xi’an Jiaotong University, Xi'an, Shaanxi Province 710004, China
- 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
- PET/CT Center, the First Affiliated Hospital of Xi’an Jiaotong University, Xi’an, Shaanxi Province 710061, China
- 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
- Department of Nuclear Medicine, the First Affiliated Hospital of Xi’an Jiaotong University, Xi’an, Shaanxi Province 710061, China
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
6e1ef1e04c58984b1e9e8aa22dd5aabe490fb4de, 21 November 2022Availability: 1 check, the latest on 27 September 2026: the link answers
- 27 September 2026: the link answers
104 files
- cfg_defaults.m, MATLAB, 520 lines
- demo/
demo_simul_paper.m , MATLAB, 115 lines - documentation/
matdoc.py , Python, 238 lines - documentation/
matdocparser.py , Python, 383 lines - documentation/
site/ , JavaScript, 29 linesassets/ javascripts/ bundle.17f42bbf.min.js - documentation/
site/ , JavaScript, 1 lineassets/ javascripts/ lunr/ min/ lunr.ar.min.js - documentation/
site/ , JavaScript, 18 linesassets/ javascripts/ lunr/ min/ lunr.da.min.js - documentation/
site/ , JavaScript, 18 linesassets/ javascripts/ lunr/ min/ lunr.de.min.js - documentation/
site/ , JavaScript, 18 linesassets/ javascripts/ lunr/ min/ lunr.du.min.js - documentation/
site/ , JavaScript, 18 linesassets/ javascripts/ lunr/ min/ lunr.es.min.js - documentation/
site/ , JavaScript, 18 linesassets/ javascripts/ lunr/ min/ lunr.fi.min.js - documentation/
site/ , JavaScript, 18 linesassets/ javascripts/ lunr/ min/ lunr.fr.min.js - documentation/
site/ , JavaScript, 1 lineassets/ javascripts/ lunr/ min/ lunr.hi.min.js - documentation/
site/ , JavaScript, 18 linesassets/ javascripts/ lunr/ min/ lunr.hu.min.js - documentation/
site/ , JavaScript, 18 linesassets/ javascripts/ lunr/ min/ lunr.it.min.js - documentation/
site/ , JavaScript, 1 lineassets/ javascripts/ lunr/ min/ lunr.ja.min.js - documentation/
site/ , JavaScript, 1 lineassets/ javascripts/ lunr/ min/ lunr.jp.min.js - documentation/
site/ , JavaScript, 1 lineassets/ javascripts/ lunr/ min/ lunr.multi.min.js - documentation/
site/ , JavaScript, 18 linesassets/ javascripts/ lunr/ min/ lunr.nl.min.js - documentation/
site/ , JavaScript, 18 linesassets/ javascripts/ lunr/ min/ lunr.no.min.js - documentation/
site/ , JavaScript, 18 linesassets/ javascripts/ lunr/ min/ lunr.pt.min.js - documentation/
site/ , JavaScript, 18 linesassets/ javascripts/ lunr/ min/ lunr.ro.min.js - documentation/
site/ , JavaScript, 18 linesassets/ javascripts/ lunr/ min/ lunr.ru.min.js - documentation/
site/ , JavaScript, 1 lineassets/ javascripts/ lunr/ min/ lunr.stemmer.support.min .js - documentation/
site/ , JavaScript, 18 linesassets/ javascripts/ lunr/ min/ lunr.sv.min.js - documentation/
site/ , JavaScript, 1 lineassets/ javascripts/ lunr/ min/ lunr.th.min.js - documentation/
site/ , JavaScript, 18 linesassets/ javascripts/ lunr/ min/ lunr.tr.min.js - documentation/
site/ , JavaScript, 1 lineassets/ javascripts/ lunr/ min/ lunr.vi.min.js - documentation/
site/ , JavaScript, 1 lineassets/ javascripts/ lunr/ min/ lunr.zh.min.js - documentation/
site/ , JavaScript, 206 linesassets/ javascripts/ lunr/ tinyseg.js - documentation/
site/ , JavaScript, 186 linesassets/ javascripts/ lunr/ wordcut.js - documentation/
site/ , JavaScript, 48 linesassets/ javascripts/ workers/ search.cefbb252.min.js - examples/
example_fmri.m , MATLAB, 419 lines - examples/
example_simulation.m , MATLAB, 375 lines - examples/
example_smri.m , MATLAB, 406 lines - fileio/
cleanup_files.m , MATLAB, 82 lines - fileio/
compile_files.m , MATLAB, 74 lines - fileio/
exist_file.m , MATLAB, 52 lines - fileio/
getfname.m , MATLAB, 51 lines - fileio/
loadmat.m , MATLAB, 63 lines - fileio/
loadmat_struct.m , MATLAB, 56 lines - fileio/
parse_input.m , MATLAB, 54 lines - fileio/
parse_struct.m , MATLAB, 54 lines - fileio/
renamemat.m , MATLAB, 63 lines - fileio/
savemat.m , MATLAB, 76 lines - fileio/
select_file.m , MATLAB, 37 lines - machines/
rcca.m , MATLAB, 44 lines - machines/
spls.m , MATLAB, 187 lines - misc/
calc_permid.m , MATLAB, 107 lines - misc/
calc_proj.m , MATLAB, 41 lines - misc/
calc_splits.m , MATLAB, 124 lines - misc/
concat_data.m , MATLAB, 48 lines - misc/
deflate_data.m , MATLAB, 113 lines - misc/
generate_data.m , MATLAB, 86 lines - misc/
get_featid.m , MATLAB, 44 lines - misc/
get_hyperparam.m , MATLAB, 97 lines - misc/
impute_mat.m , MATLAB, 53 lines - misc/
load_data.m , MATLAB, 359 lines - misc/
main.m , MATLAB, 83 lines - misc/
permute_data.m , MATLAB, 73 lines - misc/
preproc_data.m , MATLAB, 123 lines - misc/
process_metric.m , MATLAB, 68 lines - misc/
qc_data.m , MATLAB, 85 lines - misc/
run_machine.m , MATLAB, 112 lines - misc/
run_model.m , MATLAB, 299 lines - misc/
save_results.m , MATLAB, 149 lines - misc/
stat_inference.m , MATLAB, 74 lines - plot/
plot_paropt.m , MATLAB, 207 lines - plot/
plot_proj.m , MATLAB, 309 lines - plot/
plot_proj_2d.m , MATLAB, 62 lines - plot/
plot_proj_2d_cmap.m , MATLAB, 64 lines - plot/
plot_proj_2d_group.m , MATLAB, 95 lines - plot/
plot_weight.m , MATLAB, 219 lines - plot/
plot_weight_behav_horz.m , MATLAB, 116 lines - plot/
plot_weight_behav_text.m , MATLAB, 146 lines - plot/
plot_weight_behav_vert.m , MATLAB, 107 lines - plot/
plot_weight_brain_conn_n , MATLAB, 84 linesode.m - plot/
plot_weight_brain_cortex , MATLAB, 65 lines.m - plot/
plot_weight_brain_edge.m , MATLAB, 98 lines - plot/
plot_weight_brain_module , MATLAB, 130 lines.m - plot/
plot_weight_brain_node.m , MATLAB, 65 lines - plot/
plot_weight_stem.m , MATLAB, 99 lines - res_defaults.m, MATLAB, 314 lines
- set_path.m, MATLAB, 100 lines
- test/
get_data.m , MATLAB, 56 lines - test/
test_algorithms.m , MATLAB, 165 lines - test/
test_pipeline.m , MATLAB, 96 lines - util/
assign_defaults.m , MATLAB, 42 lines - util/
calc_distance.m , MATLAB, 32 lines - util/
calc_exvar.m , MATLAB, 113 lines - util/
calc_stability.m , MATLAB, 130 lines - util/
cov2.m , MATLAB, 37 lines - util/
deflation.m , MATLAB, 108 lines - util/
fastsvd.m , MATLAB, 139 lines - util/
ffd_val_str.m , MATLAB, 50 lines - util/
fix_fileend.m , MATLAB, 58 lines - util/
init_brainnet.m , MATLAB, 63 lines - util/
mean_center_features.m , MATLAB, 36 lines - util/
norm_features.m , MATLAB, 62 lines - util/
normalize2MNI.m , MATLAB, 77 lines - util/
postproc_weight.m , MATLAB, 57 lines - util/
update_dir.m , MATLAB, 135 lines - LICENSE, License, 692 lines
- README.md, Text, 49 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;
- 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/
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-neuropsychiatr
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-neuropsychiatr
journal = {Brain communications},
year = {2026},
month = jun,
volume = {8},
number = {4},
pages = {fcag232},
publisher = {Oxford University Press},
issn = {2632-1297},
doi = {10.1093/
url = {https://
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-neuropsychiatr
T2 - Brain communications
J2 - Brain Commun
PY - 2026
DA - 2026/
VL - 8
IS - 4
SP - fcag232
SN - 2632-1297
PB - Oxford University Press
DO - 10.1093/
UR - https://
LA - en
ER -
CSL-JSON
{
"id": "10.1093/
"type": "article-journal",
"title": "Dynamic multivariate patterns of brain structure-neuropsychiatr
"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":
"volume": "8",
"issue": "4",
"page": "fcag232",
"DOI": "10.1093/
"PMID": "42422532",
"PMCID": "PMC13343389",
"ISSN": "2632-1297",
"publisher": "Oxford University Press",
"URL": "https://
"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 - healthIn 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 behaviorIn 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 immunologyIn 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 sciencesIn 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 communicationsIn 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 communicationsIn 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 communicationsIn 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 - healthIn 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 dataIn 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 neuroscienceIn 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.
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, 102 scripts, and 0 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:83569afc61c7bf9e…
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.
