


multiplot_tfrGND() - Plots bin spectrograms or the difference between bin
spectrograms at multiple channels using the Fieldtrip
function ft_multiplotTFR.m. Plots are derived from a
MATLABmk tfrGND variable and can be masked for
statistical significance if test results have been stored
in the tfrGND variable.
Usage:
>> multiplot_tfrGND(tfrGND,varargin);
Required Input:
tfrGND - A MATLABmk tfrGND variable. These are produced by the
MATLABmk function tfrs2tfrGND.m. It contains spectrograms from
one or more participants, their grand averages, and
associated information.
Optional Inputs:
'bin' - [string] Indicates the number of the bin or the bin
difference you wish to plot. For example, if you
wish to plot the spectrograms for Bin 1, enter '1'.
If you want to plot the spectrograms for Bin 1 minus
those from Bin 2, enter '1=2'. {default: '1'}
'freq_limits' - [min max] Frequency limits (in Hz) of the spectrgrams you
wish to visualize. {default: lowest and highest
frequencies in the tfrGND variable}
'time_limits' - [min max] Time limits (in ms) of the spectrgrams
you wish to visualize. {default: lowest and highest
time points in the tfrGND variable}
'exclude_chans' - A cell array of channel labels or a single channel
label string (e.g., {'A2','lle','rhe'} or 'A2').
These channels will be excluded from the plot. Use
headinfo_spec.m to see the channel labels stored in
the tfrGND variable. You cannot use both this option
and 'include_chans' (below).{default: not used, all
channels included in plot}
'include_chans' - A cell array of channel labels to use in the plot
(e.g., {'MiPf','MiCe','RLPf'}). All other channels
will be ignored. Use headinfo_spec.m to see the
channel labels stored in the tfrGND variable. You
cannot use both this option and 'exclude_chans'
(above). {default: not used, all channels included in
plot}
'color_limits' - [min max] Limits of the spectrogram color scale.
{default: lowest and highest time points in the
tfrGND variable}
'units' - ['dB' or 'raw'] If 'dB' spectrogram color scale will
be in units of decibels 10*log10(uV^2/Hz). If 'raw'
spectrogram color scale will be in units of uV^2/Hz.
{default: whatever the units were when the tfrGND
variable was first created}
'bsln_type' - The type of baseline used to normalize each
participant's data. Default is to use whatever baseline
type was used when the tfrGND variable was first
created. Options are:
'relative' - Power at each time point is divided by
the mean power in the baseline window.
'absolute' - The mean power in the baseline window
is subtracted from the power at each
time point.
'bsln_wind' - [min max] Time window (in ms) used to baseline the
spectrograms {default: whatever baseline window was
originally used with the tfrGND variable}
'interactive' - ['yes' or 'no'] If 'yes', ft_multiplotTFR.m's inter-
active feature wil be activated which allows you draw
a box on the figure and plot the average of all the
spectrograms in the box. {default: 'yes'}
'sub_id' - [integer] The number of the subject whose individual
data you wish to plot. If not specified, grand average
spectrograms will be plot. {default: not specified}
'fig_id' - [integer] The index number of the MATLAB figure in
which the plot will be produced. Useful for over-
writing old figures. {default: lowest unused figure
number}
'test_id' - [integer] The index number of the test results you
want to use to mask the spectrograms. If x, the
results stored in tfrGND.stats{x} will be used.
{default: no masking}
'p_value_mask' - [number between 0 and 1] All voxels with a p-value
less than p_value_mask will be shown as 0. Note, this
argument has no effect if 'test_id' argument is not
used. {default: the alpha level of the test being
visualized}
Author:
David Groppe
Kutaslab, 1/2011

