Back to the main page.

Bug 3393 - ft_sourceplot cannot deal with trialaveraged data following ft_selectdata

Status CLOSED FIXED
Reported 2017-12-30 06:42:00 +0100
Modified 2022-03-21 16:21:10 +0100
Product: FieldTrip
Component: plotting
Version: unspecified
Hardware: PC
Operating System: Mac OS
Importance: P5 normal
Assigned to: Jan-Mathijs Schoffelen
URL:
Tags:
Depends on:
Blocks:
See also:

Arjen Stolk - 2017-12-30 06:42:17 +0100

The issue is due to an incorrect dimension of freq.powspctrm, but I'm not sure whether it needs to be addressed in ft_sourceplot or in ft_selectdata. Any thoughts? The issue occurs as follows: cfg = []; cfg.frequency = [70 150]; cfg.avgoverfreq = 'yes'; cfg.latency = [0 0.8]; cfg.avgovertime = 'yes'; cfg.avgoverrpt = 'yes'; freq_sel = ft_selectdata(cfg, freq_blc); which results in (note the 1 x 145 dim of powspctrm): ans = struct with fields: label: {145×1 cell} dimord: 'rpt_chan_freq_time' freq: 110.1471 time: 0.4000 elec: [1×1 struct] trialinfo: 711.5385 powspctrm: [1×145 double] cfg: [1×1 struct] The 1 x 145 dim of powspctrm will cause the following line (274) in ft_sourceplot to produce: functional = ft_checkdata(functional, 'datatype', {'source', 'volume'}, 'feedback', 'yes', 'hasunit', 'yes'); functional = struct with fields: pos: [145×3 double] unit: 'mm' freq: 110.1471 time: 0.4000 inside: [145×1 logical] which due to the missing powspctrm and powspctrmdimord will cause the plotting to fail. Flipping the dimension of freq_sel.powspctrm (freq_sel.powspctrm = freq_sel.powspctrm') makes ft_sourceplot run through and functional look as follows: functional = struct with fields: pos: [145×3 double] unit: 'mm' powspctrm: [145×1 double] powspctrmdimord: 'pos_freq_time' freq: 110.1471 time: 0.4000 inside: [145×1 logical]


Jan-Mathijs Schoffelen - 2018-01-05 12:18:15 +0100

well, my thought is to look into ft_checkdata. somehow, you want to convert sensor-level type data into a source-type data. in the conversion, you lose the data field with the stuff you want to plot


Arjen Stolk - 2018-01-05 17:59:37 +0100

Thanks for your response. It's true that after the conversion this is lost but only because the powspctrm field of the input is 1 x 145 and not 145 x 1 (following ft_selectdata). I guess my main question is: should averaging over trials with ft_selectdata result in a 1 x 145 powspctrm in the output (the input is rpt_chan_freq_time)? For convenience, the respective code: cfg = []; cfg.frequency = [70 150]; cfg.avgoverfreq = 'yes'; cfg.latency = [0 0.8]; cfg.avgovertime = 'yes'; cfg.avgoverrpt = 'yes'; freq_sel = ft_selectdata(cfg, freq_blc); which results in (note the 1 x 145 dim of powspctrm): ans = struct with fields: label: {145×1 cell} dimord: 'rpt_chan_freq_time' freq: 110.1471 time: 0.4000 elec: [1×1 struct] trialinfo: 711.5385 powspctrm: [1×145 double] cfg: [1×1 struct]


Arjen Stolk - 2018-01-05 18:25:55 +0100

Since we're here talking ft_selectdata, let me drop in another observation from a colleague related to ft_selectdata: "when I use ft_selectdata to then narrow the time range with .latency (this is timelock data), I get a warning that it contains fields with and without repeats, and it keeps .trial and tosses .avg and .var" Is this new and intended behavior, in an attempt to disambiguate output (just like with ft_mvaranalysis and ft_regressconfound)?


Arjen Stolk - 2018-01-05 18:27:04 +0100

In other words: are the simultaneous occurrences of the avg and trial field in a timelock structure no longer allowed?


