Code covered by the BSD License  

Highlights from
Mass Univariate ERP Toolbox

image thumbnail
from Mass Univariate ERP Toolbox by David Groppe
Functions for performing and visualizing mass univariate analyses of event-related potentials.

sig_topo(GND_GRP_specGND_or_fname,test_id,varargin)
% sig_topo() - Plots scalp topographies of EEG efffects that have been
%              tested for significance in a family of tests.  Only works for
%              EEG effects derived from averaging time points within 
%              time windows (for tests of every single time point within
%              time windows use gui_erp.m or gui_pow.m).  Topographies can 
%              be visualized in microvolts (for ERPs), decibels (for spectral
%              power), or t-scores.
%             
% Usage:
%  >> sig_topo(GND_GRP_specGND_or_fname,test_id,varargin)
%
% Required Inputs:
%  GND_GRP_specGND_or_fname - A GND, GRP, or specGND structure variable or the 
%                             filename of such a variable that has
%                             been saved to disk. If you specifiy a filename be
%                             sure to include the file's path, unless the file is
%                             in the current working directory.
%  test_id          - [integer] The index # of the t-test results 
%                     stored in the GND/GRP/specGND variable that you wish to visualize.  
%                     To see what test results are available, look at 
%                     the "t_tests" field of your variable (e.g., GND.t_tests)
%                     or use the functions headinfo.m or headinfo_spec.m.
%
% Optional Inputs:
%  fig_id           - [integer] The index # of the MATLAB figure in which
%                     the diagram will be produced.  Useful for overwriting
%                     old figures. {default: lowest unused index}
%  units            - ['uV','dB', or 't'] If 'uV' topographies will be 
%                     visualized in units of microvolts.  If 'dB' spectral  
%                     power will be shown in decibels (10*log10((uV^2)/Hz)). 
%                     If 't', they will be shown in t-scores. {default: 't'}
%  title_on         - [0 or 1] If 1, the bin # and bin descriptor will be
%                     printed at the top of the figure. {default: 1}
%  one_scale        - [0 or 1] If 1, all topographies will be plot using
%                     the same color scale (useful for comparing effect 
%                     sizes across topographies).  If 0, each topography
%                     will be plot using a color scale tailored to it
%                     (provides maximal resolution of topography
%                     distribution).  {default: 1 if plotting in uV or dB, 
%                     0 if plotting t-scores}
%  scale_limits     - [min_value max_value] Minimum and maximum value of
%                     color scale used to illustrate topographies (e.g.,
%                     [-10 10]). If specified, one_scale parameter is set
%                     to 1. If not specified, color scales are set to +/-
%                     the maximum absolute value of the topography.
%                     {default: not used}                     
%  verblevel        - An integer specifiying the amount of information you want
%                     this function to provide about what it is doing during runtime.
%                     Options are:
%                      0 - quiet, only show errors, warnings, and EEGLAB reports
%                      1 - stuff anyone should probably know
%                      2 - stuff you should know the first time you start working
%                          with a data set {default value}
%                      3 - stuff that might help you debug (show all
%                          reports)
%
% Global Variable:
%   VERBLEVEL - Mass Univariate ERP Toolbox level of verbosity (i.e., tells 
%               functions how much to report about what they're doing during             
%               runtime) set by the optional function argument 'verblevel'
%
% Notes:
% -The printed/exported figure will have the same dimensions as the figure
% on the display.  Thus you can undo figure clutter by re-sizing it.
%
% -Note you need data at least three channels to interpolate a scalp topography.
%
% Author:
% David Groppe
% Kutaslab, 3/2010

%%%%%%%%%%%%%%%% REVISION LOG %%%%%%%%%%%%%%%%%
% 5/6/2010-Made compatible with FDR control
%
% 12/14/2010-Compatible with specGND variables now too
%
% 9/10/2012-scale_limits option added

%%%%%%%%%%%%%%%% FUTURE WORK %%%%%%%%%%%%%%%%%
% -

function sig_topo(GND_GRP_specGND_or_fname,test_id,varargin)

p=inputParser;
p.addRequired('GND_GRP_specGND_or_fname',@(x) ischar(x) || isstruct(x));
p.addRequired('test_id',@(x) isnumeric(x) && (length(x)==1));
p.addParamValue('units','t',@ischar);
p.addParamValue('fig_id',[],@(x) isnumeric(x) && (length(x)==1));
p.addParamValue('title_on',1,@(x) isnumeric(x) && (length(x)==1));
p.addParamValue('one_scale',[],@(x) isnumeric(x) && (length(x)==1));
p.addParamValue('verblevel',[],@(x) isnumeric(x) && (length(x)==1));
p.addParamValue('scale_limits',[],@(x) isnumeric(x) && (length(x)==2));

