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