Navigation Menu

Skip to content

Commit

Permalink
FIX #1729 - make cfg.channels explicitly forbidden
Browse files Browse the repository at this point in the history
- notify people when they accidentally specify a mistyped cfg option
- moved the ft_checkdata more consistently to the top of the high-level functions
- always give feedback in ft_checkdata, irrespective of cfg.feedback (which is only set later)
- updated whitespace and linebreaks in the help of some functions
  • Loading branch information
robertoostenveld committed Apr 7, 2021
1 parent 79f5377 commit 786b527
Show file tree
Hide file tree
Showing 49 changed files with 557 additions and 458 deletions.
5 changes: 3 additions & 2 deletions ft_badchannel.m
Expand Up @@ -104,8 +104,9 @@
% check if the input data is valid for this function
data = ft_checkdata(data, 'datatype', 'raw', 'feedback', 'yes');

% ensure that the configuration is consistent
cfg = ft_checkconfig(cfg, 'required', 'metric');
% check if the input cfg is valid for this function
cfg = ft_checkconfig(cfg, 'forbidden', {'channels'});
cfg = ft_checkconfig(cfg, 'required', 'metric');

% ensure that the preproc specific options are located in the cfg.preproc substructure
cfg = ft_checkconfig(cfg, 'createsubcfg', {'preproc'});
Expand Down
5 changes: 3 additions & 2 deletions ft_badsegment.m
Expand Up @@ -103,8 +103,9 @@
% check if the input data is valid for this function
data = ft_checkdata(data, 'datatype', 'raw', 'feedback', 'yes');

% ensure that the configuration is consistent
cfg = ft_checkconfig(cfg, 'required', 'metric');
% check if the input cfg is valid for this function
cfg = ft_checkconfig(cfg, 'forbidden', {'channels'});
cfg = ft_checkconfig(cfg, 'required', 'metric');

% ensure that the preproc specific options are located in the cfg.preproc substructure
cfg = ft_checkconfig(cfg, 'createsubcfg', {'preproc'});
Expand Down
16 changes: 10 additions & 6 deletions ft_channelnormalise.m
Expand Up @@ -65,26 +65,30 @@
return
end

% store the original datatype
dtype = ft_datatype(data);

% check if the input data is valid for this function
data = ft_checkdata(data, 'datatype', 'raw', 'feedback', 'yes');

% check if the input cfg is valid for this function
cfg = ft_checkconfig(cfg, 'forbidden', {'channels'});

% set the defaults
cfg.channel = ft_getopt(cfg, 'channel', 'all');
cfg.trials = ft_getopt(cfg, 'trials', 'all', 1);
cfg.scale = ft_getopt(cfg, 'scale', 1);
cfg.demean = ft_getopt(cfg, 'demean', 'yes');
cfg.method = ft_getopt(cfg, 'method', 'perchannel'); % or acrosschannel

% store original datatype
dtype = ft_datatype(data);

% check if the input data is valid for this function
data = ft_checkdata(data, 'datatype', 'raw', 'feedback', 'yes');

if ~strcmp(cfg.channel, 'all') || ~strcmp(cfg.trials, 'all')
% select channels and trials of interest
tmpcfg = keepfields(cfg, {'trials', 'channel', 'tolerance', 'showcallinfo'});
data = ft_selectdata(tmpcfg, data);
% restore the provenance information
[cfg, data] = rollback_provenance(cfg, data);
end

% initialise some variables
nchan = numel(data.label);
ntrl = numel(data.trial);
Expand Down
1 change: 1 addition & 0 deletions ft_componentanalysis.m
Expand Up @@ -185,6 +185,7 @@
data = ft_checkdata(data, 'datatype', 'raw', 'feedback', 'yes');

% check if the input cfg is valid for this function
cfg = ft_checkconfig(cfg, 'forbidden', {'channels'});
cfg = ft_checkconfig(cfg, 'forbidden', {'detrend'});
cfg = ft_checkconfig(cfg, 'renamed', {'blc', 'demean'});
cfg = ft_checkconfig(cfg, 'renamedval', {'method', 'predetermined mixing matrix', 'predetermined unmixing matrix'});
Expand Down
3 changes: 3 additions & 0 deletions ft_connectivityanalysis.m
Expand Up @@ -140,6 +140,9 @@
% check if the input data is valid for this function
% data = ft_checkdata(data, 'datatype', {'raw', 'timelock', 'freq', 'source'});

% check if the input cfg is valid for this function
cfg = ft_checkconfig(cfg, 'forbidden', {'channels'});