0001 % multiplot_tfrGND() - Plots bin spectrograms or the difference between bin 0002 % spectrograms at multiple channels using the Fieldtrip 0003 % function ft_multiplotTFR.m. Plots are derived from a 0004 % MATLABmk tfrGND variable and can be masked for 0005 % statistical significance if test results have been stored 0006 % in the tfrGND variable. 0007 % 0008 % Usage: 0009 % >> multiplot_tfrGND(tfrGND,varargin); 0010 % 0011 % Required Input: 0012 % tfrGND - A MATLABmk tfrGND variable. These are produced by the 0013 % MATLABmk function tfrs2tfrGND.m. It contains spectrograms from 0014 % one or more participants, their grand averages, and 0015 % associated information. 0016 % 0017 % Optional Inputs: 0018 % 'bin' - [string] Indicates the number of the bin or the bin 0019 % difference you wish to plot. For example, if you 0020 % wish to plot the spectrograms for Bin 1, enter '1'. 0021 % If you want to plot the spectrograms for Bin 1 minus 0022 % those from Bin 2, enter '1=2'. {default: '1'} 0023 % 'freq_limits' - [min max] Frequency limits (in Hz) of the spectrgrams you 0024 % wish to visualize. {default: lowest and highest 0025 % frequencies in the tfrGND variable} 0026 % 'time_limits' - [min max] Time limits (in ms) of the spectrgrams 0027 % you wish to visualize. {default: lowest and highest 0028 % time points in the tfrGND variable} 0029 % 'exclude_chans' - A cell array of channel labels or a single channel 0030 % label string (e.g., {'A2','lle','rhe'} or 'A2'). 0031 % These channels will be excluded from the plot. Use 0032 % headinfo_spec.m to see the channel labels stored in 0033 % the tfrGND variable. You cannot use both this option 0034 % and 'include_chans' (below).{default: not used, all 0035 % channels included in plot} 0036 % 'include_chans' - A cell array of channel labels to use in the plot 0037 % (e.g., {'MiPf','MiCe','RLPf'}). All other channels 0038 % will be ignored. Use headinfo_spec.m to see the 0039 % channel labels stored in the tfrGND variable. You 0040 % cannot use both this option and 'exclude_chans' 0041 % (above). {default: not used, all channels included in 0042 % plot} 0043 % 'color_limits' - [min max] Limits of the spectrogram color scale. 0044 % {default: lowest and highest time points in the 0045 % tfrGND variable} 0046 % 'units' - ['dB' or 'raw'] If 'dB' spectrogram color scale will 0047 % be in units of decibels 10*log10(uV^2/Hz). If 'raw' 0048 % spectrogram color scale will be in units of uV^2/Hz. 0049 % {default: whatever the units were when the tfrGND 0050 % variable was first created} 0051 % 'bsln_type' - The type of baseline used to normalize each 0052 % participant's data. Default is to use whatever baseline 0053 % type was used when the tfrGND variable was first 0054 % created. Options are: 0055 % 'relative' - Power at each time point is divided by 0056 % the mean power in the baseline window. 0057 % 'absolute' - The mean power in the baseline window 0058 % is subtracted from the power at each 0059 % time point. 0060 % 'bsln_wind' - [min max] Time window (in ms) used to baseline the 0061 % spectrograms {default: whatever baseline window was 0062 % originally used with the tfrGND variable} 0063 % 'interactive' - ['yes' or 'no'] If 'yes', ft_multiplotTFR.m's inter- 0064 % active feature wil be activated which allows you draw 0065 % a box on the figure and plot the average of all the 0066 % spectrograms in the box. {default: 'yes'} 0067 % 'sub_id' - [integer] The number of the subject whose individual 0068 % data you wish to plot. If not specified, grand average 0069 % spectrograms will be plot. {default: not specified} 0070 % 'fig_id' - [integer] The index number of the MATLAB figure in 0071 % which the plot will be produced. Useful for over- 0072 % writing old figures. {default: lowest unused figure 0073 % number} 0074 % 'test_id' - [integer] The index number of the test results you 0075 % want to use to mask the spectrograms. If x, the 0076 % results stored in tfrGND.stats{x} will be used. 0077 % {default: no masking} 0078 % 'p_value_mask' - [number between 0 and 1] All voxels with a p-value 0079 % less than p_value_mask will be shown as 0. Note, this 0080 % argument has no effect if 'test_id' argument is not 0081 % used. {default: the alpha level of the test being 0082 % visualized} 0083 % 0084 % 0085 % Author: 0086 % David Groppe 0087 % Kutaslab, 1/2011 0088 0089 %%%%%%%%%%%%%%%% Revision History %%%%%%%%%%%%%%%%% 0090 % 3/17/2011 - I removed the following option, since I'm converting power 0091 % spectra to dB by default when tfrGND variable is created. 0092 % 'baseline_type' - [string] The method (if any) used to baseline the 0093 % spectrograms. Possible options are: 0094 % 'no baseline' = No baseline {default if baseline_wind 0095 % NOT specified} 0096 % 'relative' = Divide power values by mean baseline 0097 % power values. {default if baseline_wind 0098 % specified} 0099 % 'absolute' = Subtract mean baseline power values 0100 % from power values. 0101 0102 0103 0104 0105 function multiplot_tfrGND(tfrGND,varargin) 0106 0107 p=inputParser; 0108 p.addRequired('tfrGND',@isstruct); 0109 p.addParamValue('bin','1',@(x) ischar(x) || isnumeric(x)); %char allows bin differences (e.g., "1-2") 0110 p.addParamValue('freq_limits',[],@(x) isnumeric(x) && length(x)==2); 0111 p.addParamValue('time_limits',[],@(x) isnumeric(x) && length(x)==2); 0112 p.addParamValue('color_limits',[],@(x) (isnumeric(x) && length(x)==2) || ischar(x)); 0113 p.addParamValue('exclude_chans',[],@(x) ischar(x) || iscell(x)); 0114 p.addParamValue('include_chans',[],@(x) ischar(x) || iscell(x)); 0115 p.addParamValue('sub_id',[],@(x) isnumeric(x) && (length(x)==1) && (x>0)); 0116 p.addParamValue('fig_id',[],@(x) isnumeric(x) && length(x)==1); 0117 p.addParamValue('test_id',0,@(x) isnumeric(x) && length(x)==1); 0118 p.addParamValue('interactive','yes',@ischar); 0119 p.addParamValue('units',[],@(x) strcmpi(x,'dB') || strcmpi(x,'raw')); 0120 p.addParamValue('bsln_wind',[],@(x) isnumeric(x) && length(x)==2); 0121 p.addParamValue('bsln_type',[],@(x) strcmpi(x,'relative') || strcmpi(x,'absolute')); 0122 p.addParamValue('p_value_mask',[],@(x) isnumeric(x) && length(x)==1); 0123 0124 p.parse(tfrGND,varargin{:}); 0125 0126 %copy these optional paramters to variables that can be written to 0127 bsln_wind=p.Results.bsln_wind; 0128 bsln_type=p.Results.bsln_type; 0129 units=p.Results.units; 0130 0131 0132 %% Error check inputs 0133 n_subs=size(tfrGND.indiv{1},1); 0134 if ~isempty(p.Results.sub_id) && (p.Results.sub_id>n_subs), 0135 error('You requested to plot Subject %d''s data this tfrGND variable only contains data for %d subjects.', ... 0136 p.Results.sub_id,n_subs); 0137 end 0138 0139 0140 %% if statistical masking is requested, grab the parameters of what to plot 0141 %from the statistical test 0142 if p.Results.test_id, 0143 n_tests=length(tfrGND.stats); 0144 if p.Results.test_id>n_tests, 0145 error('You requested Test %d, but you only have %d tests in this tfrGND variable.', ... 0146 p.Results.test_id,n_tests); 0147 end 0148 if ~strcmpi(tfrGND.stats{p.Results.test_id}.dimord,'chan_freq_time') 0149 error(['"dimord" field of this test is not ''chan_freq_time''. This leads me to believe this test was performed after averaging over time points or frequencies. ', ... 0150 'multiplot_tfrGND.m cannot plot the result of such an analysis.']); 0151 end 0152 if length(tfrGND.stats{p.Results.test_id}.label)==1, 0153 %If only one channel, it's possible test has averaged over channels 0154 if ismember('+',tfrGND.stats{p.Results.test_id}.label{1}) 0155 %Test was performed on the average across channels 0156 error('This test was performed on the average across multiple channels. Using singeplot_tfrGND.m instead.'); 0157 end 0158 end 0159 plot_bins=tfrGND.stats{p.Results.test_id}.bins; 0160 if isempty(p.Results.freq_limits) 0161 freq_limits=[tfrGND.stats{p.Results.test_id}.freq(1) tfrGND.stats{p.Results.test_id}.freq(end)]; 0162 else 0163 freq_limits=p.Results.freq_limits; 0164 end 0165 if isempty(p.Results.time_limits) 0166 time_limits=tfrGND.stats{p.Results.test_id}.cfg.latency; 0167 else 0168 time_limits=p.Results.time_limits/1000; %convert from ms to sec 0169 end 0170 0171 %grab baseline info from test 0172 units=tfrGND.stats{p.Results.test_id}.units; 0173 bsln_wind=tfrGND.stats{p.Results.test_id}.bsln_wind; 0174 bsln_type=tfrGND.stats{p.Results.test_id}.bsln_type; 0175 0176 if isempty(p.Results.p_value_mask) 0177 p_mask=tfrGND.stats{p.Results.test_id}.family_alpha; 0178 else 0179 p_mask=p.Results.p_value_mask; 0180 fprintf('Using requested p-value threshold of %g to mask out data instead of the test p-value of %g\n', ... 0181 p_mask,tfrGND.stats{p.Results.test_id}.family_alpha); 0182 end 0183 0184 n_test_chans=length(tfrGND.stats{p.Results.test_id}.label); 0185 n_all_chans=length(tfrGND.ftrip.label); 0186 if n_all_chans~=n_test_chans, 0187 test_chan_ids=zeros(1,n_test_chans); 0188 cfg.channel=cell(1,n_test_chans); 0189 for a=1:n_test_chans, 0190 test_chan_ids(a)=find(ismember(tfrGND.ftrip.label,tfrGND.stats{p.Results.test_id}.label{a})); 0191 cfg.channel{a}=tfrGND.stats{p.Results.test_id}.label{a}; 0192 end 0193 else 0194 test_chan_ids=1:n_all_chans; 0195 end 0196 else 0197 %statistical masking not requested 0198 plot_bins=p.Results.bin; 0199 if isempty(p.Results.freq_limits), 0200 freq_limits=[tfrGND.ftrip.freq(1) tfrGND.ftrip.freq(end)]; 0201 else 0202 freq_limits=p.Results.freq_limits; 0203 end 0204 if isempty(p.Results.time_limits), 0205 time_limits=[tfrGND.ftrip.time(1) tfrGND.ftrip.time(end)]; 0206 else 0207 time_limits=p.Results.time_limits; 0208 end 0209 0210 %select a subset of channels if requested 0211 if ~isempty(p.Results.include_chans), 0212 if ~isempty(p.Results.exclude_chans), 0213 error('You cannot use both ''exclude_chans'' AND ''include_chans'' options.'); 0214 end 0215 %convert p.Results.include_chans to cell array if just one string passed 0216 if ischar(p.Results.include_chans), 0217 %cfg.channel{1}=p.Results.include_chans; 0218 error('If you only want to plot one channel, use singleplot_tfrGND.m instead.'); 0219 else 0220 cfg.channel=p.Results.include_chans; 0221 end 0222 n_req_chan=length(cfg.channel); 0223 %make sure requested channels exist 0224 for a=1:n_req_chan, 0225 if ~ismember(cfg.channel{a},tfrGND.ftrip.label) 0226 error('There is no channel called %s in this tfrGND variable.',cfg.channel{a}); 0227 end 0228 end 0229 elseif ~isempty(p.Results.exclude_chans), 0230 %convert p.Results.exclude_chans to cell array if just one string passed 0231 if ischar(p.Results.exclude_chans), 0232 exclude_chans{1}=p.Results.exclude_chans; 0233 else 0234 exclude_chans=p.Results.exclude_chans; 0235 end 0236 n_req_chan=length(exclude_chans); 0237 cfg.channel=cell(1,n_req_chan+1); 0238 cfg.channel{1}='all'; %include all but excluded chans 0239 for a=1:n_req_chan, 0240 %make sure requested channels exist 0241 if ~ismember(exclude_chans{a},tfrGND.ftrip.label) 0242 error('There is no channel called %s in this tfrGND variable.',exclude_chans{a}); 0243 else 0244 %add negative sign to show that it's excluded 0245 cfg.channel{a+1}=['-' exclude_chans{a}]; 0246 end 0247 end 0248 end 0249 end 0250 0251 %Copy baseline info to variables that can be overwritten 0252 if isempty(bsln_wind), 0253 bsln_wind=tfrGND.bsln_wind; 0254 end 0255 if isempty(bsln_type), 0256 bsln_type=tfrGND.bsln_type; 0257 end 0258 if isempty(units), 0259 units=tfrGND.units; 0260 end 0261 0262 %Check bin/bins 0263 n_bins=length(tfrGND.bindesc); 0264 0265 %See if user has requested the difference between conditions 0266 neg_id=find(plot_bins=='-'); 0267 if ismember('-',plot_bins), 0268 bin1=str2double(plot_bins(1:(neg_id-1))); 0269 bin2=str2double(plot_bins((neg_id+1):end)); 0270 %make sure bins exist 0271 if isempty(bin1) || isempty(bin2), 0272 error('%s is not a valid bin request.',plot_bins); 0273 elseif bin1>n_bins, 0274 error('You only have %d bins in this tfrGND variable but you requested Bin %d.',n_bins,bin1); 0275 elseif bin2>n_bins, 0276 error('You only have %d bins in this tfrGND variable but you requested Bin %d.',n_bins,bin2); 0277 end 0278 0279 % Transform spectrograms to dB or re-baseline (if requested) 0280 if ~strcmpi(units,tfrGND.units) || ... 0281 ~isequal(bsln_wind,tfrGND.bsln_wind) || ... 0282 ~strcmpi(bsln_type,tfrGND.bsln_type) 0283 tfrGND=baseline_tfrGND(tfrGND,units,bsln_wind,bsln_type,[bin1 bin2]); 0284 end 0285 0286 0287 dif=1; 0288 %Store data to be visualized in tfrGND.ftrip.powspctrm 0289 prefix=[tfrGND.bindesc{bin1} '-' tfrGND.bindesc{bin2}]; 0290 if isempty(p.Results.sub_id), 0291 %grand average spectrograms 0292 tfrGND.ftrip.powspctrm=tfrGND.grands{bin1}-tfrGND.grands{bin2}; 0293 suffix=['(Bin ' int2str(bin1) '-' int2str(bin2) ', Grand)']; 0294 else 0295 %plot spectrogram for an individual subjec 0296 tfrGND.ftrip.powspctrm=squeeze(tfrGND.indiv{bin1}(p.Results.sub_id,:,:,:))- ... 0297 squeeze(tfrGND.indiv{bin2}(p.Results.sub_id,:,:,:)); 0298 suffix=['(Bin ' int2str(bin1) '-' int2str(bin2) ', Sub ' int2str(p.Results.sub_id) ')']; 0299 end 0300 else 0301 if ischar(plot_bins) 0302 bin=str2double(plot_bins); 0303 else 0304 bin=plot_bins; 0305 end 0306 if isempty(bin), 0307 error('%s is not a valid bin request.',plot_bins); 0308 end 0309 %make sure bin exists 0310 if bin>n_bins, 0311 error('You only have %d bins in this tfrGND variable but you requested Bin %d.',n_bins,bin); 0312 end 0313 0314 % Transform spectrograms to dB or re-baseline (if requested) 0315 if ~strcmpi(units,tfrGND.units) || ... 0316 ~isequal(bsln_wind,tfrGND.bsln_wind) || ... 0317 ~strcmpi(bsln_type,tfrGND.bsln_type) 0318 tfrGND=baseline_tfrGND(tfrGND,units,bsln_wind,bsln_type,bin); 0319 end 0320 0321 dif=0; 0322 %Store data to be visualized in tfrGND.ftrip.powspctrm 0323 prefix=tfrGND.bindesc{bin}; 0324 if isempty(p.Results.sub_id), 0325 %plot grand average spectrograms 0326 tfrGND.ftrip.powspctrm=tfrGND.grands{bin}; 0327 suffix=['(Bin ' int2str(bin) ', Grand)']; 0328 else 0329 %plot spectrogram for an individual subject 0330 tfrGND.ftrip.powspctrm=squeeze(tfrGND.indiv{bin}(p.Results.sub_id,:,:,:)); 0331 suffix=['(Bin ' int2str(bin) ', Sub ' int2str(p.Results.sub_id) ')']; 0332 end 0333 end 0334 0335 if isempty(p.Results.color_limits), 0336 cfg.zlim='maxmin'; 0337 else 0338 cfg.zlim=p.Results.color_limits; 0339 end 0340 if dif, 0341 fprintf('Note, the power difference between conditions is always shown in decibels.\n'); 0342 cfg.dB='no'; %add error mesg? 0343 end 0344 cfg.ylim=freq_limits; 0345 cfg.xlim=time_limits; 0346 cfg.showlabels='yes'; 0347 cfg.interactive=p.Results.interactive; 0348 cfg.layout=tfrGND.ftrip.elec; 0349 cfg.elec=tfrGND.ftrip.elec; 0350 0351 0352 %% Mask data according to significance 0353 if p.Results.test_id, 0354 % Find rectangle of spectrogram that corresponds to test limits 0355 freq_ids=find_tpt(tfrGND.stats{p.Results.test_id}.freq(1),tfrGND.ftrip.freq): ... 0356 find_tpt(tfrGND.stats{p.Results.test_id}.freq(end),tfrGND.ftrip.freq); 0357 time_ids=find_tpt(tfrGND.stats{p.Results.test_id}.time(1),tfrGND.ftrip.time): ... 0358 find_tpt(tfrGND.stats{p.Results.test_id}.time(end),tfrGND.ftrip.time); 0359 % freq_ids=find_tpt(freq_limits(1),tfrGND.ftrip.freq):find_tpt(freq_limits(2),tfrGND.ftrip.freq); 0360 % time_ids=find_tpt(time_limits(1),tfrGND.ftrip.time):find_tpt(time_limits(2),tfrGND.ftrip.time); 0361 0362 if 0 0363 %this code reduces the size of the spectrogram to the size of the 0364 %mask. As is, it produces errors because the time and frequency 0365 %limits no longer agree with what's specified in tfrGND.ftrip. I 0366 %could fix it up, but I don't really think it's necessary. We'll 0367 %see. 0368 tfrGND.ftrip.powspctrm=tfrGND.ftrip.powspctrm(:,freq_ids,time_ids); 0369 0370 %make sure size of spectrogram=size of mask 0371 if ~isequal(size(tfrGND.ftrip.powspctrm),size(tfrGND.stats{p.Results.test_id}.prob)), 0372 error('Size of spectrograms doesn''t equal the size of the p-value matrix from the statistical test.'); 0373 end 0374 0375 % multiply pow spectrum by mask (voxels>p_mask will be shown as 0); 0376 tfrGND.ftrip.powspctrm=tfrGND.ftrip.powspctrm.*(tfrGND.stats{p.Results.test_id}.prob<=p_mask); 0377 else 0378 if ~sum(sum(sum(tfrGND.stats{p.Results.test_id}.prob<=p_mask))) 0379 error('No comparisons have a p-value greater than the threshold of %g, thus all data will be masked out. Use a higher value of ''p_value_mask''.', ... 0380 p_mask); 0381 else 0382 tfrGND.ftrip.powspctrm(test_chan_ids,freq_ids,time_ids)=tfrGND.ftrip.powspctrm(test_chan_ids,freq_ids,time_ids).* ... 0383 (tfrGND.stats{p.Results.test_id}.prob<=p_mask); 0384 end 0385 end 0386 end 0387 0388 0389 %% Create multiplot 0390 if isempty(p.Results.fig_id), 0391 figure('renderer','zbuffer'); ft_multiplotTFR(cfg,tfrGND.ftrip); 0392 else 0393 figure(p.Results.fig_id); clf; ft_multiplotTFR(cfg,tfrGND.ftrip); 0394 end 0395 set(gcf,'name',[prefix ' ' suffix]); 0396 0397