Back to the main page.

Bug 1729 - unequal frequency axis cannot be plotted properly (ft_singleplotTFR/ft_plot_matrix)

Reported 2012-09-20 14:39:00 +0200
Modified 2015-07-15 13:31:22 +0200
Product: FieldTrip
Component: plotting
Version: unspecified
Hardware: PC
Operating System: Windows
Importance: P3 normal
Assigned to: Jan-Mathijs Schoffelen
Depends on:
See also:

Jörn M. Horschig - 2012-09-20 14:39:32 +0200

This is related to Haiteng's recent mail on the mailinglist. In short, he did a TFR on low frequencies using a Hann taper and one on high frequencies using DPSS tapers. Then, he concatenated the two datasets. In the end, his frequency axis looked like this [4:30 35:5:100] When plotting from 4 to 30Hz, his TFR looked fine. However, when including higher frequencies, he realized that his frequency axis 'shifted' towards higher frequencies. My first hinge was, that the frequency axis is not handles properly in FieldTrip. I underestimated FieldTrip - my sincere apologies. FieldTrip is passing correctly the .freq field over to ft_plot_matrix. ft_plot_matrix, which is doing the work for singleplotTFR, is internally calling Matlabs built-in funciton imagesc, which cannot deal with these kind of data and axes. Here a quick example which illustrates the problem: xvalues = [1:10 15:5:40]; yvalues = [1:10 15:5:40]; cvalues = xvalues'*yvalues; figure; subplot(211) imagesc(xvalues, yvalues, cvalues) xvalues = linspace(1, 40, numel(xvalues)); yvalues = linspace(1, 40, numel(yvalues)); subplot(212) imagesc(xvalues, yvalues, cvalues); Although 'frequency-time' tiles in the first subplot should have different sizes, both subplot look exactly the same. This means, that Matlab cannot handle such a thing properly. Long story, short fix: Internally, look for the minimal distance within the frequency-axis min(diff(freq)), reconstruct the full frequency axis and interpolate (nearest-neighbour interpolation!) the 'missing' frequency bins. All this should of course happen in ft_plot_matrix, since it's a graphical issue and not some data handling thingy. I would pursue this, if agreed upon. When I receive no comments until Wednesday, I'll bring this up in the FT-meeting and we'll spend some time discussing it. Sounds like a bit like a threat, doesn't it? :P

Jörn M. Horschig - 2012-09-20 14:43:14 +0200

Created attachment 313 Haiteng's TFRs - note the shift of main activity from 10Hz to 20Hz when using more frequency bins.

Jan-Mathijs Schoffelen - 2012-09-20 14:56:40 +0200

Yes, but fieldtrip/plotting/private contains uimage and uimagesc which should be able to deal with this (to some extent, that is). I think in the past these functions were operational, but removed from the higher level plotting functions either due to non-robust behaviour, or due to the overhaul and move to the new intermediate level plotting functions.

Jörn M. Horschig - 2012-09-20 16:22:58 +0200

hm, so?

Robert Oostenveld - 2012-09-20 16:23:34 +0200

I have made a test scrip, please have a look at it. It goes like this freq.label = {'chan'}; freq.time = 0; freq.freq = [1:10 21:30]; freq.powspcrtm = zeros(1, 20, 1); freq.powspcrtm(:) = freq.freq; freq.dimord = 'chan_freq_time'; manzana> svn commit ft_singleplotTFR.m Sending ft_singleplotTFR.m Transmitting file data . Committed revision 6500. manzana> svn commit test/test_bug1729.m Adding test/test_bug1729.m Transmitting file data . Committed revision 6501.

Robert Oostenveld - 2012-09-20 16:26:22 +0200

see bug 419 and bug 250

Jörn M. Horschig - 2012-09-20 16:29:31 +0200

I plus-oned your test script commit on google code ;) Would still need to know whether to use uimage* or the manual fix

Robert Oostenveld - 2012-09-20 17:05:05 +0200