% set the defaults
cfg.feedback = ft_getopt(cfg, 'feedback', 'none');
cfg.channel = ft_getopt(cfg, 'channel', 'all');
Expand Down
7 changes: 4 additions & 3 deletions ft_connectivityplot.m
Expand Up @@ -62,9 +62,10 @@
end

% check if the input cfg is valid for this function
cfg = ft_checkconfig(cfg, 'renamed', {'zparam', 'parameter'});
cfg = ft_checkconfig(cfg, 'renamed', {'color', 'linecolor'});
cfg = ft_checkconfig(cfg, 'renamed', {'graphcolor', 'linecolor'});
cfg = ft_checkconfig(cfg, 'forbidden', {'channels'});
cfg = ft_checkconfig(cfg, 'renamed', {'zparam', 'parameter'});
cfg = ft_checkconfig(cfg, 'renamed', {'color', 'linecolor'});
cfg = ft_checkconfig(cfg, 'renamed', {'graphcolor', 'linecolor'});

% set the defaults
cfg.channel = ft_getopt(cfg, 'channel', 'all');
Expand Down
73 changes: 39 additions & 34 deletions ft_crossfrequencyanalysis.m
Expand Up @@ -12,25 +12,26 @@
% cfg.freqlow = scalar or vector, selection of frequencies for the low frequency data
% cfg.freqhigh = scalar or vector, selection of frequencies for the high frequency data
%
% Channel selection can be specified according to whether one wants to perform within- or
% Channel selection can be specified according to whether one wants to perform within- or
% cross-channel analysis.
%
% For within-channel analysis (default), one specifies only a single channel
% selection:
% For within-channel analysis (default), you should specifies only a single channel selection:
% cfg.channel = cell-array with selection of channels, see FT_CHANNELSELECTION
% In this case, the "dimord" will be "chan_freqlow_freqhigh"
% In this case, the output "dimord" will be "chan_freqlow_freqhigh"
%
% For cross-channel analysis, one specifies two sets:
% cfg.chanlow = cell-array with selection of channels for the phase providing channels from the
% For cross-channel analysis, you should specifies two channel selections:
% cfg.chanlow = cell-array with selection of channels for the phase providing channels from the
% freqlow data argument, with wildcards allowed, see FT_CHANNELSELECTION
% cfg.chanhigh = cell-array with selection of channels for the amplitude providing channels from the
% cfg.chanhigh = cell-array with selection of channels for the amplitude providing channels from the
% freqhigh data argument, with wildcards allowed, see FT_CHANNELSELECTION
% In this case, the "dimord" will be "chancmb_freqlow_freqhigh" and "label" field will be replaced with
% "labelcmb" (corresponding to the dimension "chancmb") describing the pairs of channel combinations as
% {'chanlow01' 'chanhigh01';
% 'chanlow01' 'chanhigh02';
% ... ;
% 'chanlow02' 'chanhigh01';
% In this case, the output "dimord" will be "chancmb_freqlow_freqhigh" and "label"
% field will be replaced with "labelcmb" (corresponding to the dimension "chancmb")
% describing the pairs of channel combinations as
% {'chanlow01' 'chanhigh01'
% 'chanlow01' 'chanhigh02'
% ...
% 'chanlow02' 'chanhigh01'
% 'chanlow02' 'chanhigh02'
% ...
% }
% N.B.: The order of channels corresponds to their order in the original "label" field
Expand Down Expand Up @@ -106,6 +107,9 @@
freqlow = ft_checkdata(freqlow, 'datatype', 'freq', 'feedback', 'yes');
freqhigh = ft_checkdata(freqhigh, 'datatype', 'freq', 'feedback', 'yes');

% check if the input cfg is valid for this function
cfg = ft_checkconfig(cfg, 'forbidden', {'channels'});

% FIXME the below is a bit hacky but it does the trick
if isfield(cfg, 'chanlow') && isfield(cfg, 'chanhigh')
docrosschan = true;
Expand All @@ -125,9 +129,10 @@
ft_error('you should either specify both cfg.chanlow and cfg.chanhigh, or none of these options');
end

% get the defaults
cfg.freqlow = ft_getopt(cfg, 'freqlow', 'all');
cfg.freqhigh = ft_getopt(cfg, 'freqhigh', 'all');
cfg.nphase = ft_getopt(cfg, 'nphase', 20);
cfg.nphase = ft_getopt(cfg, 'nphase', 20);
cfg.keeptrials = ft_getopt(cfg, 'keeptrials');

% make selection of frequencies and channels
Expand Down Expand Up @@ -155,7 +160,7 @@
% prepare the data
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
switch cfg.method

case 'coh'
% coherence
cohdatas = zeros(ntrial,nchan,numel(LF),numel(HF));
Expand All @@ -167,7 +172,7 @@
end
end
cfcdata = cohdatas;

case 'plv'
% phase locking value
plvdatas = zeros(ntrial,nchan,numel(LF),numel(HF));
Expand All @@ -179,7 +184,7 @@
end
end
cfcdata = plvdatas;

case 'mvl'
% mean vector length
mvldatas = zeros(ntrial,nchan,numel(LF),numel(HF));
Expand All @@ -191,7 +196,7 @@
end
end
cfcdata = mvldatas;

case {'mi','pac'}
% modulation index
pacdatas = zeros(ntrial,nchan,numel(LF),numel(HF),cfg.nphase);
Expand All @@ -203,15 +208,15 @@
end
end
cfcdata = pacdatas;

end % switch method for data preparation

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% do the actual computation
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

switch cfg.method

case 'coh'
[ntrial,nchan,nlf,nhf] = size(cfcdata);
if strcmp(cfg.keeptrials, 'no')
Expand All @@ -221,7 +226,7 @@
crsspctrm = abs(cfcdata);
dimord = 'rpt_chan_freqlow_freqhigh' ;
end

case 'plv'
[ntrial,nchan,nlf,nhf] = size(cfcdata);
if strcmp(cfg.keeptrials, 'no')
Expand All @@ -231,7 +236,7 @@
crsspctrm = abs(cfcdata);
dimord = 'rpt_chan_freqlow_freqhigh' ;
end

case 'mvl'
[ntrial,nchan,nlf,nhf] = size(cfcdata);
if strcmp(cfg.keeptrials, 'no')
Expand All @@ -241,10 +246,10 @@
crsspctrm = abs(cfcdata);
dimord = 'rpt_chan_freqlow_freqhigh' ;
end

case 'mi'
[ntrial,nchan,nlf,nhf,nbin] = size(cfcdata);

if strcmp(cfg.keeptrials, 'yes')
dimord = 'rpt_chan_freqlow_freqhigh' ;
crsspctrm = zeros(ntrial,nchan,nlf,nhf);
Expand All @@ -253,7 +258,7 @@
pac = squeeze(cfcdata(k,n,:,:,:));
Q =ones(nbin,1)/nbin; % uniform distribution
mi = zeros(nlf,nhf);

for i=1:nlf
for j=1:nhf
P = squeeze(pac(i,j,:))/ nansum(pac(i,j,:)); % normalized distribution
Expand All @@ -262,20 +267,20 @@
end
end
crsspctrm(k,n,:,:) = mi;

end
end

else
dimord = 'chan_freqlow_freqhigh' ;
crsspctrm = zeros(nchan,nlf,nhf);
cfcdatamean = reshape(mean(cfcdata,1),[nchan nlf nhf nbin 1]);

for k =1:nchan
pac = squeeze(cfcdatamean(k,:,:,:));
Q =ones(nbin,1)/nbin; % uniform distribution
mi = zeros(nlf,nhf);

for i=1:nlf
for j=1:nhf
P = squeeze(pac(i,j,:))/ nansum(pac(i,j,:)); % normalized distribution
Expand All @@ -285,9 +290,9 @@
end
crsspctrm(k,:,:) = mi;
end

end % if keeptrials

case 'pac'
[ntrial,nchan,nlf,nhf,nbin] = size(cfcdata);

Expand All @@ -299,7 +304,7 @@
dimord = 'chan_freqlow_freqhigh_phase' ;
crsspctrm = reshape(mean(cfcdata,1),[nchan nlf nhf nbin 1]);
crsspctrm(isnan(crsspctrm)) = 0;

end % if keeptrials

end % switch method for actual computation
Expand Down Expand Up @@ -349,11 +354,11 @@
Nx = sum(~isnan(LFsigtemp(i,:) .* LFsigtemp(i,:)));
Ny = sum(~isnan(HFsigtemp(j,:) .* HFsigtemp(j,:)));
Nxy = sum(~isnan(LFsigtemp(i,:) .* HFsigtemp(j,:)));

Px = LFsig(i,:) * ctranspose(LFsig(i,:)) ./ Nx;
Py = HFsig(j,:) * ctranspose(HFsig(j,:)) ./ Ny;
Cxy = LFsig(i,:) * ctranspose(HFsig(j,:)) ./ Nxy;

cohdata(i,j) = Cxy / sqrt(Px * Py);
end
end
Expand Down
1 change: 1 addition & 0 deletions ft_databrowser.m
Expand Up @@ -162,6 +162,7 @@
hascomp = hasdata && ft_datatype(data, 'comp'); % can be 'raw+comp' or 'timelock+comp'

% check if the input cfg is valid for this function
cfg = ft_checkconfig(cfg, 'forbidden', {'channels'});
cfg = ft_checkconfig(cfg, 'unused', {'comps', 'inputfile', 'outputfile'});
cfg = ft_checkconfig(cfg, 'renamed', {'zscale', 'ylim'});
cfg = ft_checkconfig(cfg, 'renamedval', {'ylim', 'auto', 'maxabs'});
Expand Down
30 changes: 16 additions & 14 deletions ft_denoise_dssp.m
Expand Up @@ -47,20 +47,22 @@
% check the input data
datain = ft_checkdata(datain, 'datatype', {'raw'}); % FIXME how about timelock and freq?

cfg = ft_checkconfig(cfg, 'renamed', {'hdmfile', 'headmodel'});
cfg = ft_checkconfig(cfg, 'renamed', {'vol', 'headmodel'});
cfg = ft_checkconfig(cfg, 'renamed', {'grid', 'sourcemodel'});

% get the options
cfg.trials = ft_getopt(cfg, 'trials', 'all', 1);
cfg.channel = ft_getopt(cfg, 'channel', 'all');
cfg.sourcemodel = ft_getopt(cfg, 'sourcemodel');
cfg.dssp = ft_getopt(cfg, 'dssp'); % sub-structure to hold the parameters
cfg.dssp.n_space = ft_getopt(cfg.dssp, 'n_space', 'all'); % number of spatial components to retain from the Gram matrix
cfg.dssp.n_in = ft_getopt(cfg.dssp, 'n_in', 'all'); % dimensionality of the Bin subspace to be used for the computation of the intersection
cfg.dssp.n_out = ft_getopt(cfg.dssp, 'n_out', 'all'); % dimensionality of the Bout subspace to be used for the computation of the intersection
cfg.dssp.n_intersect = ft_getopt(cfg.dssp, 'n_intersect', 0.9); % dimensionality of the intersection
cfg.output = ft_getopt(cfg, 'output', 'original');
% check if the input cfg is valid for this function
cfg = ft_checkconfig(cfg, 'forbidden', {'channels'});
cfg = ft_checkconfig(cfg, 'renamed', {'hdmfile', 'headmodel'});
cfg = ft_checkconfig(cfg, 'renamed', {'vol', 'headmodel'});
cfg = ft_checkconfig(cfg, 'renamed', {'grid', 'sourcemodel'});

% set the defaults
cfg.trials = ft_getopt(cfg, 'trials', 'all', 1);
cfg.channel = ft_getopt(cfg, 'channel', 'all');
cfg.sourcemodel = ft_getopt(cfg, 'sourcemodel');
cfg.dssp = ft_getopt(cfg, 'dssp'); % sub-structure to hold the parameters
cfg.dssp.n_space = ft_getopt(cfg.dssp, 'n_space', 'all'); % number of spatial components to retain from the Gram matrix
cfg.dssp.n_in = ft_getopt(cfg.dssp, 'n_in', 'all'); % dimensionality of the Bin subspace to be used for the computation of the intersection
cfg.dssp.n_out = ft_getopt(cfg.dssp, 'n_out', 'all'); % dimensionality of the Bout subspace to be used for the computation of the intersection
cfg.dssp.n_intersect = ft_getopt(cfg.dssp, 'n_intersect', 0.9); % dimensionality of the intersection
cfg.output = ft_getopt(cfg, 'output', 'original');

% select channels and trials of interest, by default this will select all channels and trials
tmpcfg = keepfields(cfg, {'trials', 'channel', 'tolerance', 'showcallinfo'});
Expand Down
4 changes: 3 additions & 1 deletion ft_denoise_pca.m
Expand Up @@ -81,6 +81,9 @@
varargin{i} = ft_checkdata(varargin{i}, 'datatype', 'raw');
end

% check if the input cfg is valid for this function
cfg = ft_checkconfig(cfg, 'forbidden', {'channels'});

% set the defaults
cfg.refchannel = ft_getopt(cfg, 'refchannel', 'MEGREF');
cfg.channel = ft_getopt(cfg, 'channel', 'MEG');
Expand All @@ -91,7 +94,6 @@
cfg.feedback = ft_getopt(cfg, 'feedback', 'none');
cfg.updatesens = ft_getopt(cfg, 'updatesens', 'yes');


if istrue(cfg.pertrial)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% iterate over trials
Expand Down

0 comments on commit 786b527

Please sign in to comment.