p.parse(GND_GRP_specGND_or_fname,test_id,varargin{:});

% Manage VERBLEVEL
if isempty(p.Results.verblevel),
    VERBLEVEL=2; %not global, just local
else
    VERBLEVEL=p.Results.verblevel;
end

if ~(strcmpi(p.Results.units,'t') || strcmpi(p.Results.units,'uV') || strcmpi(p.Results.units,'dB'))
    error('Value of optional input ''units'' must be ''t'', ''uV'', or ''dB''.');
end
    
%Load GND, GRP, or specGND struct
if ischar(GND_GRP_specGND_or_fname),
    fprintf('Loading GND, GRP, or specGND struct variable from file %s.\n',GND_GRP_specGND_or_fname);
    load(GND_GRP_specGND_or_fname,'-MAT');
    if ~exist('GND','var') && ~exist('GRP','var') && ~exist('specGND','var')
        error('File %s does not contain a GND, GRP, or specGND variable.',GND_GRP_specGND_or_fname);
    end
    if exist('GRP','var'),
        GND=GRP; %for simplicity GRP variables are re-named GND
        clear GRP;
    elseif exist('specGND','var'),
        GND=specGND; %for simplicity specGND variables are re-named GND
        clear specGND;
    end
    VerbReport(sprintf('Experiment: %s',GND.exp_desc),2,VERBLEVEL);
else
    GND=GND_GRP_specGND_or_fname; %for simplicity GRP and specGND variables are re-named GND
    clear GND_GRP_specGND_or_fname;
end

n_test=length(GND.t_tests);
if test_id>n_test,
   error('There are only %d t-tests stored with these data, but you requested Test #%d',n_test,test_id); 
end

if isfield(GND.t_tests(1),'freq_band')
    % We're dealing with spectral power analysis.  Create temporary fields 
    % to make frequency domain plotting compatible easily compatible with time domain plot
    GND.t_tests(test_id).time_wind=GND.t_tests(test_id).freq_band;
    GND.t_tests(test_id).mean_wind=GND.t_tests(test_id).mean_band;
    GND.t_tests(test_id).used_tpt_ids=GND.t_tests(test_id).used_freq_ids;
    GND.grands_t=GND.grands_pow_dB_t;
    GND.grands=GND.grands_pow_dB;
    freq_step=GND.freqs(2)-GND.freqs(1);
    freq_ord=orderofmag(freq_step);
    ord_pow=log10(freq_ord); %useful for formatting topo titles
    if ord_pow>=0,
        n_dig_past_dot=0;
    else
        n_dig_past_dot=-ord_pow;
    end
    GND.time_pts=rnd_orderofmag(GND.freqs);
    freq_domain=1;
    if strcmpi(p.Results.units,'uV'),
       watchit('You can''t plot spectral power topographies in units of microvolts.  They will be plot in decibels (i.e., 10*log10((uV^2)/Hz))) instead.');
    end
else
    freq_domain=0;
    if strcmpi(p.Results.units,'dB'),
        watchit('You can''t plot ERP topographies in units of decibels.  They will be plot in microvolts instead.');
    end
end

if ~strcmpi(GND.t_tests(test_id).mean_wind,'yes'),
   error('sig_topo.m only works for significance tests applied to data averaged across multiple time points.'); 
end

n_topos=length(GND.t_tests(test_id).used_tpt_ids);
wdth=floor(sqrt(n_topos));
ht=ceil(n_topos/wdth);

bin=GND.t_tests(test_id).bin;
chans=GND.t_tests(test_id).used_chan_ids;
if length(chans)<3,
   watchit('sig_topo.m cannot plot scalp topographies with less than 3 electrodes.');
   return
end
if isempty(p.Results.fig_id)
    fig_h=figure;
else
    fig_h=figure(p.Results.fig_id); clf;
end
if isfield(GND,'bin_info'),
    set(fig_h,'name',['Bin ' int2str(bin) ' [' GND.bin_info(bin).bindesc ']'],'paperpositionmode','auto');
else
    set(fig_h,'name',['Bin ' int2str(bin) ' [' GND.bindesc{bin} ']'],'paperpositionmode','auto');