(In reply to comment #6) It seems to me that uimagesc is being used, but that it manzana> grep uimagesc *.m ft_plot_matrix.m:% the uimagesc-call needs to be here to avoid calling it several times in switch-highlight ft_plot_matrix.m: h = uimagesc(hdat, vdat, cdat, clim); ft_plot_matrix.m:% the uimagesc-call needs to be inside switch-statement, otherwise 'saturation' will cause it to be called twice ft_plot_matrix.m: h = uimagesc(hdat, vdat, cdat, clim); except when highlightstype=saturation, because that causes the normal imagesc to be called.

Robert Oostenveld - 2012-09-20 17:05:38 +0200

(In reply to comment #0) xvalues = [1:10 15:5:40]; yvalues = [1:10 15:5:40]; cvalues = xvalues'*yvalues; figure; subplot(211) uimagesc(xvalues, yvalues, cvalues) xvalues = linspace(1, 40, numel(xvalues)); yvalues = linspace(1, 40, numel(yvalues)); subplot(212) uimagesc(xvalues, yvalues, cvalues); works correctly, so I think uimage should be able to do it. But then... why is it not doing it properly?

Jörn M. Horschig - 2012-09-24 13:38:50 +0200

I'm pretty sure that I stepped through the function and the call was to imagesc rather than uimagesc Nathan Weisz sent me a mail suggesting to use contourf instead. His main motivation for using contourf is the (nicer) interpolation, but apparently it can also deal with unequal frequency axes. Also, he said that he once had a similar problem and Ingrid replied on the mailinglist to his question (but he does not recall what she replied). Gonna look that up. I assume to keep it consistent, the use of uimagesc would be preferred over contourf?

Jörn M. Horschig - 2012-09-24 13:49:38 +0200

example code: xvalues = [1:10 15:5:40]; yvalues = [1:10 15:5:40]; cvalues = xvalues'*yvalues; nlines = (numel(yvalues)*numel(xvalues))/4; figure; subplot(211) [ch ch] = contourf(xvalues, yvalues, cvalues, nlines) set(ch,'edgecolor','none'); xvalues = linspace(1, 40, numel(xvalues)); yvalues = linspace(1, 40, numel(yvalues)); subplot(212) [ch ch] = contourf(xvalues, yvalues, cvalues, nlines); set(ch,'edgecolor','none');

Jörn M. Horschig - 2012-10-24 10:35:45 +0200

aha, stepping throigh the function reveals that indeed uimagesc is used, but then a 'quick fix' is applied, which ruins it all. h = uimagesc(hdat, vdat, cdat, clim); set(h,'CData',cdat); % quick fix The reason why this is applied is because in the next step an alpha map is set which in turn needs to have the same dimensionality as the color data. set(h,'AlphaData',highlight); uimagesc however does some magic interpolation. Since we do not know what magic interpolation is happening here, I decided to go for this dirty but most efficient approach: h = uimagesc(hdat, vdat, highlight, clim); highlight = get(h, 'CData'); h = uimagesc(hdat, vdat, cdat, clim); set(h,'AlphaData',highlight); An alternative would be to copy out the interpolation steps from uimage.m (which to my surprise is a private FieldTrip function) to ft_plot_matrix. I kept the quick&dirty approach for now cause it is more robust towards changes in uimage, okilidokili?

Jörn M. Horschig - 2012-11-28 17:53:51 +0100

no complaints + no comments = good fix ;)

Jan-Mathijs Schoffelen - 2015-05-09 17:33:01 +0200

regression function fails. This is caused by the fact that getdimord is not robust enough when trailing dimensions are singleton. Specifically, when a 'dimord' is in the datastructure, a check is performed whether the length of tokenize(dimord) is equal to the length(size(dataparameter)). For the latter, trailing singletons are not in the output of size

Jan-Mathijs Schoffelen - 2015-05-09 17:59:40 +0200

[jansch@mentat002 private]$ svn commit -m "enhancement - made function more robust against trailing singleton-length dimensions" getdimord.m Sending getdimord.m Transmitting file data . Committed revision 10400. this change fixes test_bug1729 and test_ft_selectdata still seems to work...