b_scenecat_n1_bl.m 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413
  1. currentFile = mfilename('fullpath');
  2. [pathstr,~,~] = fileparts(currentFile);
  3. cd(fullfile(pathstr,'..'))
  4. rootpath = pwd;
  5. pn.data_eeg = fullfile(rootpath, '..', 'eegmp_preproc', 'data', 'outputs', 'eeg');
  6. pn.data_erp = fullfile(rootpath, 'data', 'erp');
  7. pn.data_erf = fullfile(rootpath, 'data', 'erf');
  8. pn.tools = fullfile(rootpath, 'tools');
  9. addpath(fullfile(rootpath, '..', 'eegmp_preproc', 'tools', 'fieldtrip')); ft_defaults
  10. addpath(fullfile(pn.tools, 'BrewerMap'));
  11. addpath(fullfile(pn.tools, 'shadedErrorBar'));
  12. %% load event info
  13. load(fullfile(pn.data_eeg, ['sub-001_task-xxxx_eeg_art.mat']), 'events');
  14. parameter = {'scene_category'; 'old'; 'behavior'; 'subsequent_memory'};
  15. for ind_param = 1:numel(parameter)
  16. conds.(parameter{ind_param}) = unique(events.(parameter{ind_param}));
  17. end
  18. %% load erp_bl
  19. for ind_id = 1:33
  20. id = sprintf('sub-%03d', ind_id);
  21. load(fullfile(pn.data_erp, [id,'_erp_bl.mat']));
  22. for ind_option = 1:numel(conds.scene_category)
  23. if ind_id == 1
  24. erpgroup.scene_category.(conds.scene_category{ind_option}) = erp_bl.scene_category{ind_option};
  25. erpgroup.scene_category.(conds.scene_category{ind_option}) = ...
  26. rmfield(erpgroup.scene_category.(conds.scene_category{ind_option}), {'avg', 'var', 'dof'});
  27. erpgroup.scene_category.(conds.scene_category{ind_option}).dimord = 'sub_chan_time';
  28. end
  29. erpgroup.scene_category.(conds.scene_category{ind_option}).avg(ind_id,:,:) = erp_bl.scene_category{ind_option}.avg;
  30. end
  31. end
  32. time = erpgroup.scene_category.manmade.time;
  33. elec = erpgroup.scene_category.manmade.elec;
  34. channels = erpgroup.scene_category.manmade.label;
  35. %idx_chans = find(ismember(channels, {'O1', 'Oz', 'O2'}));
  36. %idx_chans = find(ismember(channels, {'PO7', 'PO8'}));
  37. %idx_chans = find(ismember(channels, {'Pz', 'CPz', 'P1'}));
  38. mergeddata = cat(4, erpgroup.scene_category.manmade.avg, ...
  39. erpgroup.scene_category.natural.avg);
  40. %% plot topography of visual N1
  41. % set custom colormap
  42. cBrew = brewermap(500,'RdBu');
  43. cBrew = flipud(cBrew);
  44. colormap(cBrew)
  45. h = figure('units','centimeters','position',[0 0 10 10]);
  46. set(gcf,'renderer','Painters')
  47. cfg = [];
  48. cfg.layout = 'EEG1010.lay';
  49. cfg.parameter = 'powspctrm';
  50. cfg.comment = 'no';
  51. cfg.colormap = cBrew;
  52. cfg.colorbar = 'EastOutside';
  53. plotData = [];
  54. plotData.label = elec.label(1:64); % {1 x N}
  55. plotData.dimord = 'chan';
  56. plotData.powspctrm = squeeze(nanmean(nanmean(nanmin(mergeddata(:,:,time>0.05 & time <0.07,1:2),[],3),1),4))';
  57. [~, sortidx] = sort(plotData.powspctrm, 'ascend');
  58. idx_chans = sortidx(1);
  59. idx_chans_visual = idx_chans;
  60. cfg.marker = 'off';
  61. cfg.highlight = 'yes';
  62. cfg.highlightchannel = plotData.label(idx_chans);
  63. cfg.highlightcolor = [1 0 0];
  64. cfg.highlightsymbol = '.';
  65. cfg.highlightsize = 18;
  66. cfg.zlim = [-2 2];%[-8 8]*10^-4;
  67. cfg.figure = h;
  68. ft_topoplotER(cfg,plotData);
  69. cb = colorbar('location', 'EastOutside'); set(get(cb,'ylabel'),'string','Amplitude');
  70. %% visualize N1 over negative maximum
  71. % avg across channels and conditions
  72. condAvg = squeeze(nanmean(nanmean(mergeddata(:,idx_chans,:,1:2),2),4));
  73. h = figure('units','centimeters','position',[0 0 10 8]);
  74. cla; hold on;
  75. % new value = old value ? subject average + grand average
  76. curData = squeeze(nanmean(mergeddata(:,idx_chans,:,1),2));
  77. curData = curData-condAvg+repmat(nanmean(condAvg,1),size(condAvg,1),1);
  78. standError = nanstd(curData,1)./sqrt(size(curData,1));
  79. l1 = shadedErrorBar(time,nanmean(curData,1),standError, 'lineprops', {'color', 'k','linewidth', 2}, 'patchSaturation', .1);
  80. curData = squeeze(nanmean(mergeddata(:,idx_chans,:,2),2));
  81. curData = curData-condAvg+repmat(nanmean(condAvg,1),size(condAvg,1),1);
  82. standError = nanstd(curData,1)./sqrt(size(curData,1));
  83. l2 = shadedErrorBar(time,nanmean(curData,1),standError, 'lineprops', {'color', 'r','linewidth', 2}, 'patchSaturation', .1);
  84. % ax = gca; ax.YDir = 'reverse';
  85. xlabel('Time (s) from stim onset')
  86. xlim([-.05 .3]); %ylim([-.03 .18])
  87. ylabel({'ERP';'(microVolts)'});
  88. xlabel({'Time (s)'});
  89. set(findall(gcf,'-property','FontSize'),'FontSize',12)
  90. %% ERP components for subjects 1-17 and 18-33 are shifted in time!
  91. h = figure('units','centimeters','position',[0 0 10 8]);
  92. cla; hold on;
  93. % new value = old value ? subject average + grand average
  94. curData = squeeze(nanmean(mergeddata(1:17,idx_chans,:,1),2));
  95. standError = nanstd(curData,1)./sqrt(size(curData,1));
  96. l1 = shadedErrorBar(time,nanmean(curData,1),standError, 'lineprops', {'color', 'k','linewidth', 2}, 'patchSaturation', .1);
  97. curData = squeeze(nanmean(mergeddata(18:end,idx_chans,:,1),2));
  98. standError = nanstd(curData,1)./sqrt(size(curData,1));
  99. l2 = shadedErrorBar(time,nanmean(curData,1),standError, 'lineprops', {'color', 'r','linewidth', 2}, 'patchSaturation', .1);
  100. % ax = gca; ax.YDir = 'reverse';
  101. xlabel('Time (s) from stim onset')
  102. xlim([-.025 .16]); %ylim([-.03 .18])
  103. ylabel({'ERP';'(microVolts)'});
  104. xlabel({'Time (s)'});
  105. set(findall(gcf,'-property','FontSize'),'FontSize',12)
  106. %% align individual subjects N1 to first negative peak
  107. % find individual minimum (condition-specific) between 40 and 150 ms
  108. time2search = find(time>0.04 & time <0.12);
  109. newtime = 0-100*(time(2)-time(1)):(time(2)-time(1)):0+100*(time(2)-time(1));
  110. % for indID = 1:size(condAvg,1)
  111. % %[peaks, locs] = findpeaks(condAvg1(indID,:));
  112. % tmp = find(islocalmin(condAvg(indID,time2search), ...
  113. % 'FlatSelection', 'center', ...
  114. % 'MinSeparation', 15));
  115. % minVal1(indID) = condAvg1(indID,time2search(tmp(1)));
  116. % minLoc1(indID) = tmp(1);
  117. % curmin = time2search(tmp(1));
  118. % alignedN1_1(indID,:) = condAvg1(indID,curmin-100:curmin+100);
  119. %
  120. % tmp = find(islocalmin(condAvg(indID,time2search), ...
  121. % 'FlatSelection', 'center', ...
  122. % 'MinSeparation', 15));
  123. % minVal2(indID) = condAvg2(indID,time2search(tmp(1)));
  124. % minLoc2(indID) = tmp(1);
  125. % curmin = time2search(tmp(1));
  126. % alignedN1_2(indID,:) = condAvg2(indID,curmin-100:curmin+100);
  127. % end
  128. % alternatively: consider global minimum
  129. for indID = 1:size(condAvg,1)
  130. [~, minLoc1(indID)] = min(condAvg(indID,time2search));
  131. curmin = time2search(minLoc1(indID));
  132. minVal1(indID) = condAvg1(indID,curmin);
  133. alignedN1_1(indID,:) = condAvg1(indID,curmin-100:curmin+100);
  134. [~, minLoc2(indID)] = min(condAvg(indID,time2search));
  135. curmin = time2search(minLoc2(indID));
  136. minVal1(indID) = condAvg2(indID,curmin);
  137. alignedN1_2(indID,:) = condAvg2(indID,curmin-100:curmin+100);
  138. end
  139. mergeddata_aligned = cat(3, alignedN1_1, alignedN1_2);
  140. [h, p] = ttest(minVal1, minVal2)
  141. % avg across channels and conditions
  142. condAvg_al = squeeze(nanmean(mergeddata_aligned(:,:,1:2),3));
  143. % plot aligned signals
  144. figure; imagesc(zscore(condAvg_al,[],2))
  145. figure; imagesc(condAvg_al)
  146. h = figure('units','centimeters','position',[0 0 10 8]);
  147. cla; hold on;
  148. % new value = old value ? subject average + grand average
  149. curData = squeeze(mergeddata_aligned(:,:,1));
  150. curData = curData-condAvg_al+repmat(nanmean(condAvg_al,1),size(condAvg_al,1),1);
  151. standError = nanstd(curData,1)./sqrt(size(curData,1));
  152. l1 = shadedErrorBar(newtime*1000,nanmean(curData,1),standError, 'lineprops', {'color', 'k','linewidth', 2}, 'patchSaturation', .1);
  153. curData = squeeze(mergeddata_aligned(:,:,2));
  154. curData = curData-condAvg_al+repmat(nanmean(condAvg_al,1),size(condAvg_al,1),1);
  155. standError = nanstd(curData,1)./sqrt(size(curData,1));
  156. l2 = shadedErrorBar(newtime*1000,nanmean(curData,1),standError, 'lineprops', {'color', 'r','linewidth', 2}, 'patchSaturation', .1);
  157. % ax = gca; ax.YDir = 'reverse';
  158. xlabel('Time (s) from local minimum')
  159. xlim([-100 100]); %ylim([-.03 .18])
  160. ylabel({'ERP';'(microVolts)'});
  161. xlabel({'Time (ms) from local minimum'});
  162. set(findall(gcf,'-property','FontSize'),'FontSize',12)
  163. %% plot topography of frontal N1
  164. % set custom colormap
  165. cBrew = brewermap(500,'RdBu');
  166. cBrew = flipud(cBrew);
  167. colormap(cBrew)
  168. h = figure('units','centimeters','position',[0 0 10 10]);
  169. set(gcf,'renderer','Painters')
  170. cfg = [];
  171. cfg.layout = 'EEG1010.lay';
  172. cfg.parameter = 'powspctrm';
  173. cfg.comment = 'no';
  174. cfg.colormap = cBrew;
  175. cfg.colorbar = 'EastOutside';
  176. plotData = [];
  177. plotData.label = elec.label(1:64); % {1 x N}
  178. plotData.dimord = 'chan';
  179. plotData.powspctrm = squeeze(nanmean(nanmean(nanmin(mergeddata(:,:,time>0.08 & time <0.12,1:2),[],3),1),4))';
  180. %plotData.powspctrm = squeeze(nanmean(nanmean(nanmean(mergeddata(:,:,time>0.05 & time <0.1,1:2),3),1),4))';
  181. %plotData.powspctrm = squeeze(nanmean(nanmean(nanmean(mergeddata(:,:,time>0.1 & time <0.15,1:2),3),1),4))';
  182. [~, sortidx] = sort(plotData.powspctrm, 'ascend');
  183. idx_chans = sortidx(1:6);
  184. idx_chans_frontal = idx_chans;
  185. cfg.marker = 'off';
  186. cfg.highlight = 'yes';
  187. cfg.highlightchannel = plotData.label(idx_chans);
  188. cfg.highlightcolor = [1 0 0];
  189. cfg.highlightsymbol = '.';
  190. cfg.highlightsize = 18;
  191. cfg.zlim = [-6 6];%[-8 8]*10^-4;
  192. cfg.figure = h;
  193. ft_topoplotER(cfg,plotData);
  194. cb = colorbar('location', 'EastOutside'); set(get(cb,'ylabel'),'string','Amplitude');
  195. %% visualize N1 over negative maximum
  196. % avg across channels and conditions
  197. condAvg = squeeze(nanmean(nanmean(mergeddata(:,idx_chans,:,1:2),2),4));
  198. h = figure('units','centimeters','position',[0 0 10 8]);
  199. cla; hold on;
  200. % new value = old value ? subject average + grand average
  201. curData = squeeze(nanmean(mergeddata(:,idx_chans,:,1),2));
  202. curData = curData-condAvg+repmat(nanmean(condAvg,1),size(condAvg,1),1);
  203. standError = nanstd(curData,1)./sqrt(size(curData,1));
  204. l1 = shadedErrorBar(time,nanmean(curData,1),standError, 'lineprops', {'color', 'k','linewidth', 2}, 'patchSaturation', .1);
  205. curData = squeeze(nanmean(mergeddata(:,idx_chans,:,2),2));
  206. curData = curData-condAvg+repmat(nanmean(condAvg,1),size(condAvg,1),1);
  207. standError = nanstd(curData,1)./sqrt(size(curData,1));
  208. l2 = shadedErrorBar(time,nanmean(curData,1),standError, 'lineprops', {'color', 'r','linewidth', 2}, 'patchSaturation', .1);
  209. % ax = gca; ax.YDir = 'reverse';
  210. xlabel('Time (s) from stim onset')
  211. xlim([-.05 .3]); %ylim([-.03 .18])
  212. ylabel({'ERP';'(microVolts)'});
  213. xlabel({'Time (s)'});
  214. set(findall(gcf,'-property','FontSize'),'FontSize',12)
  215. %% plot both trajectories into same plot
  216. h = figure('units','centimeters','position',[0 0 10 8]);
  217. cla; hold on;
  218. % new value = old value ? subject average + grand average
  219. curData = squeeze(nanmean(nanmean(mergeddata(:,idx_chans_visual,:,1:2),2),4));
  220. standError = nanstd(curData,1)./sqrt(size(curData,1));
  221. l1 = shadedErrorBar(time,nanmean(curData,1),standError, 'lineprops', {'color', 'k','linewidth', 2}, 'patchSaturation', .1);
  222. curData = squeeze(nanmean(nanmean(mergeddata(:,idx_chans_frontal,:,1:2),2),4));
  223. standError = nanstd(curData,1)./sqrt(size(curData,1));
  224. l2 = shadedErrorBar(time,nanmean(curData,1),standError, 'lineprops', {'color', 'r','linewidth', 2}, 'patchSaturation', .1);
  225. % ax = gca; ax.YDir = 'reverse';
  226. xlabel('Time (s) from stim onset')
  227. xlim([-.025 .15]); %ylim([-.03 .18])
  228. ylabel({'ERP';'(microVolts)'});
  229. xlabel({'Time (s)'});
  230. set(findall(gcf,'-property','FontSize'),'FontSize',12)
  231. %% plot difference between conditions
  232. h = figure('units','centimeters','position',[0 0 10 10]);
  233. set(gcf,'renderer','Painters')
  234. cfg = [];
  235. cfg.layout = 'biosemi64.lay';
  236. cfg.parameter = 'powspctrm';
  237. cfg.comment = 'no';
  238. cfg.colormap = cBrew;
  239. cfg.colorbar = 'EastOutside';
  240. plotData = [];
  241. plotData.label = elec.label(1:66); % {1 x N}
  242. plotData.dimord = 'chan';
  243. plotData.powspctrm = squeeze(nanmean(nanmean(nanmean(mergeddata(:,:,time>0.08 & time <0.12,2),3),1),4))'...
  244. -squeeze(nanmean(nanmean(nanmean(mergeddata(:,:,time>0.08 & time <0.12,1),3),1),4))';
  245. [~, sortidx] = sort(plotData.powspctrm, 'ascend');
  246. idx_chans = sortidx(1:6);
  247. cfg.marker = 'off';
  248. cfg.highlight = 'yes';
  249. cfg.highlightchannel = plotData.label(idx_chans);
  250. cfg.highlightcolor = [1 0 0];
  251. cfg.highlightsymbol = '.';
  252. cfg.highlightsize = 18;
  253. %cfg.zlim = [-5 5]*10^-4;
  254. cfg.figure = h;
  255. ft_topoplotER(cfg,plotData);
  256. cb = colorbar('location', 'EastOutside'); set(get(cb,'ylabel'),'string','Amplitude');
  257. %% visualize for negative pls channels
  258. %idx_chans = [28:30];
  259. condAvg = squeeze(nanmean(nanmean(mergeddata(:,idx_chans,:,1:2),2),4));
  260. h = figure('units','centimeters','position',[0 0 10 8]);
  261. cla; hold on;
  262. % new value = old value ? subject average + grand average
  263. curData = squeeze(nanmean(mergeddata(:,idx_chans,:,1),2));
  264. curData = curData-condAvg+repmat(nanmean(condAvg,1),size(condAvg,1),1);
  265. standError = nanstd(curData,1)./sqrt(size(curData,1));
  266. l1 = shadedErrorBar(time,nanmean(curData,1),standError, 'lineprops', {'color', 'k','linewidth', 2}, 'patchSaturation', .1);
  267. curData = squeeze(nanmean(mergeddata(:,idx_chans,:,2),2));
  268. curData = curData-condAvg+repmat(nanmean(condAvg,1),size(condAvg,1),1);
  269. standError = nanstd(curData,1)./sqrt(size(curData,1));
  270. l2 = shadedErrorBar(time,nanmean(curData,1),standError, 'lineprops', {'color', 'r','linewidth', 2}, 'patchSaturation', .1);
  271. xlabel('Time (s) from stim onset')
  272. xlim([-.2 1]); %ylim([-.03 .18])
  273. xlim([-.05 .3]);
  274. ylabel({'ERP';'(microVolts)'});
  275. xlabel({'Time (s)'});
  276. set(findall(gcf,'-property','FontSize'),'FontSize',12)
  277. %% visualize for positive pls channels
  278. idx_chans = [21:23, 58:62];
  279. condAvg = squeeze(nanmean(nanmean(mergeddata(:,idx_chans,:,1:2),2),4));
  280. h = figure('units','centimeters','position',[0 0 10 8]);
  281. cla; hold on;
  282. % new value = old value ? subject average + grand average
  283. curData = squeeze(nanmean(mergeddata(:,idx_chans,:,1),2));
  284. curData = curData-condAvg+repmat(nanmean(condAvg,1),size(condAvg,1),1);
  285. standError = nanstd(curData,1)./sqrt(size(curData,1));
  286. l1 = shadedErrorBar(time,nanmean(curData,1),standError, 'lineprops', {'color', 'k','linewidth', 2}, 'patchSaturation', .1);
  287. curData = squeeze(nanmean(mergeddata(:,idx_chans,:,2),2));
  288. curData = curData-condAvg+repmat(nanmean(condAvg,1),size(condAvg,1),1);
  289. standError = nanstd(curData,1)./sqrt(size(curData,1));
  290. l2 = shadedErrorBar(time,nanmean(curData,1),standError, 'lineprops', {'color', 'r','linewidth', 2}, 'patchSaturation', .1);
  291. xlabel('Time (s) from stim onset')
  292. xlim([-.5 1]); %ylim([-.03 .18])
  293. xlim([-.05 .3]);
  294. ylabel({'ERP';'(microVolts)'});
  295. xlabel({'Time (s)'});
  296. set(findall(gcf,'-property','FontSize'),'FontSize',12)
  297. %% visualize for frontal channels
  298. idx_chans = [37];%[4,38,39];
  299. condAvg = squeeze(nanmean(nanmean(mergeddata(:,idx_chans,:,1:2),2),4));
  300. h = figure('units','centimeters','position',[0 0 10 8]);
  301. cla; hold on;
  302. % new value = old value ? subject average + grand average
  303. curData = squeeze(nanmean(mergeddata(:,idx_chans,:,1),2));
  304. curData = curData-condAvg+repmat(nanmean(condAvg,1),size(condAvg,1),1);
  305. standError = nanstd(curData,1)./sqrt(size(curData,1));
  306. l1 = shadedErrorBar(time,nanmean(curData,1),standError, 'lineprops', {'color', 'k','linewidth', 2}, 'patchSaturation', .1);
  307. curData = squeeze(nanmean(mergeddata(:,idx_chans,:,2),2));
  308. curData = curData-condAvg+repmat(nanmean(condAvg,1),size(condAvg,1),1);
  309. standError = nanstd(curData,1)./sqrt(size(curData,1));
  310. l2 = shadedErrorBar(time,nanmean(curData,1),standError, 'lineprops', {'color', 'r','linewidth', 2}, 'patchSaturation', .1);
  311. xlabel('Time (s) from stim onset')
  312. xlim([-1 2]); %ylim([-.03 .18])
  313. ylabel({'ERP';'(microVolts)'});
  314. xlabel({'Time (s)'});
  315. set(findall(gcf,'-property','FontSize'),'FontSize',12)
  316. %% visualize for all channels
  317. idx_chans = [1:66];
  318. condAvg = squeeze(nanmean(nanmean(mergeddata(:,idx_chans,:,1:2),2),4));
  319. h = figure('units','centimeters','position',[0 0 10 8]);
  320. cla; hold on;
  321. % new value = old value ? subject average + grand average
  322. curData = squeeze(nanmean(mergeddata(:,idx_chans,:,1),2));
  323. curData = curData-condAvg+repmat(nanmean(condAvg,1),size(condAvg,1),1);
  324. standError = nanstd(curData,1)./sqrt(size(curData,1));
  325. l1 = shadedErrorBar(time,nanmean(curData,1),standError, 'lineprops', {'color', 'k','linewidth', 2}, 'patchSaturation', .1);
  326. curData = squeeze(nanmean(mergeddata(:,idx_chans,:,2),2));
  327. curData = curData-condAvg+repmat(nanmean(condAvg,1),size(condAvg,1),1);
  328. standError = nanstd(curData,1)./sqrt(size(curData,1));
  329. l2 = shadedErrorBar(time,nanmean(curData,1),standError, 'lineprops', {'color', 'r','linewidth', 2}, 'patchSaturation', .1);
  330. xlabel('Time (s) from stim onset')
  331. xlim([-.2 1]); %ylim([-.03 .18])
  332. xlim([-.05 .3]);
  333. ylabel({'ERP';'(microVolts)'});
  334. xlabel({'Time (s)'});
  335. set(findall(gcf,'-property','FontSize'),'FontSize',12)
  336. %% plot the ERPs
  337. manmade = erpgroup.scene_category.manmade;
  338. manmade.avg = squeeze(nanmean(manmade.avg,1));
  339. manmade.dimord = 'chan_time';
  340. natural = erpgroup.scene_category.natural;
  341. natural.avg = squeeze(nanmean(natural.avg,1));
  342. natural.dimord = 'chan_time';
  343. cfg = [];
  344. cfg.layout = 'biosemi64.lay';
  345. cfg.interactive = 'yes';
  346. cfg.showoutline = 'yes';
  347. cfg.xlim = [-.2 .3];
  348. ft_multiplotER(cfg, natural, manmade)