end
%setting paperpositionmode to 'auto' means that if the figure is manually
%resized, the printed version of the figure will reflect whatever the
%shown size was (at the time of printing)

if strcmpi(p.Results.units,'uV') || strcmpi(p.Results.units,'dB') ,
    if freq_domain,
        units='dB';
    else
        units='\muV';
    end
    %Compute mean voltage or spectral power in each time window
    mns=zeros(length(chans),n_topos);
    for w=1:n_topos,
        mns(:,w)=mean(GND.grands(chans,GND.t_tests(test_id).used_tpt_ids{w},bin),2);
    end
    if ~isempty(p.Results.scale_limits)
        one_scale=1;
        maplimits=p.Results.scale_limits;
        VerbReport(sprintf('Using color scale limits of: %f to %f',maplimits(1),maplimits(2)),2,VERBLEVEL);
        VerbReport(sprintf('All topographies will have the same color scale.'),2,VERBLEVEL);
    elseif isempty(p.Results.one_scale) || (p.Results.one_scale<=0),
        one_scale=0;
        maplimits='absmax';
    else
        one_scale=1;
        mx=max(max(abs(mns)));
        maplimits=[-1 1]*mx;
    end
else
    units='t';
    if ~isempty(p.Results.scale_limits)
        one_scale=1;
        maplimits=p.Results.scale_limits;
        VerbReport(sprintf('Using color scale limits of: %f to %f',maplimits(1),maplimits(2)),2,VERBLEVEL);
        VerbReport(sprintf('All topographies will have the same color scale.'),2,VERBLEVEL);
    elseif isempty(p.Results.one_scale) || (p.Results.one_scale>0),
        one_scale=1;
        mx=max(max(abs(GND.t_tests(test_id).data_t)));
        maplimits=[-1 1]*mx;
    else
        one_scale=0;
        maplimits='absmax';
    end
end

if VERBLEVEL,
    if isnan(GND.t_tests(test_id).n_perm),
        fprintf('q level of critical t-scores: %f., FDR method: %s\n', ...
            GND.t_tests(test_id).desired_alphaORq,GND.t_tests(test_id).mult_comp_method);
    else
        fprintf('Estimated alpha level of critical t-scores: %f.\n', ...
            GND.t_tests(test_id).estimated_alpha);
    end
end

for a=1:n_topos,
    subplot(ht,wdth,a);
    time_wind=GND.t_tests(test_id).time_wind(a,:);
    if strcmpi(p.Results.units,'uV') || strcmpi(p.Results.units,'dB') ,
        mn=mns(:,a);
    else
        mn=GND.t_tests(test_id).data_t(:,a);
    end
    
    if isnan(GND.t_tests(test_id).n_perm),
        sig_chans=find(GND.t_tests(test_id).fdr_rej(:,a));
    else
        sig_chans=find(GND.t_tests(test_id).adj_pval(:,a)<GND.t_tests(test_id).estimated_alpha);
    end
    topoplotMK(mn,GND.chanlocs(chans),'emarker2',{sig_chans,'o',[1 1 1],4}, ...
        'maplimits',maplimits);
    if freq_domain,
        lab_form=['%.' int2str(n_dig_past_dot) 'f-%.' int2str(n_dig_past_dot)  'f Hz'];
    else
        lab_form='%d-%d ms';
    end
    
    hh=title(sprintf(lab_form,time_wind(1),time_wind(2)));
    if ~one_scale,
        hcb=colorbar;
        hy=ylabel(hcb,units);
        set(hy,'rotation',0,'verticalalignment','middle','position',[4.9+n_topos*.2 0.03 1.0001]);
    end
end

if one_scale,
    hcb=cbar_nudge('vert',0,maplimits);
    hy=ylabel(hcb,units);
    set(hy,'rotation',0,'verticalalignment','middle');
end

% Plot title of entire figure
if p.Results.title_on,      
    if isfield(GND,'bin_info'),
        h=textsc(['Bin ' int2str(bin) ': ' GND.bin_info(bin).bindesc],'title');
    else
        h=textsc(['Bin ' int2str(bin) ': ' GND.bindesc{bin}],'title');
    end
    set(h,'fontsize',14,'fontweight','bold');
