PageRenderTime 54ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

/trunk/examples/toolboxes/fieldtrip/topoplot.m

http://brainstream.googlecode.com/
MATLAB | 621 lines | 413 code | 43 blank | 165 comment | 109 complexity | c411b2826e2bf1635279fa2d5f1a9d81 MD5 | raw file
Possible License(s): BSD-3-Clause, AGPL-1.0, LGPL-2.0, GPL-3.0, GPL-2.0, LGPL-2.1, LGPL-3.0, BSD-2-Clause
  1. function [handle] = topoplot(varargin)
  2. % TOPOPLOT plots a topographic map of an EEG or MEG field as a 2-D
  3. % circular view (looking down at the top of the head) using interpolation
  4. % on a fine cartesian grid.
  5. %
  6. % This function is called by topoplotER or topoplotTFR
  7. %
  8. % You can also call this function directly as follows:
  9. % topoplot(cfg, datavector)
  10. % topoplot(cfg, X, Y, datavector)
  11. % topoplot(cfg, X, Y, datavector, Labels)
  12. % topoplot(datavector,'Key1','Value1','Key2','Value2',...)
  13. %
  14. % Inputs can be either:
  15. % datavector = vector of values to be plotted as color
  16. % cfg = configuration structure containing the (optional)
  17. % parameters
  18. % X = x-coordinates for channels in datavector
  19. % Y = y-coordinates for channels in datavector
  20. % Labels = labels for channels in datavector
  21. % or the inputs can be key-value pairs containing the (optional) parameters.
  22. % Every cfg field can be specified using the fieldname as a key in the
  23. % key-value pairs.
  24. %
  25. % if X, Y and Labels are given, cfg.layout is NOT used. If X, Y, and Labels
  26. % are not given, cfg.layout must be given and it is assumed that the
  27. % channels in the datavector exactly mach the channels in the layout.
  28. %
  29. % The layout defines how the channels will be arranged in the 2-D plane.
  30. % You can specify the layout in a variety of ways:
  31. % - you can give the name of an ascii layout file with extension *.lay
  32. % - you can give the name of an electrode file
  33. % - you can give an electrode definition, i.e. "elec" structure
  34. % - you can give a gradiometer definition, i.e. "grad" structure
  35. % If you do not specify any of these, and if the data structure contains an
  36. % electrode or gradiometer structure, that will be used for creating a
  37. % layout.
  38. %
  39. % Optional Parameters and Values
  40. %
  41. % cfg.colormap = any sized colormap, see COLORMAP
  42. % cfg.colorbar = 'yes'
  43. % 'no' (default)
  44. % 'North' inside plot box near top
  45. % 'South' inside bottom
  46. % 'East' inside right
  47. % 'West' inside left
  48. % 'NorthOutside' outside plot box near top
  49. % 'SouthOutside' outside bottom
  50. % 'EastOutside' outside right
  51. % 'WestOutside' outside left
  52. % cfg.interplimits = limits for interpolation (default = 'head')
  53. % 'electrodes' to furthest electrode
  54. % 'head' to edge of head
  55. % cfg.gridscale = scaling grid size (default = 67)
  56. % determines resolution of figure
  57. % cfg.maplimits = 'maxabs' +/- the absolute-max (default = 'maxabs')
  58. % 'maxmin' scale to data range
  59. % [clim1, clim2] user-defined lo/hi
  60. % cfg.style = topoplot style (default = 'both')
  61. % 'straight' colormap only
  62. % 'contour' contour lines only
  63. % 'both' (default) both colormap and contour lines
  64. % 'fill' constant color between lines
  65. % 'blank' just head and electrodes
  66. % cfg.contournum = number of contour lines (default = 6), see CONTOUR
  67. % cfg.shading = 'flat' 'interp' (default = 'flat')
  68. % cfg.interpolation = 'linear','cubic','nearest','v4' (default = 'v4') see GRIDDATA
  69. % cfg.headcolor = Color of head cartoon (default = [0,0,0])
  70. % cfg.hlinewidth = number, Linewidth of the drawn head, nose and ears (default = 2)
  71. % cfg.contcolor = Contourline color (default = [0 0 0])
  72. % cfg.electrodes = 'on','off','labels','numbers','highlights' or 'dotnum' (default = 'on')
  73. % cfg.emarker = Marker symbol (default = 'o')
  74. % cfg.ecolor = Marker color (default = [0 0 0] (black))
  75. % cfg.emarkersize = Marker size (default = 2)
  76. % cfg.efontsize = Font size of electrode labels/numbers (default = 8 pt)
  77. % when cfg.electrodes = 'numbers' or 'labels'
  78. % cfg.comment = string of text
  79. % cfg.commentpos = position of comment (default = 'leftbottom')
  80. % 'lefttop' 'leftbottom' 'middletop' 'middlebottom' 'righttop' 'rightbottom'
  81. % or [x y] coordinates
  82. % or 'title' to place comment as title
  83. % cfg.fontsize = Font size of comment (default = 8 pt)
  84. % cfg.highlight = 'off' or the channel numbers you want to highlight (default = 'off').
  85. % These numbers should correspond with the channels in the data, not in
  86. % the layout file.
  87. % cfg.hlmarker = Highlight marker symbol (default = 'o')
  88. % cfg.hlcolor = Highlight marker color (default = [0 0 0] (black))
  89. % cfg.hlmarkersize = Highlight marker size (default = 6)
  90. % cfg.hllinewidth = Highlight marker linewidth (default = 3)
  91. % cfg.outline = 'scalp' or 'ECog' (default = 'scalp')
  92. %
  93. % Note: topoplot() only works when map limits are >= the max and min
  94. % interpolated data values.
  95. % Undocumented local options:
  96. % cfg.grid
  97. % cfg.maxchans
  98. % cfg.showlabels
  99. % cfg.zlim
  100. % cfg.mask for opacity masking, e.g. with statistical significance
  101. % Copyright (C) 1996, Andy Spydell, Colin Humphries & Arnaud Delorme, CNL / Salk Institute
  102. % Copyright (C) 2004-2009, F.C. Donders Centre, New implementation by Geerten Kramer, based on versions of Ole Jensen and Jan-Mathijs Schoffelen
  103. %
  104. % This program is free software; you can redistribute it and/or modify
  105. % it under the terms of the GNU General Public License as published by
  106. % the Free Software Foundation; either version 2 of the License, or
  107. % (at your option) any later version.
  108. %
  109. % This program is distributed in the hope that it will be useful,
  110. % but WITHOUT ANY WARRANTY; without even the implied warranty of
  111. % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  112. % GNU General Public License for more details.
  113. %
  114. % You should have received a copy of the GNU General Public License
  115. % along with this program; if not, write to the Free Software
  116. % Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  117. %
  118. % $Id: topoplot.m 948 2010-04-21 18:02:21Z roboos $
  119. fieldtripdefs
  120. % deprecation warning
  121. warning('this function is deprecated, please use the topoplotER/TFR function instead');
  122. % Try to detect EEGLAB-style input and give an informative error
  123. % message. The EEGLAB documentation describes the usage as
  124. % >> topoplot(datavector, EEG.chanlocs); % plot a map using an EEG chanlocs structure
  125. % >> topoplot(datavector, 'my_chan.locs'); % read a channel locations file and plot a map
  126. % >> topoplot('example'); % give an example of an electrode location file
  127. % >> [h grid_or_val plotrad_or_grid, xmesh, ymesh]= ...
  128. % topoplot(datavector, chan_locs, 'Input1','Value1', ...);
  129. if nargin==2 && isvector(varargin{1}) && isstruct(varargin{2}) && isfield(varargin{2}, 'labels')
  130. eeglab = 1;
  131. elseif nargin==2 && isvector(varargin{1}) && ischar(varargin{2})
  132. eeglab = 1;
  133. elseif nargin==1 && isequal(varargin{1}, 'example')
  134. eeglab = 1;
  135. elseif nargin>2 && isvector(varargin{1}) && mod(nargin,2)==0 && isstruct(varargin{2}) && isfield(varargin{2}, 'labels')
  136. eeglab = 1;
  137. else
  138. eeglab = 0;
  139. end
  140. if eeglab
  141. % the input resembles the input of the EEGLAB topoplot function
  142. error('Unrecognized input, please look at "help topoplot", "which topoplot" and "path". The input looks as if you expect the EEGLAB version of the topoplot function. Your path settings may be incorrect and the FieldTrip and EEGLAB version of the "topoplot" function may be confused.')
  143. end
  144. % deal with the different types of input syntax that this function can get
  145. if mod(nargin,2) && isnumeric(varargin{1}) && ischar(varargin{2})
  146. % topoplot(data, key, val, ...)
  147. cfg = keyval2cfg(varargin(2:end));
  148. data = varargin{1};
  149. OldStyleSyntax=0;
  150. elseif nargin==2
  151. % topoplot(cfg,data)
  152. OldStyleSyntax=0;
  153. cfg = varargin{1};
  154. data = varargin{2};
  155. err = 0;
  156. if ~isempty(cfg),
  157. err = err + double(~isstruct(cfg) && ~strcmp(class(cfg), 'config'));
  158. end
  159. err = err + ~isnumeric(data);
  160. if err
  161. errmsg=['\n'];
  162. errmsg=[errmsg,'When two input arguments are supplied, the following syntax should be used:\n'];
  163. errmsg=[errmsg,'topoplot(cfg,datavector);\n'];
  164. error(sprintf(errmsg));
  165. end;
  166. elseif nargin==4
  167. % topoplot(cfg,X,Y,data)
  168. OldStyleSyntax=1;
  169. cfg = varargin{1};
  170. chanX = varargin{2};
  171. chanY = varargin{3};
  172. data = varargin{4};
  173. err = 0;
  174. if ~isempty(cfg),
  175. err = err + double(~isstruct(cfg) && ~strcmp(class(cfg), 'config'));
  176. end
  177. err = err + ~isnumeric(data);
  178. err = err + ~isnumeric(chanX);
  179. err = err + ~isnumeric(chanY);
  180. if err
  181. errmsg=['\n'];
  182. errmsg=[errmsg,'When four input arguments are supplied, the following syntax should be used:\n'];
  183. errmsg=[errmsg,'topoplot(cfg,X,Y,datavector);\n'];
  184. error(sprintf(errmsg));
  185. end;
  186. elseif nargin==5
  187. % topoplot(cfg,X,Y,data,labels)
  188. OldStyleSyntax=1;
  189. cfg = varargin{1};
  190. chanX = varargin{2};
  191. chanY = varargin{3};
  192. data = varargin{4};
  193. chanLabels = varargin{5};
  194. err = 0;
  195. if ~isempty(cfg),
  196. err = err + double(~isstruct(cfg) && ~strcmp(class(cfg), 'config'));
  197. end
  198. err = err + ~isnumeric(data);
  199. err = err + ~isnumeric(chanX);
  200. err = err + ~isnumeric(chanY);
  201. err = err + ~iscell(chanLabels);
  202. err = err + numel(chanLabels)~=numel(chanX);
  203. err = err + numel(chanLabels)~=numel(chanY);
  204. if err
  205. errmsg=['\n'];
  206. errmsg=[errmsg,'When five input arguments are supplied, the following syntax should be used:\n'];
  207. errmsg=[errmsg,'topoplot(cfg,X,Y,datavector,Labels);\n'];
  208. error(sprintf(errmsg));
  209. end;
  210. else
  211. error('unrecognized input, please look at the help of this function')
  212. end
  213. % set the defaults
  214. if ~isfield(cfg, 'maxchans') cfg.maxchans = 256; end;
  215. if ~isfield(cfg, 'maplimits') cfg.maplimits = 'maxabs'; end; % maxabs, maxmin, [values]
  216. if ~isfield(cfg, 'interplimits') cfg.interplimits ='head'; end; % head, electrodes
  217. if ~isfield(cfg, 'gridscale') cfg.gridscale = 67; end; % 67 in original
  218. if ~isfield(cfg, 'contournum') cfg.contournum = 6; end;
  219. if ~isfield(cfg, 'colorbar') cfg.colorbar = 'no'; end;
  220. if ~isfield(cfg, 'style') cfg.style = 'both'; end; % both,straight,fill,contour,blank
  221. if ~isfield(cfg, 'headcolor') cfg.headcolor = [0 0 0]; end;
  222. if ~isfield(cfg, 'contcolor') cfg.contcolor = 'k'; end;
  223. if ~isfield(cfg, 'hlinewidth') cfg.hlinewidth = 2; end;
  224. if ~isfield(cfg, 'shading') cfg.shading = 'flat'; end; % flat or interp
  225. if ~isfield(cfg, 'interpolation') cfg.interpolation = 'v4'; end;
  226. if ~isfield(cfg, 'fontsize'), cfg.fontsize = 8; end;
  227. if ~isfield(cfg, 'commentpos'), cfg.commentpos = 'leftbottom'; end;
  228. if ~isfield(cfg, 'mask'), cfg.mask = []; end;
  229. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  230. % try to update the existing figure, this is to speed up realtime plotting
  231. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  232. if isfield(cfg, 'update') && strcmp(cfg.update, 'yes')
  233. update = guidata(gcf);
  234. if ~isempty(update)
  235. Xi = update.Xi;
  236. Yi = update.Yi;
  237. x = update.x;
  238. y = update.y;
  239. xi = update.xi;
  240. yi = update.yi;
  241. % Interpolate the topographic data
  242. Zi = griddata(x', y, data, xi', yi, cfg.interpolation);
  243. % keep the same NaNs
  244. Zi(isnan(update.Zi)) = NaN;
  245. deltax = xi(2)-xi(1); % length of grid entry
  246. deltay = yi(2)-yi(1); % length of grid entry
  247. surface(Xi-deltax/2,Yi-deltay/2,zeros(size(Zi)),Zi,'EdgeColor','none','FaceColor',cfg.shading);
  248. return
  249. end
  250. end
  251. if ~isfield(cfg,'layout')
  252. if ~OldStyleSyntax
  253. error('Specify at least the field or key "layout".');
  254. end;
  255. end;
  256. if ~ischar(cfg.contcolor) cfg.contcolor = 'k'; warning('cfg.contcolor must be string, put to ''k'''); end;
  257. if ~isfield(cfg,'electrodes') cfg.electrodes = 'on'; end; % on,off,label,numbers or highlights
  258. if ~isfield(cfg,'showlabels') % for compatibility with OLDSTYLE
  259. cfg.showlabels = '';
  260. else
  261. cfg.electrodes = '';
  262. end;
  263. if ~isfield(cfg,'emarker') cfg.emarker = 'o'; end;
  264. if ~isfield(cfg,'ecolor') cfg.ecolor = [0 0 0]; end;
  265. if ~isfield(cfg,'emarkersize') cfg.emarkersize = 2; end;
  266. if ~isfield(cfg,'efontsize') cfg.efontsize = get(0,'DefaultAxesFontSize');end;
  267. if ~isfield(cfg,'highlight') cfg.highlight = 'off'; end; % 'off' or the electrodenumbers.
  268. if ~isfield(cfg,'hlmarker') cfg.hlmarker = 'o'; end;
  269. if ~isfield(cfg,'hlcolor') cfg.hlcolor = [0 0 0]; end;
  270. if ~isfield(cfg,'hlmarkersize') cfg.hlmarkersize = 6; end;
  271. if ~isfield(cfg,'hllinewidth') cfg.hllinewidth = 3; end;
  272. if ~isfield(cfg,'hlfacecolor') cfg.hlfacecolor = cfg.hlcolor; end;
  273. if isfield(cfg,'colormap')
  274. if size(cfg.colormap,2)~=3, error('topoplot(): Colormap must be a n x 3 matrix'); end
  275. colormap(cfg.colormap);
  276. end;
  277. % check if the input cfg is valid for this function
  278. cfg = checkconfig(cfg, 'renamedval', {'maplimits', 'absmax', 'maxabs'});
  279. cfg = checkconfig(cfg, 'renamed', {'grid_scale', 'gridscale'});
  280. cfg = checkconfig(cfg, 'renamed', {'interpolate', 'interpolation'});
  281. cfg = checkconfig(cfg, 'renamed', {'numcontour', 'contournum'});
  282. cfg = checkconfig(cfg, 'renamed', {'electrod', 'electrodes'});
  283. cfg = checkconfig(cfg, 'renamed', {'hcolor', 'headcolor'});
  284. cfg = checkconfig(cfg, 'renamed', {'electcolor', 'ecolor'});
  285. cfg = checkconfig(cfg, 'renamed', {'emsize', 'emarkersize'});
  286. cfg = checkconfig(cfg, 'renamed', {'efsize', 'efontsize'});
  287. cfg = checkconfig(cfg, 'renamed', {'headlimits', 'interplimits'});
  288. if isfield(cfg,'interplimits')
  289. if ~ischar(cfg.interplimits), error('topoplot(): interplimits value must be a string'); end
  290. cfg.interplimits = lower(cfg.interplimits);
  291. if ~strcmp(cfg.interplimits,'electrodes') && ~strcmp(cfg.interplimits,'head') && ~strcmp(cfg.interplimits,'headleft'),
  292. error('topoplot(): Incorrect value for interplimits');
  293. end
  294. end;
  295. if isfield(cfg,'shading')
  296. cfg.shading = lower(cfg.shading);
  297. if ~any(strcmp(cfg.shading,{'flat','interp'})), error('Invalid Shading Parameter'); end
  298. end
  299. % for compatibility with topoplotXXX functions
  300. if isfield(cfg,'zlim')
  301. cfg.maplimits = cfg.zlim;
  302. cfg = rmfield(cfg,'zlim');
  303. end;
  304. [numChan,numTime] = size(data);
  305. if numChan && numTime>1
  306. error('topoplot(): data should be a column vector\n');
  307. end
  308. if ~OldStyleSyntax
  309. % create layout including channel positions, labels and anatomical mask and outline
  310. cfg.layout = prepare_layout(cfg);
  311. chanX = cfg.layout.pos(:,1);
  312. chanY = cfg.layout.pos(:,2);
  313. chanLabels = cfg.layout.label(:);
  314. else
  315. % create layout including channel positions, labels and anatomical mask and outline
  316. cfg.layout.pos = [chanX chanY];
  317. cfg.layout.label = chanLabels;
  318. cfg.layout = prepare_layout(cfg);
  319. end
  320. clear chanX chanY
  321. % The whole figure will be created with the x-axis along the horizontal
  322. % dimension of the figure and the y-axis along the vertical dimension. This
  323. % means that for data coming from a system with a head-coordinate system in
  324. % which the x-axis points to the nose (e.g. CTF), the layout should be 90
  325. % degrees rotated relative to the head coordinates.
  326. x = cfg.layout.pos(:,1);
  327. y = cfg.layout.pos(:,2);
  328. if isfield(cfg, 'outline')
  329. error('the option cfg.outline is not supported any more, please contact Robert for a detailled explanation');
  330. end
  331. if exist('chanLabels', 'var'),
  332. ind_SCALE = strmatch('SCALE', chanLabels);
  333. if length(ind_SCALE)==1
  334. % remember the position of the scale
  335. X_SCALE = cfg.layout.pos(ind_SCALE, 1);
  336. Y_SCALE = cfg.layout.pos(ind_SCALE, 2);
  337. x(ind_SCALE) = [];
  338. y(ind_SCALE) = [];
  339. chanLabels(ind_SCALE) = [];
  340. end
  341. ind_COMNT = strmatch('COMNT', chanLabels);
  342. if length(ind_COMNT)==1
  343. % remember the position of the comment
  344. X_COMNT = cfg.layout.pos(ind_COMNT, 1);
  345. Y_COMNT = cfg.layout.pos(ind_COMNT, 1);
  346. x(ind_COMNT) = [];
  347. y(ind_COMNT) = [];
  348. chanLabels(ind_COMNT) = [];
  349. end
  350. end
  351. % Set coordinates for comment
  352. if strcmp(cfg.commentpos,'lefttop')
  353. x_COMNT = -0.7;
  354. y_COMNT = 0.6;
  355. HorAlign = 'left';
  356. VerAlign = 'top';
  357. elseif strcmp(cfg.commentpos,'leftbottom')
  358. x_COMNT = -0.6;
  359. y_COMNT = -0.6;
  360. HorAlign = 'left';
  361. VerAlign = 'bottom';
  362. elseif strcmp(cfg.commentpos,'middletop')
  363. x_COMNT = 0;
  364. y_COMNT = 0.75;
  365. HorAlign = 'center';
  366. VerAlign = 'top';
  367. elseif strcmp(cfg.commentpos,'middlebottom')
  368. x_COMNT = 0;
  369. y_COMNT = -0.7;
  370. HorAlign = 'center';
  371. VerAlign = 'bottom';
  372. elseif strcmp(cfg.commentpos,'righttop')
  373. x_COMNT = 0.65;
  374. y_COMNT = 0.6;
  375. HorAlign = 'right';
  376. VerAlign = 'top';
  377. elseif strcmp(cfg.commentpos,'rightbottom')
  378. x_COMNT = 0.6;
  379. y_COMNT = -0.6;
  380. HorAlign = 'right';
  381. VerAlign = 'bottom';
  382. elseif isnumeric(cfg.commentpos)
  383. x_COMNT = cfg.commentpos(1);
  384. y_COMNT = cfg.commentpos(2);
  385. HorAlign = 'left';
  386. VerAlign = 'middle';
  387. x_COMNT = 0.9*((x_COMNT-min(x))/(max(x)-min(x))-0.5);
  388. y_COMNT = 0.9*((y_COMNT-min(y))/(max(y)-min(y))-0.5);
  389. end
  390. gca;
  391. cla;
  392. hold on
  393. if ~strcmp(cfg.style,'blank')
  394. % find limits for interpolation:
  395. if strcmp(cfg.interplimits,'head')
  396. xmin = +inf;
  397. xmax = -inf;
  398. ymin = +inf;
  399. ymax = -inf;
  400. for i=1:length(cfg.layout.mask)
  401. xmin = min([xmin; cfg.layout.mask{i}(:,1)]);
  402. xmax = max([xmax; cfg.layout.mask{i}(:,1)]);
  403. ymin = min([ymin; cfg.layout.mask{i}(:,2)]);
  404. ymax = max([ymax; cfg.layout.mask{i}(:,2)]);
  405. end
  406. elseif strcmp(cfg.interplimits,'electrodes')
  407. xmin = min(cfg.layout.pos(:,1));
  408. xmax = max(cfg.layout.pos(:,1));
  409. ymin = min(cfg.layout.pos(:,2));
  410. ymax = max(cfg.layout.pos(:,2));
  411. elseif strcmp(cfg.interplimits,'headleft')
  412. xmin = +inf;
  413. xmax = -inf;
  414. ymin = +inf;
  415. ymax = -inf;
  416. for i=1:length(cfg.layout.mask)
  417. xmin = min([xmin; cfg.layout.mask{i}(:,1)]);
  418. xmax = 0.02;
  419. ymin = min([ymin; cfg.layout.mask{i}(:,2)]);
  420. ymax = max([ymax; cfg.layout.mask{i}(:,2)]);
  421. end
  422. else
  423. xmin = min(cfg.layout.pos(:,1));
  424. xmax = max(cfg.layout.pos(:,1));
  425. ymin = min(cfg.layout.pos(:,2));
  426. ymax = max(cfg.layout.pos(:,2));
  427. end
  428. xi = linspace(xmin,xmax,cfg.gridscale); % x-axis for interpolation (row vector)
  429. yi = linspace(ymin,ymax,cfg.gridscale); % y-axis for interpolation (row vector)
  430. [Xi,Yi,Zi] = griddata(x', y, data, xi', yi, cfg.interpolation); % Interpolate the topographic data
  431. % calculate colormap limits
  432. m = size(colormap,1);
  433. if ischar(cfg.maplimits)
  434. if strcmp(cfg.maplimits,'maxabs')
  435. amin = -max(max(abs(Zi)));
  436. amax = max(max(abs(Zi)));
  437. elseif strcmp(cfg.maplimits,'maxmin')
  438. amin = min(min(Zi));
  439. amax = max(max(Zi));
  440. end
  441. else
  442. amin = cfg.maplimits(1);
  443. amax = cfg.maplimits(2);
  444. end
  445. % FIXME, according to Ingrid and Robert (19 Oct 2009), these deltas probably should be 0
  446. deltax = xi(2)-xi(1); % length of grid entry
  447. deltay = yi(2)-yi(1); % length of grid entry
  448. if isfield(cfg.layout, 'mask') && ~isempty(cfg.layout.mask)
  449. % apply anatomical mask to the data, i.e. that determines that the interpolated data outside the circle is not displayed
  450. maskA = false(size(Zi));
  451. for i=1:length(cfg.layout.mask)
  452. cfg.layout.mask{i}(end+1,:) = cfg.layout.mask{i}(1,:); % force them to be closed
  453. maskA(inside_contour([Xi(:) Yi(:)], cfg.layout.mask{i})) = true;
  454. end
  455. Zi(~maskA) = NaN;
  456. end
  457. if ~isempty(cfg.mask),
  458. % this mask is based on some statistical feature of the data itself, e.g. significance and is not related to the anatomical mask
  459. [maskX,maskY,maskZ] = griddata(x', y, double(cfg.mask), xi', yi, cfg.interpolation);
  460. % mask should be scaled between 0 and 1, clip the values that ly outside that range
  461. maskZ(isnan(maskZ)) = 0;
  462. maskZ(isinf(maskZ)) = 0;
  463. maskZ(maskZ<0) = 0;
  464. maskZ(maskZ>1) = 1;
  465. end
  466. % Draw topoplot on head
  467. if strcmp(cfg.style,'contour')
  468. contour(Xi,Yi,Zi,cfg.contournum,cfg.contcolor);
  469. elseif strcmp(cfg.style,'both')
  470. % first draw the surface, then the contour, to ensure that after exporting the contour lines are "on top"
  471. h = surface(Xi-deltax/2,Yi-deltay/2,zeros(size(Zi)),Zi,'EdgeColor','none', 'FaceColor',cfg.shading);
  472. if exist('maskZ','var'),
  473. set(h, 'AlphaData', maskZ);
  474. alim([0 1]);
  475. set(h, 'FaceAlpha', 'interp');
  476. end
  477. contour(Xi,Yi,Zi,cfg.contournum,cfg.contcolor);
  478. elseif strcmp(cfg.style,'straight')
  479. h = surface(Xi-deltax/2,Yi-deltay/2,zeros(size(Zi)),Zi,'EdgeColor','none', 'FaceColor',cfg.shading);
  480. if exist('maskZ','var'),
  481. set(h, 'AlphaData', maskZ);
  482. alim([0 1]);
  483. set(h, 'FaceAlpha', 'interp');
  484. end
  485. elseif strcmp(cfg.style,'fill')
  486. contourf(Xi,Yi,Zi,cfg.contournum,cfg.contcolor);
  487. else
  488. error('Invalid style')
  489. end
  490. caxis([amin amax]); % set coloraxis
  491. end
  492. % Plot electrodes:
  493. if strcmp(cfg.electrodes,'on') || strcmp(cfg.showlabels,'markers')
  494. if ischar(cfg.highlight)
  495. plot_vector(x,y,'style',cfg.emarker,'Color',cfg.ecolor,'markersize',cfg.emarkersize);
  496. elseif isnumeric(cfg.highlight)
  497. normal = setdiff(1:length(x), cfg.highlight);
  498. plot_vector(x(normal), y(normal), 'style', cfg.emarker, 'Color', cfg.ecolor, 'markersize', cfg.emarkersize);
  499. plot_vector(x(cfg.highlight), y(cfg.highlight), 'style', cfg.hlmarker, 'Color', cfg.hlcolor, 'markersize', cfg.hlmarkersize, ...
  500. 'linewidth', cfg.hllinewidth, 'markerfacecolor', cfg.hlfacecolor);
  501. elseif iscell(cfg.highlight)
  502. plot_vector(x,y,'style',cfg.emarker,'Color',cfg.ecolor,'markersize',cfg.emarkersize);
  503. for iCell = 1:length(cfg.highlight)
  504. plot_vector(x(cfg.highlight{iCell}), y(cfg.highlight{iCell}), 'style', cfg.hlmarker{iCell}, 'Color', ...
  505. cfg.hlcolor{iCell}, 'markersize', cfg.hlmarkersize{iCell}, ...
  506. 'linewidth', cfg.hllinewidth{iCell}, 'markerfacecolor', cfg.hlfacecolor{iCell});
  507. end
  508. else
  509. error('Unknown highlight type');
  510. end;
  511. elseif any(strcmp(cfg.electrodes,{'highlights','highlight'}))
  512. if isnumeric(cfg.highlight)
  513. plot_vector(x(cfg.highlight),y(cfg.highlight),'style',cfg.hlmarker,'Color',cfg.hlcolor,'markersize',cfg.hlmarkersize, 'linewidth',cfg.hllinewidth, 'markerfacecolor', cfg.hlfacecolor);
  514. else
  515. error('Unknown highlight type');
  516. end;
  517. elseif strcmp(cfg.electrodes,'labels') || strcmp(cfg.showlabels,'yes')
  518. for i = 1:numChan
  519. plot_text(x(i), y(i), chanLabels{i}, 'HorizontalAlignment', 'center', 'VerticalAlignment', 'middle', 'Color', cfg.ecolor, 'FontSize', cfg.efontsize);
  520. end
  521. elseif strcmp(cfg.electrodes,'numbers') || strcmp(cfg.showlabels,'numbers')
  522. for i = 1:numChan
  523. plot_text(x(i), y(i), int2str(i), 'HorizontalAlignment', 'center', 'VerticalAlignment', 'middle', 'Color', cfg.ecolor, 'FontSize',cfg.efontsize);
  524. end
  525. elseif strcmp(cfg.electrodes,'dotnum')
  526. for i = 1:numChan
  527. plot_text(x(i), y(i), int2str(i), 'HorizontalAlignment', 'left', 'VerticalAlignment', 'bottom', 'Color', cfg.ecolor, 'FontSize', cfg.efontsize);
  528. end
  529. if ischar(cfg.highlight)
  530. plot_vector(x, y, 'style', cfg.emarker, 'Color', cfg.ecolor, 'markersize', cfg.emarkersize);
  531. elseif isnumeric(cfg.highlight)
  532. normal = setdiff(1:length(x), cfg.highlight);
  533. plot_vector(x(normal), y(normal), 'style', cfg.emarker, 'Color', cfg.ecolor, 'markersize', cfg.emarkersize);
  534. plot_vector(x(cfg.highlight), y(cfg.highlight), 'style', cfg.hlmarker, 'Color', cfg.hlcolor, 'markersize', cfg.hlmarkersize, 'linewidth', cfg.hllinewidth, 'markerfacecolor', cfg.hlfacecolor);
  535. else
  536. error('Unknown highlight type');
  537. end;
  538. end
  539. if isfield(cfg.layout, 'outline')
  540. % plot the outline of the head, ears and nose
  541. for i=1:length(cfg.layout.outline)
  542. plot_vector(cfg.layout.outline{i}(:,1), cfg.layout.outline{i}(:,2), 'Color', cfg.headcolor, 'LineWidth', cfg.hlinewidth)
  543. end
  544. end
  545. % Write comment:
  546. if isfield(cfg, 'comment')
  547. if strcmp(cfg.commentpos, 'title')
  548. title(cfg.comment, 'Fontsize', cfg.fontsize);
  549. else
  550. plot_text(x_COMNT, y_COMNT, cfg.comment, 'Fontsize', cfg.fontsize, 'HorizontalAlignment', HorAlign, 'VerticalAlignment', VerAlign);
  551. end
  552. end
  553. % plot colorbar:
  554. if isfield(cfg, 'colorbar') && ~all(data == data(1))
  555. if strcmp(cfg.colorbar, 'yes')
  556. colorbar;
  557. elseif ~strcmp(cfg.colorbar, 'no')
  558. colorbar('location',cfg.colorbar);
  559. end
  560. end
  561. hold off
  562. axis off
  563. axis tight
  564. axis equal
  565. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  566. % this allows to update the existing figure, this is to speed up realtime
  567. % plotting
  568. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  569. if isfield(cfg, 'update') && strcmp(cfg.update, 'yes')
  570. update.Xi = Xi;
  571. update.Yi = Yi;
  572. update.Zi = Zi;
  573. update.xi = xi;
  574. update.yi = yi;
  575. update.x = x;
  576. update.y = y;
  577. guidata(gcf, update);
  578. end