d1_taskPLS_recognition_erp_LV1.m 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. % Create an overview plot featuring the results of the multivariate PLS
  2. % comparing spectral changes during the stimulus period under load
  3. clear all; cla; clc;
  4. currentFile = mfilename('fullpath');
  5. [pathstr,~,~] = fileparts(currentFile);
  6. cd(fullfile(pathstr,'..'))
  7. rootpath = pwd;
  8. pn.data = fullfile(rootpath, 'data', 'stats');
  9. pn.figures = fullfile(rootpath, 'figures');
  10. pn.tools = fullfile(rootpath, 'tools');
  11. addpath(genpath(fullfile(pn.tools, '[MEG]PLS', 'MEGPLS_PIPELINE_v2.02b')))
  12. addpath(fullfile(pn.tools, 'fieldtrip')); ft_defaults;
  13. addpath(genpath(fullfile(pn.tools, 'RainCloudPlots')));
  14. addpath(fullfile(pn.tools, 'BrewerMap'));
  15. addpath(fullfile(pn.tools, 'winsor'));
  16. % set custom colormap
  17. cBrew = brewermap(500,'RdBu');
  18. cBrew = flipud(cBrew);
  19. colormap(cBrew)
  20. load(fullfile(pn.data, 'd1_taskpls_erp.mat'),...
  21. 'stat', 'result', 'lvdat', 'lv_evt_list', 'num_chans', 'num_freqs', 'num_time')
  22. load(fullfile(rootpath, 'data','erp', ['sub-001_erp.mat']));
  23. elec = erp.scene_category{1}.elec;
  24. result.perm_result.sprob
  25. indLV = 1;
  26. lvdat = reshape(result.boot_result.compare_u(:,indLV), num_chans, num_freqs, num_time);
  27. stat.prob = lvdat;
  28. stat.mask = lvdat > 3 | lvdat < -3;
  29. % maskNaN = double(stat.mask);
  30. % maskNaN(maskNaN==0) = NaN;
  31. %% invert solution
  32. stat.mask = stat.mask;
  33. stat.prob = stat.prob.*-1;
  34. result.vsc = result.vsc.*-1;
  35. result.usc = result.usc.*-1;
  36. %% plot temporal loadings
  37. h = figure('units','centimeter','position',[0 0 10 10]);
  38. set(gcf,'renderer','Painters')
  39. hold on;
  40. % highlight relevant phase in background
  41. patches.timeVec = [.35 .55];
  42. patches.colorVec = [.8 .95 1];
  43. for indP = 1:size(patches.timeVec,2)-1
  44. YLim = [-.5 .5];
  45. p = patch([patches.timeVec(indP) patches.timeVec(indP+1) patches.timeVec(indP+1) patches.timeVec(indP)], ...
  46. [YLim(1) YLim(1) YLim(2), YLim(2)], patches.colorVec(indP,:));
  47. p.EdgeColor = 'none';
  48. end
  49. % highlight relevant phase in background
  50. patches.timeVec = [.6 1];
  51. patches.colorVec = [1 .95 .8];
  52. for indP = 1:size(patches.timeVec,2)-1
  53. YLim = [-.5 .5];
  54. p = patch([patches.timeVec(indP) patches.timeVec(indP+1) patches.timeVec(indP+1) patches.timeVec(indP)], ...
  55. [YLim(1) YLim(1) YLim(2), YLim(2)], patches.colorVec(indP,:));
  56. p.EdgeColor = 'none';
  57. end
  58. % highlight relevant phase in background
  59. patches.timeVec = [1.2 1.7];
  60. patches.colorVec = [1 .8 .7];
  61. for indP = 1:size(patches.timeVec,2)-1
  62. YLim = [-.5 .5];
  63. p = patch([patches.timeVec(indP) patches.timeVec(indP+1) patches.timeVec(indP+1) patches.timeVec(indP)], ...
  64. [YLim(1) YLim(1) YLim(2), YLim(2)], patches.colorVec(indP,:));
  65. p.EdgeColor = 'none';
  66. end
  67. statsPlot = [];
  68. statsPlot = cat(1, statsPlot,squeeze(nanmean(stat.mask(1:64,:,:).*stat.prob(1:64,:,:),1)));
  69. plot(stat.time,statsPlot, 'k')
  70. xlabel('Time [s from stim onset]'); ylabel('mean BSR');
  71. title({'ERP changes'; ['p = ', num2str(round(result.perm_result.sprob(indLV),4))]})
  72. set(findall(gcf,'-property','FontSize'),'FontSize',18)
  73. figureName = ['d1_rec_erp_bsr'];
  74. saveas(h, fullfile(pn.figures, figureName), 'epsc');
  75. saveas(h, fullfile(pn.figures, figureName), 'png');
  76. %% plot early positivity/negativity
  77. h = figure('units','centimeters','position',[0 0 10 10]);
  78. set(gcf,'renderer','Painters')
  79. cfg = [];
  80. cfg.layout = 'biosemi64.lay';
  81. cfg.parameter = 'powspctrm';
  82. cfg.comment = 'no';
  83. cfg.colormap = cBrew;
  84. cfg.colorbar = 'EastOutside';
  85. plotData = [];
  86. plotData.label = elec.label; % {1 x N}
  87. plotData.dimord = 'chan';
  88. cfg.zlim = [-4 4];
  89. cfg.figure = h;
  90. plotData.powspctrm = squeeze(nanmean(stat.mask(:,:,stat.time>.35 & stat.time<.55).*...
  91. stat.prob(:,:,stat.time>.35 & stat.time<.55),3));
  92. [~, sortind] = sort(plotData.powspctrm, 'ascend');
  93. cfg.marker = 'off';
  94. cfg.highlight = 'yes';
  95. cfg.highlightchannel = plotData.label(sortind([1:2, end])); % 42, 35 (neg) 37 (pos)
  96. cfg.highlightcolor = [0 0 0];
  97. cfg.highlightsymbol = '.';
  98. cfg.highlightsize = 30;
  99. ft_topoplotER(cfg,plotData);
  100. cb = colorbar('location', 'EastOutside'); set(get(cb,'ylabel'),'string','Mean BSR');
  101. figureName = ['d1_rec_erp_topo1'];
  102. saveas(h, fullfile(pn.figures, figureName), 'epsc');
  103. saveas(h, fullfile(pn.figures, figureName), 'png');
  104. %% plot later positivity
  105. h = figure('units','centimeters','position',[0 0 10 10]);
  106. set(gcf,'renderer','Painters')
  107. cfg = [];
  108. cfg.layout = 'biosemi64.lay';
  109. cfg.parameter = 'powspctrm';
  110. cfg.comment = 'no';
  111. cfg.colormap = cBrew;
  112. cfg.colorbar = 'EastOutside';
  113. plotData = [];
  114. plotData.label = elec.label; % {1 x N}
  115. plotData.dimord = 'chan';
  116. cfg.zlim = [-4 4];
  117. cfg.figure = h;
  118. plotData.powspctrm = squeeze(nanmean(stat.mask(:,:,stat.time>.6 & stat.time<1).*...
  119. stat.prob(:,:,stat.time>0.6 & stat.time<1),3));
  120. [~, sortind] = sort(plotData.powspctrm, 'descend');
  121. cfg.marker = 'off';
  122. cfg.highlight = 'yes';
  123. cfg.highlightchannel = plotData.label(sortind([1:2])); % 19, 21
  124. cfg.highlightcolor = [0 0 0];
  125. cfg.highlightsymbol = '.';
  126. cfg.highlightsize = 30;
  127. ft_topoplotER(cfg,plotData);
  128. cb = colorbar('location', 'EastOutside'); set(get(cb,'ylabel'),'string','Mean BSR');
  129. figureName = ['d1_rec_erp_topo2'];
  130. saveas(h, fullfile(pn.figures, figureName), 'epsc');
  131. saveas(h, fullfile(pn.figures, figureName), 'png');
  132. %% plot late negativity
  133. h = figure('units','centimeters','position',[0 0 10 10]);
  134. set(gcf,'renderer','Painters')
  135. cfg = [];
  136. cfg.layout = 'biosemi64.lay';
  137. cfg.parameter = 'powspctrm';
  138. cfg.comment = 'no';
  139. cfg.colormap = cBrew;
  140. cfg.colorbar = 'EastOutside';
  141. plotData = [];
  142. plotData.label = elec.label; % {1 x N}
  143. plotData.dimord = 'chan';
  144. cfg.zlim = [-2.5 2.5];
  145. cfg.figure = h;
  146. plotData.powspctrm = squeeze(nanmean(stat.mask(:,:,stat.time>1.2 & stat.time<1.7).*...
  147. stat.prob(:,:,stat.time>1.2 & stat.time<1.7),3));
  148. [~, sortind] = sort(plotData.powspctrm, 'descend');
  149. cfg.marker = 'off';
  150. cfg.highlight = 'yes';
  151. %cfg.highlightchannel = plotData.label(sortind([end-3:end])); % 63, 26, 21, 58 (negative)
  152. %cfg.highlightchannel = plotData.label(sortind([8])); % 16, 53, 15, 54, 52, 51 (positive lateral)
  153. %cfg.highlightchannel = plotData.label([16, 53, 15, 52]); % (positive lateral)
  154. %cfg.highlightchannel = plotData.label([28]); % (positive posterior)
  155. cfg.highlightchannel = plotData.label([63, 26, 21, 58, 16, 53, 15, 52, 28]); % (positive posterior)
  156. cfg.highlightcolor = [.5 .5 .5];
  157. cfg.highlightsymbol = '.';
  158. cfg.highlightsize = 30;
  159. ft_topoplotER(cfg,plotData);
  160. cb = colorbar('location', 'EastOutside'); set(get(cb,'ylabel'),'string','Mean BSR');
  161. figureName = ['d1_rec_erp_topo3'];
  162. saveas(h, fullfile(pn.figures, figureName), 'epsc');
  163. saveas(h, fullfile(pn.figures, figureName), 'png');
  164. %% plot using raincloud plot
  165. groupsizes=result.num_subj_lst;
  166. conditions=lv_evt_list;
  167. conds = {'hit'; 'miss'};
  168. condData = []; uData = [];
  169. for indGroup = 1
  170. if indGroup == 1
  171. relevantEntries = 1:groupsizes(1)*numel(conds);
  172. elseif indGroup == 2
  173. relevantEntries = groupsizes(1)*numel(conds)+1:...
  174. groupsizes(1)*numel(conds)+groupsizes(2)*numel(conds);
  175. end
  176. for indCond = 1:numel(conds)
  177. targetEntries = relevantEntries(conditions(relevantEntries)==indCond);
  178. condData{indGroup}(indCond,:) = result.vsc(targetEntries,indLV);
  179. uData{indGroup}(indCond,:) = result.usc(targetEntries,indLV);
  180. end
  181. end
  182. cBrew(1,:) = 2.*[.3 .1 .1];
  183. cBrew(2,:) = [.6 .6 .6];
  184. idx_outlier = cell(1); idx_standard = cell(1);
  185. for indGroup = 1
  186. dataToPlot = uData{indGroup}';
  187. % define outlier as lin. modulation that is more than three scaled median absolute deviations (MAD) away from the median
  188. X = [1 1; 1 2]; b=X\dataToPlot'; IndividualSlopes = b(2,:);
  189. outliers = isoutlier(IndividualSlopes, 'median');
  190. idx_outlier{indGroup} = find(outliers);
  191. idx_standard{indGroup} = find(outliers==0);
  192. end
  193. h = figure('units','centimeter','position',[0 0 8 10]);
  194. ax = subplot(1,1,1);
  195. for indGroup = 1
  196. dataToPlot = uData{indGroup}';
  197. % read into cell array of the appropriate dimensions
  198. data = []; data_ws = [];
  199. for i = 1:2
  200. for j = 1:1
  201. data{i, j} = dataToPlot(:,i);
  202. % individually demean for within-subject visualization
  203. data_ws{i, j} = dataToPlot(:,i)-...
  204. nanmean(dataToPlot(:,:),2)+...
  205. repmat(nanmean(nanmean(dataToPlot(:,:),2),1),size(dataToPlot(:,:),1),1);
  206. data_nooutlier{i, j} = data{i, j};
  207. data_nooutlier{i, j}(idx_outlier{indGroup}) = [];
  208. data_ws_nooutlier{i, j} = data_ws{i, j};
  209. data_ws_nooutlier{i, j}(idx_outlier{indGroup}) = [];
  210. % sort outliers to back in original data for improved plot overlap
  211. data_ws{i, j} = [data_ws{i, j}(idx_standard{indGroup}); data_ws{i, j}(idx_outlier{indGroup})];
  212. end
  213. end
  214. % IMPORTANT: plot individually centered estimates, stats on uncentered estimates!
  215. %subplot(1,2,indGroup);
  216. set(gcf,'renderer','Painters')
  217. cla;
  218. cl = cBrew(indGroup,:);
  219. [~, dist] = rm_raincloud_fixedSpacing(data_ws, [.8 .8 .8],1);
  220. h_rc = rm_raincloud_fixedSpacing(data_ws_nooutlier, cl,1,[],[],[],dist);
  221. view([90 -90]);
  222. axis ij
  223. box(gca,'off')
  224. set(gca, 'YTickLabels', {conds{2}; conds{1}});
  225. yticks = get(gca, 'ytick'); ylim([yticks(1)-(yticks(2)-yticks(1))./2, yticks(2)+(yticks(2)-yticks(1))./1.5]);
  226. minmax = [min(min(cat(2,data_ws{:}))), max(max(cat(2,data_ws{:})))];
  227. xlim(minmax+[-0.2*diff(minmax), 0.2*diff(minmax)])
  228. ylabel('recognition'); xlabel({'Brainscore'; '[Individually centered]'})
  229. % test linear effect
  230. curData = [data_nooutlier{1, 1}, data_nooutlier{2, 1}];
  231. X = [1 1; 1 2]; b=X\curData'; IndividualSlopes = b(2,:);
  232. [~, p, ci, stats] = ttest(IndividualSlopes);
  233. title(['M:', num2str(round(mean(IndividualSlopes),3)), '; p=', num2str(round(p,6))])
  234. end
  235. % make misses initial tick
  236. ax.XDir = 'reverse';
  237. set(ax, 'YTickLabels', {conds{1}; conds{2}});
  238. figureName = ['d1_rec_erp_rcp'];
  239. saveas(h, fullfile(pn.figures, figureName), 'epsc');
  240. saveas(h, fullfile(pn.figures, figureName), 'png');