Jan-Mathijs Schoffelen - 2018-01-06 17:16:09 +0100

(In reply to Arjen Stolk from comment #4) No, presence of trial and avg/var/dof is ambiguous and avg/dof/var are intentionally removed. If your colleague wants to do the operation on the average, ft_selectdata should be called with a tlck structure that has been obtained without cfg.keeptrials.


Arjen Stolk - 2018-01-06 20:47:54 +0100

Thanks. In the meantime, I've narrowed the above problem down to a few possibilities, but it's getting over my head in terms of what are the intended behaviors of the respective functionalities: 1) get_dimord (at line 242) thinks the data is rpt_chan_freq_time, which ft_checkdata does not check for at line 1281: fn = fieldnames(data); fn = setdiff(fn, {'label', 'time', 'freq', 'hdr', 'cfg', 'grad', 'elec', 'dimord', 'unit'}); % remove irrelevant fields fn(~cellfun(@isempty, regexp(fn, 'dimord$'))) = []; % remove irrelevant (dimord) fields sel = false(size(fn)); for i=1:numel(fn) try sel(i) = ismember(getdimord(data, fn{i}), {'chan', 'chan_time', 'chan_freq', 'chan_freq_time', 'chan_chan'}); end end parameter = fn(sel); As a result, parameter becomes empty. 2) Simply adding rpt_chan_freq_time to this checklist causes the data to be correctly converted, including a powsptrcm field and a rpt_pos_freq_time dimord. However, it throws issues further down the line in ft_sourceinterpolate: Assignment has more non-singleton rhs dimensions than non-singleton subscripts Error in ft_sourceinterpolate (line 337) allav(:,k,m) = av; Error in ft_sourceplot (line 335) functional = ft_sourceinterpolate(tmpcfg, functional, anatomical); CODE: for c = 1:10 freq.label{c,1} = num2str(c); end freq.freq = 1; freq.time = 1; freq.powspctrm = rand(1,10); freq.dimord = 'chan_freq_time'; freq.elec.elecpos = randn(10,3); freq.elec.chanpos = freq.elec.elecpos; freq.elec.label = freq.label; freq.elec.unit = 'mm'; mesh.pos = randn(117024,3); mesh.tri = randn(234044,3); mesh.unit = 'mm'; mesh.coordsys = 'acpc'; cfg = []; cfg.funparameter = 'powspctrm'; cfg.funcolorlim = [-.5 .5]; cfg.method = 'surface'; cfg.interpmethod = 'sphere_weighteddistance'; cfg.sphereradius = 8; ft_sourceplot(cfg, freq, mesh);


Jan-Mathijs Schoffelen - 2018-01-09 13:19:16 +0100

Just for convenience, I took over the assignment. The functionality breaks (after allowing for 'rpt_*' dimords in ft_checkdata, because ft_sourceinterpolate cannot deal with 'rpt_*' data, even if the rpt is singleton. I think that this is by design, although an informative error would have been appropriate. Yet, I think the ft_checkdata - based in principle should allow for chan2source conversion, justifying the addition of 'rpt_*' dimords when doing the parameter selection. I notice that ft_selectdata has an option cfg.keeprptdim, which I think should git rid of the 'rpt_*' in combination with cfg.avgoverrpt = 'yes' I have written a test function, and am trying to test all this, but at the moment the cluster is really slow, and it's getting a bit annoying. Will try again soon.


Jan-Mathijs Schoffelen - 2018-01-09 17:09:20 +0100

OK, it seems as if ft_selectdata does not appropriately reshape the powspctrm, even if cfg.keeprptdim is set to 'yes'; This is tracked to the squeezedim subfunction in ft_selectdata, where in case of a vectorial input, the data is not reshaped.


Arjen Stolk - 2018-01-09 17:32:54 +0100

Sleuth JM strikes gold! Does that mean that the powspctrm field should have been 1 x 145, rather than 145 x 1, after calling ft_selectdata on rpt_chan_freq_time data?


Jan-Mathijs Schoffelen - 2022-03-21 16:21:02 +0100

This looks closable to me