end


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% cbar_nudge (plots colorbar slightly to left of cbar.m
% search for "DG change" to find the line I edited
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [handle]=cbar_nudge(arg,colors,minmax, grad)

if nargin < 2
  colors = 0;
end
posscale = 'off';
if nargin < 1
  arg = 'vert';
  ax = [];
else
  if isempty(arg)
    arg = 0;
  end
  if arg(1) == 0
    ax = [];
    arg = 'vert';
  elseif strcmpi(arg, 'pos')
    ax = [];
    arg = 'vert';
    posscale = 'on';
  else      
    if isstr(arg)
      ax = [];
    else
      ax = arg;
      arg = [];
    end
  end
end

if nargin>2
  if size(minmax,1) ~= 1 | size(minmax,2) ~= 2
    help cbar
    fprintf('cbar() : minmax arg must be [min,max]\n');
    return
  end
end
if nargin < 4
    grad = 5;
end;


%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Choose colorbar position
%%%%%%%%%%%%%%%%%%%%%%%%%%%

if (length(colors) == 1) & (colors == 0)
  t = caxis;
else
  t = [0 1];
end
if ~isempty(arg)
  if strcmp(arg,'vert')  
    cax = gca;
    pos = get(cax,'Position');
    stripe = 0.04; 
    edge = 0.01;
    space = -.02;

    set(cax,'Position',[pos(1) pos(2) pos(3) pos(4)])
    rect = [pos(1)+pos(3)+space pos(2) stripe*pos(3) pos(4)];
    ax = axes('Position', rect);
  elseif strcmp(arg,'horiz')
    cax = gca;
    pos = get(cax,'Position');
    stripe = 0.075; 
    space = .1;  
    set(cax,'Position',...
        [pos(1) pos(2)+(stripe+space)*pos(4) pos(3) (1-stripe-space)*pos(4)])
    rect = [pos(1) pos(2) pos(3) stripe*pos(4)];
    ax = axes('Position', rect);
  end
else
  pos = get(ax,'Position');
  if pos(3) > pos(4)
    arg = 'horiz';
  else
    arg = 'vert';
  end
end
  
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Draw colorbar using image()
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

map = colormap;
n = size(map,1);

if length(colors) == 1
  if strcmp(arg,'vert')
      if strcmpi(posscale, 'on')
          image([0 1],[0 t(2)],[ceil(n/2):n-colors]');
      else
          image([0 1],t,[1:n-colors]');
      end;
      set(ax,'xticklabelmode','manual')
      set(ax,'xticklabel',[],'YAxisLocation','right')
      
  else
    image(t,[0 1],[1:n-colors]);
    set(ax,'yticklabelmode','manual')
    set(ax,'yticklabel',[],'YAxisLocation','right')
  end
  set(ax,'Ydir','normal','YAxisLocation','right')

else % length > 1

  if max(colors) > n
    error('Color vector excedes size of colormap')
  end
  if strcmp(arg,'vert')
    image([0 1],t,[colors]');
    set(ax,'xticklabelmode','manual')
    set(ax,'xticklabel',[])
  else
    image([0 1],t,[colors]);
    set(ax,'yticklabelmode','manual')
    set(ax,'yticklabel',[],'YAxisLocation','right')
  end  
  set(ax,'Ydir','normal','YAxisLocation','right')
end

%%%%%%%%%%%%%%%%%%%%%%%%%
% Adjust cbar ticklabels
%%%%%%%%%%%%%%%%%%%%%%%%%

if nargin > 2 
  if strcmp(arg,'vert')
      Cax = get(ax,'Ylim');
  else
      Cax = get(ax,'Xlim');
  end;
  CBTicks = [Cax(1):(Cax(2)-Cax(1))/(grad-1):Cax(2)]; % caxis tick positions
  CBLabels = [minmax(1):(minmax(2)-minmax(1))/(grad-1):minmax(2)]; % tick labels
  
  dec = floor(log10(max(abs(minmax)))); % decade of largest abs value
  CBLabels = ([minmax]* [ linspace(1,0, grad);linspace(0, 1, grad)]);
  if dec<1
    CBLabels = round(CBLabels*10^(1-dec))*10^(dec-1);
  elseif dec == 1
    CBLabels = round(CBLabels*10^(2-dec))*10^(dec-2);
  else
    CBLabels = round(CBLabels);
  end

  if strcmp(arg,'vert')
    set(ax,'Ytick',CBTicks);
    set(ax,'Yticklabel',CBLabels);
  else
    set(ax,'Xtick',CBTicks);
    set(ax,'Xticklabel',CBLabels);
  end
end
handle = ax;

%%%%%%%%%%%%%%%%%%
% Adjust cbar tag
%%%%%%%%%%%%%%%%%%

set(ax,'tag','cbar')

Contact us