瀏覽代碼

save nocsd branch

kosciessa 1 年之前
父節點
當前提交
da50421038
共有 100 個文件被更改,包括 5907 次插入228 次删除
  1. 8 9
      code/a_eegmp_calculate_erp_tfr.m
  2. 22 160
      code/c23_novelty_plot_theta_alpha.m
  3. 121 0
      code/extended/b2a_taskPLS_novelty_frontal_erp_2group.m
  4. 225 0
      code/extended/b2a_taskPLS_novelty_frontal_erp_2group_plotLV1.m
  5. 109 0
      code/prior/b1_taskPLS_scenecat_N1.m
  6. 111 0
      code/prior/b1_taskPLS_scenecat_N1_avg.m
  7. 153 0
      code/prior/b1_taskPLS_scenecat_N1_avg_plotLV1.m
  8. 181 0
      code/prior/b1_taskPLS_scenecat_N1_plotLV1.m
  9. 113 0
      code/prior/b2a_taskPLS_novelty_frontal_erp.m
  10. 181 0
      code/prior/b2a_taskPLS_novelty_frontal_erp_plotLV1.m
  11. 156 0
      code/prior/b2a_taskPLS_novelty_frontal_erp_plot_trace.m
  12. 106 0
      code/prior/b2b_taskPLS_novelty_frontal_theta.m
  13. 189 0
      code/prior/b2b_taskPLS_novelty_frontal_theta_plotLV1.m
  14. 116 0
      code/prior/b2c_taskPLS_novelty_posterior_alpha.m
  15. 179 0
      code/prior/b2c_taskPLS_novelty_posterior_alpha_LV1.m
  16. 127 0
      code/prior/b2x_novelty_plot_theta_alpha.m
  17. 106 0
      code/prior/b3a_taskPLS_recognition_erp.m
  18. 176 0
      code/prior/b3a_taskPLS_recognition_erp_LV1.m
  19. 107 0
      code/prior/b3b_taskPLS_recognition_erf.m
  20. 165 0
      code/prior/b3b_taskPLS_recognition_erf_LV1.m
  21. 106 0
      code/prior/b4a_taskPLS_memory_erp.m
  22. 176 0
      code/prior/b4a_taskPLS_memory_erp_LV1.m
  23. 107 0
      code/prior/b4b_taskPLS_memory_erf.m
  24. 198 0
      code/prior/b4b_taskPLS_memory_erf_LV1.m
  25. 224 0
      code/prior/b_scenecat_n1.m
  26. 413 0
      code/prior/b_scenecat_n1_bl.m
  27. 106 0
      code/unbaselined/d1_taskPLS_recognition_erp.m
  28. 234 0
      code/unbaselined/d1_taskPLS_recognition_erp_LV1.m
  29. 106 0
      code/unbaselined/e1_taskPLS_memory_erp.m
  30. 192 0
      code/unbaselined/e1_taskPLS_memory_erp_LV1.m
  31. 109 0
      code/z_archive/b1_taskPLS_scenecat_N1.m
  32. 111 0
      code/z_archive/b1_taskPLS_scenecat_N1_avg.m
  33. 153 0
      code/z_archive/b1_taskPLS_scenecat_N1_avg_plotLV1.m
  34. 181 0
      code/z_archive/b1_taskPLS_scenecat_N1_plotLV1.m
  35. 156 0
      code/z_archive/b2a_taskPLS_novelty_frontal_erp_plot_trace_tmp.m
  36. 303 0
      code/z_archive/b_scenecat_n1.m
  37. 106 0
      code/z_archive/e1_taskPLS_memory_erp copy.m
  38. 59 0
      code/z_eegmp_old_new_ERP.m
  39. 27 0
      code/z_eegmp_old_new_ERP_START.sh
  40. 130 0
      code/z_eegmp_old_new_ERP_trace.m
  41. 1 1
      data/erf/sub-001_erf.mat
  42. 1 1
      data/erf/sub-002_erf.mat
  43. 1 1
      data/erf/sub-003_erf.mat
  44. 1 1
      data/erf/sub-004_erf.mat
  45. 1 1
      data/erf/sub-005_erf.mat
  46. 1 1
      data/erf/sub-006_erf.mat
  47. 1 1
      data/erf/sub-007_erf.mat
  48. 1 1
      data/erf/sub-008_erf.mat
  49. 1 1
      data/erf/sub-009_erf.mat
  50. 1 1
      data/erf/sub-010_erf.mat
  51. 1 1
      data/erf/sub-011_erf.mat
  52. 1 1
      data/erf/sub-012_erf.mat
  53. 1 1
      data/erf/sub-013_erf.mat
  54. 1 1
      data/erf/sub-014_erf.mat
  55. 1 1
      data/erf/sub-015_erf.mat
  56. 1 1
      data/erf/sub-016_erf.mat
  57. 1 1
      data/erf/sub-017_erf.mat
  58. 1 1
      data/erf/sub-018_erf.mat
  59. 1 1
      data/erf/sub-019_erf.mat
  60. 1 1
      data/erf/sub-020_erf.mat
  61. 1 1
      data/erf/sub-021_erf.mat
  62. 1 1
      data/erf/sub-022_erf.mat
  63. 1 1
      data/erf/sub-023_erf.mat
  64. 1 1
      data/erf/sub-024_erf.mat
  65. 1 1
      data/erf/sub-025_erf.mat
  66. 1 1
      data/erf/sub-026_erf.mat
  67. 1 1
      data/erf/sub-027_erf.mat
  68. 1 1
      data/erf/sub-028_erf.mat
  69. 1 1
      data/erf/sub-029_erf.mat
  70. 1 1
      data/erf/sub-030_erf.mat
  71. 1 1
      data/erf/sub-031_erf.mat
  72. 1 1
      data/erf/sub-032_erf.mat
  73. 1 1
      data/erf/sub-033_erf.mat
  74. 1 1
      data/erp/sub-001_erp.mat
  75. 1 1
      data/erp/sub-001_erp_bl.mat
  76. 1 1
      data/erp/sub-002_erp.mat
  77. 1 1
      data/erp/sub-002_erp_bl.mat
  78. 1 1
      data/erp/sub-003_erp.mat
  79. 1 1
      data/erp/sub-003_erp_bl.mat
  80. 1 1
      data/erp/sub-004_erp.mat
  81. 1 1
      data/erp/sub-004_erp_bl.mat
  82. 1 1
      data/erp/sub-005_erp.mat
  83. 1 1
      data/erp/sub-005_erp_bl.mat
  84. 1 1
      data/erp/sub-006_erp.mat
  85. 1 1
      data/erp/sub-006_erp_bl.mat
  86. 1 1
      data/erp/sub-007_erp.mat
  87. 1 1
      data/erp/sub-007_erp_bl.mat
  88. 1 1
      data/erp/sub-008_erp.mat
  89. 1 1
      data/erp/sub-008_erp_bl.mat
  90. 1 1
      data/erp/sub-009_erp.mat
  91. 1 1
      data/erp/sub-009_erp_bl.mat
  92. 1 1
      data/erp/sub-010_erp.mat
  93. 1 1
      data/erp/sub-010_erp_bl.mat
  94. 1 1
      data/erp/sub-011_erp.mat
  95. 1 1
      data/erp/sub-011_erp_bl.mat
  96. 1 1
      data/erp/sub-012_erp.mat
  97. 1 1
      data/erp/sub-012_erp_bl.mat
  98. 1 1
      data/erp/sub-013_erp.mat
  99. 1 1
      data/erp/sub-013_erp_bl.mat
  100. 0 0
      data/erp/sub-014_erp.mat

+ 8 - 9
code/a_eegmp_calculate_erp_tfr.m

@@ -30,22 +30,21 @@ data_eeg = ft_preprocessing(cfg, data_eeg);
 
 %% CSD transform
     
-csd_cfg = [];
-csd_cfg.elecfile = 'standard_1005.elc';
-csd_cfg.method = 'spline';
-csd_cfg.degree = 14;
-data_eeg = ft_scalpcurrentdensity(csd_cfg, data_eeg);
+% csd_cfg = [];
+% csd_cfg.elecfile = 'standard_1005.elc';
+% csd_cfg.method = 'spline';
+% data_eeg = ft_scalpcurrentdensity(csd_cfg, data_eeg);
 
-%% time-frequency transform using superlets
+%% time-frequency transform using wavelets
 
 freq_cfg = [];
 freq_cfg.channel     = 'all';
-freq_cfg.method      = 'superlet';
-freq_cfg.width       = 3;
+freq_cfg.method      = 'wavelet';
+freq_cfg.width       = 5;
 freq_cfg.keeptrials  = 'yes';
 freq_cfg.output      = 'pow';
 freq_cfg.foi         = 1:1:40;
-freq_cfg.toi         = -1:0.025:2;
+freq_cfg.toi         = -1:0.05:2;
 tfr = ft_freqanalysis(freq_cfg, data_eeg);
 
 % single-trial log10-transform

+ 22 - 160
code/c23_novelty_plot_theta_alpha.m

@@ -60,15 +60,15 @@ condAvg = squeeze(nanmean(nanmean(mergeddata(:,idx_chans,:,1:2),2),4));
 
 h = figure('units','centimeters','position',[0 0 10 8]);
 cla; hold on;
-% highlight relevant phase in background
-patches.timeVec = [0.3 0.5];
-patches.colorVec = [1 .95 .8];
-for indP = 1:size(patches.timeVec,2)-1
-    YLim = [-4.95 -4.8];
-    p = patch([patches.timeVec(indP) patches.timeVec(indP+1) patches.timeVec(indP+1) patches.timeVec(indP)], ...
-                [YLim(1) YLim(1)  YLim(2), YLim(2)], patches.colorVec(indP,:));
-    p.EdgeColor = 'none';
-end
+% % highlight relevant phase in background
+% patches.timeVec = [0.3 0.5];
+% patches.colorVec = [1 .95 .8];
+% for indP = 1:size(patches.timeVec,2)-1
+%     YLim = [-4.95 -4.8];
+%     p = patch([patches.timeVec(indP) patches.timeVec(indP+1) patches.timeVec(indP+1) patches.timeVec(indP)], ...
+%                 [YLim(1) YLim(1)  YLim(2), YLim(2)], patches.colorVec(indP,:));
+%     p.EdgeColor = 'none';
+% end
 % new value = old value ? subject average + grand average
 curData = squeeze(nanmean(mergeddata(:,idx_chans,:,1),2));
 curData = curData-condAvg+repmat(nanmean(condAvg,1),size(condAvg,1),1);
@@ -83,7 +83,7 @@ l2 = shadedErrorBar(time,nanmean(curData,1),standError, 'lineprops', ...
 xlabel('Time (s) from stim onset')
 legend([l1.mainLine, l2.mainLine],{'old', 'new'}, ...
     'location', 'southeast'); legend('boxoff')
-xlim([-.5 1.5]); ylim(YLim)
+xlim([-.5 1.5]); %ylim(YLim)
 %xlim([-.05 .3]);
 ylabel({'theta power';'(log10)'});
 xlabel({'Time (s)'});    
@@ -100,15 +100,15 @@ condAvg = squeeze(nanmean(nanmean(mergeddata(1:17,idx_chans,:,1:2),2),4));
 
 h = figure('units','centimeters','position',[0 0 20 8]);
 subplot(1,2,1); cla; hold on;
-% highlight relevant phase in background
-patches.timeVec = [0.3 0.5];
-patches.colorVec = [1 .95 .8];
-for indP = 1:size(patches.timeVec,2)-1
-    YLim = [-4.95 -4.75];
-    p = patch([patches.timeVec(indP) patches.timeVec(indP+1) patches.timeVec(indP+1) patches.timeVec(indP)], ...
-                [YLim(1) YLim(1)  YLim(2), YLim(2)], patches.colorVec(indP,:));
-    p.EdgeColor = 'none';
-end
+% % highlight relevant phase in background
+% patches.timeVec = [0.3 0.5];
+% patches.colorVec = [1 .95 .8];
+% for indP = 1:size(patches.timeVec,2)-1
+%     YLim = [-4.95 -4.75];
+%     p = patch([patches.timeVec(indP) patches.timeVec(indP+1) patches.timeVec(indP+1) patches.timeVec(indP)], ...
+%                 [YLim(1) YLim(1)  YLim(2), YLim(2)], patches.colorVec(indP,:));
+%     p.EdgeColor = 'none';
+% end
 % new value = old value ? subject average + grand average
 curData = squeeze(nanmean(mergeddata(1:17,idx_chans,:,1),2));
 curData = curData-condAvg+repmat(nanmean(condAvg,1),size(condAvg,1),1);
@@ -123,7 +123,7 @@ l2 = shadedErrorBar(time,nanmean(curData,1),standError, 'lineprops', ...
 xlabel('Time (s) from stim onset')
 legend([l1.mainLine, l2.mainLine],{'old', 'new'}, ...
     'location', 'NorthEast'); legend('boxoff')
-xlim([-.5 1.5]); ylim(YLim)
+xlim([-.5 1.5]); %ylim(YLim)
 %xlim([-.05 .3]);
 ylabel({'theta power';'(log10)'});
 xlabel({'Time (s)'});
@@ -132,16 +132,6 @@ set(findall(gcf,'-property','FontSize'),'FontSize',12)
 
 subplot(1,2,2); cla; hold on;
 condAvg = squeeze(nanmean(nanmean(mergeddata(18:end,idx_chans,:,1:2),2),4));
-
-% highlight relevant phase in background
-patches.timeVec = [0.3 0.5];
-patches.colorVec = [1 .95 .8];
-for indP = 1:size(patches.timeVec,2)-1
-    YLim = [-4.95 -4.75];
-    p = patch([patches.timeVec(indP) patches.timeVec(indP+1) patches.timeVec(indP+1) patches.timeVec(indP)], ...
-                [YLim(1) YLim(1)  YLim(2), YLim(2)], patches.colorVec(indP,:));
-    p.EdgeColor = 'none';
-end
 % new value = old value ? subject average + grand average
 curData = squeeze(nanmean(mergeddata(18:end,idx_chans,:,1),2));
 curData = curData-condAvg+repmat(nanmean(condAvg,1),size(condAvg,1),1);
@@ -156,7 +146,7 @@ l2 = shadedErrorBar(time,nanmean(curData,1),standError, 'lineprops', ...
 xlabel('Time (s) from stim onset')
 legend([l1.mainLine, l2.mainLine],{'old', 'new'}, ...
     'location', 'NorthEast'); legend('boxoff')
-xlim([-.5 1.5]); ylim(YLim)
+xlim([-.5 1.5]);
 %xlim([-.05 .3]);
 ylabel({'theta power';'(log10)'});
 xlabel({'Time (s)'});
@@ -176,15 +166,6 @@ condAvg = squeeze(nanmean(nanmean(mergeddata(:,idx_chans,:,1:2),2),4));
 
 h = figure('units','centimeters','position',[0 0 10 8]);
 cla; hold on;
-% highlight relevant phase in background
-patches.timeVec = [0.3 0.5];
-patches.colorVec = [1 .95 .8];
-for indP = 1:size(patches.timeVec,2)-1
-    YLim = [-5.2 -4.5];
-    p = patch([patches.timeVec(indP) patches.timeVec(indP+1) patches.timeVec(indP+1) patches.timeVec(indP)], ...
-                [YLim(1) YLim(1)  YLim(2), YLim(2)], patches.colorVec(indP,:));
-    p.EdgeColor = 'none';
-end
 % new value = old value ? subject average + grand average
 curData = squeeze(nanmean(mergeddata(:,idx_chans,:,1),2));
 curData = curData-condAvg+repmat(nanmean(condAvg,1),size(condAvg,1),1);
@@ -198,7 +179,7 @@ l2 = shadedErrorBar(time,nanmean(curData,1),standError, 'lineprops', ...
     {'color', 'r','linewidth', 3}, 'patchSaturation', .1);
 xlabel('Time (s) from stim onset')
 legend([l1.mainLine, l2.mainLine],{'old', 'new'}, 'location', 'northeast'); legend('boxoff')
-xlim([-.5 1.5]); ylim(YLim)
+xlim([-.5 1.5]);
 %xlim([-.05 .3]);
 ylabel({'alpha power';'(log10)'});
 xlabel({'Time (s)'});    
@@ -207,122 +188,3 @@ set(findall(gcf,'-property','FontSize'),'FontSize',15)
 figureName = ['c_novelty_alpha'];
 saveas(h, fullfile(pn.figures, figureName), 'epsc');
 saveas(h, fullfile(pn.figures, figureName), 'png');
-
-%% visualize for two groups
-
-idx_chans = idx_chans_a;
-condAvg = squeeze(nanmean(nanmean(mergeddata(1:17,idx_chans,:,1:2),2),4));
-
-h = figure('units','centimeters','position',[0 0 20 8]);
-subplot(1,2,1); cla; hold on;
-% highlight relevant phase in background
-patches.timeVec = [0.3 0.5];
-patches.colorVec = [1 .95 .8];
-for indP = 1:size(patches.timeVec,2)-1
-    YLim = [-5.2 -4.5];
-    p = patch([patches.timeVec(indP) patches.timeVec(indP+1) patches.timeVec(indP+1) patches.timeVec(indP)], ...
-                [YLim(1) YLim(1)  YLim(2), YLim(2)], patches.colorVec(indP,:));
-    p.EdgeColor = 'none';
-end
-% new value = old value ? subject average + grand average
-curData = squeeze(nanmean(mergeddata(1:17,idx_chans,:,1),2));
-curData = curData-condAvg+repmat(nanmean(condAvg,1),size(condAvg,1),1);
-standError = nanstd(curData,1)./sqrt(size(curData,1));
-l1 = shadedErrorBar(time,nanmean(curData,1),standError, 'lineprops', ...
-    {'color', 'k','linewidth', 2}, 'patchSaturation', .1);
-curData = squeeze(nanmean(mergeddata(1:17,idx_chans,:,2),2));
-curData = curData-condAvg+repmat(nanmean(condAvg,1),size(condAvg,1),1);
-standError = nanstd(curData,1)./sqrt(size(curData,1));
-l2 = shadedErrorBar(time,nanmean(curData,1),standError, 'lineprops', ...
-    {'color', 'r','linewidth', 2}, 'patchSaturation', .1);
-xlabel('Time (s) from stim onset')
-legend([l1.mainLine, l2.mainLine],{'old', 'new'}, ...
-    'location', 'NorthEast'); legend('boxoff')
-xlim([-.5 1.5]); ylim(YLim)
-%xlim([-.05 .3]);
-ylabel({'alpha power';'(log10)'});
-xlabel({'Time (s)'});
-title('Initial 17');
-set(findall(gcf,'-property','FontSize'),'FontSize',12)
-
-subplot(1,2,2); cla; hold on;
-condAvg = squeeze(nanmean(nanmean(mergeddata(18:end,idx_chans,:,1:2),2),4));
-
-% highlight relevant phase in background
-patches.timeVec = [0.3 0.5];
-patches.colorVec = [1 .95 .8];
-for indP = 1:size(patches.timeVec,2)-1
-    YLim = [-5.2 -4.5];
-    p = patch([patches.timeVec(indP) patches.timeVec(indP+1) patches.timeVec(indP+1) patches.timeVec(indP)], ...
-                [YLim(1) YLim(1)  YLim(2), YLim(2)], patches.colorVec(indP,:));
-    p.EdgeColor = 'none';
-end
-% new value = old value ? subject average + grand average
-curData = squeeze(nanmean(mergeddata(18:end,idx_chans,:,1),2));
-curData = curData-condAvg+repmat(nanmean(condAvg,1),size(condAvg,1),1);
-standError = nanstd(curData,1)./sqrt(size(curData,1));
-l1 = shadedErrorBar(time,nanmean(curData,1),standError, 'lineprops', ...
-    {'color', 'k','linewidth', 2}, 'patchSaturation', .1);
-curData = squeeze(nanmean(mergeddata(18:end,idx_chans,:,2),2));
-curData = curData-condAvg+repmat(nanmean(condAvg,1),size(condAvg,1),1);
-standError = nanstd(curData,1)./sqrt(size(curData,1));
-l2 = shadedErrorBar(time,nanmean(curData,1),standError, 'lineprops', ...
-    {'color', 'r','linewidth', 2}, 'patchSaturation', .1);
-xlabel('Time (s) from stim onset')
-legend([l1.mainLine, l2.mainLine],{'old', 'new'}, ...
-    'location', 'NorthEast'); legend('boxoff')
-xlim([-.5 1.5]); ylim(YLim)
-%xlim([-.05 .3]);
-ylabel({'alpha power';'(log10)'});
-xlabel({'Time (s)'});
-title('Final 16');
-set(findall(gcf,'-property','FontSize'),'FontSize',12)
-
-figureName = ['c_novelty_alpha_bygroup'];
-saveas(h, fullfile(pn.figures, figureName), 'epsc');
-saveas(h, fullfile(pn.figures, figureName), 'png');
-
-%% plot superimposed
-
-mergeddata = cat(4, thetagroup.old.old.avg, thetagroup.old.new.avg);
-
-idx_chans = [33,4,47]; 
-h = figure('units','centimeters','position',[0 0 10 8]);
-cla; hold on;
-% new value = old value ? subject average + grand average
-curData = squeeze(nanmean(nanmean(mergeddata(1:17,idx_chans,:,1:2),4),2));
-standError = nanstd(curData,1)./sqrt(size(curData,1));
-l1 = shadedErrorBar(time,nanmean(curData,1),standError, 'lineprops', ...
-    {'color', 'k','linewidth', 2}, 'patchSaturation', .1);
-curData = squeeze(nanmean(nanmean(mergeddata(18:end,idx_chans,:,1:2),4),2));
-standError = nanstd(curData,1)./sqrt(size(curData,1));
-l2 = shadedErrorBar(time,nanmean(curData,1),standError, 'lineprops', ...
-    {'color', 'r','linewidth', 2}, 'patchSaturation', .1);
-xlabel('Time (s) from stim onset')
-legend([l1.mainLine, l2.mainLine],{'initial', 'final'}, ...
-    'location', 'southeast'); legend('boxoff')
-xlim([-.5 1.5]); ylim([-5.1 -4.75])
-ylabel({'theta power';'(log10)'});
-set(findall(gcf,'-property','FontSize'),'FontSize',12)
-
-mergeddata = cat(4, alphagroup.old.old.avg, alphagroup.old.new.avg);
-
-idx_chans = idx_chans_a;
-
-h = figure('units','centimeters','position',[0 0 10 8]);
-cla; hold on;
-% new value = old value ? subject average + grand average
-curData = squeeze(nanmean(nanmean(mergeddata(1:17,idx_chans,:,1:2),4),2));
-standError = nanstd(curData,1)./sqrt(size(curData,1));
-l1 = shadedErrorBar(time,nanmean(curData,1),standError, 'lineprops', ...
-    {'color', 'k','linewidth', 2}, 'patchSaturation', .1);
-curData = squeeze(nanmean(nanmean(mergeddata(18:end,idx_chans,:,1:2),4),2));
-standError = nanstd(curData,1)./sqrt(size(curData,1));
-l2 = shadedErrorBar(time,nanmean(curData,1),standError, 'lineprops', ...
-    {'color', 'r','linewidth', 2}, 'patchSaturation', .1);
-xlabel('Time (s) from stim onset')
-legend([l1.mainLine, l2.mainLine],{'initial', 'final'}, ...
-    'location', 'southeast'); legend('boxoff')
-xlim([-.5 1.5]); ylim([-5.2 -4.5])
-ylabel({'alpha power';'(log10)'});
-set(findall(gcf,'-property','FontSize'),'FontSize',12)

+ 121 - 0
code/extended/b2a_taskPLS_novelty_frontal_erp_2group.m

@@ -0,0 +1,121 @@
+% Set up EEG PLS for a task PLS using spectral power
+
+clear all; cla; clc;
+
+currentFile = mfilename('fullpath');
+[pathstr,~,~] = fileparts(currentFile);
+cd(fullfile(pathstr,'..'))
+rootpath = pwd;
+
+pn.data_eeg = fullfile(rootpath, '..', 'eegmp_preproc', 'data', 'outputs', 'eeg');
+pn.data_erp = fullfile(rootpath, 'data', 'erp');
+pn.data_erf = fullfile(rootpath, 'data', 'erf');
+pn.data = fullfile(rootpath, 'data', 'stats'); mkdir(pn.data);
+pn.tools = fullfile(rootpath, 'tools');
+    addpath(fullfile(rootpath, '..', 'eegmp_preproc', 'tools', 'fieldtrip')); ft_defaults
+    addpath(genpath(fullfile(pn.tools, '[MEG]PLS', 'MEGPLS_PIPELINE_v2.02b')))
+    addpath(fullfile(pn.tools, 'BrewerMap'));
+    addpath(fullfile(pn.tools, 'shadedErrorBar'));
+
+%% add seed for reproducibility
+
+rng(0, 'twister');
+    
+%% load event info
+
+load(fullfile(pn.data_eeg, ['sub-001_task-xxxx_eeg_art.mat']), 'events');
+
+parameter = {'scene_category'; 'old'; 'behavior'; 'subsequent_memory'};
+for ind_param = 1:numel(parameter)
+    conds.(parameter{ind_param}) = unique(events.(parameter{ind_param}));
+end
+
+%% load erp
+
+for ind_id = 1:33
+    id = sprintf('sub-%03d', ind_id); disp(id)
+    load(fullfile(pn.data_erp, [id,'_erp_bl.mat']));
+    for ind_option = 1:numel(conds.old)
+        if ind_id == 1
+             erpgroup.old.(conds.old{ind_option}) = erp_bl.old{ind_option};
+             erpgroup.old.(conds.old{ind_option}) = ...
+                 rmfield(erpgroup.old.(conds.old{ind_option}), {'avg', 'var', 'dof'});
+             erpgroup.old.(conds.old{ind_option}).dimord = 'sub_chan_time';
+        end
+        % only include time points from 300 - 500 ms
+        time = erpgroup.old.(conds.old{ind_option}).time;
+        toi = time >0.3 & time <0.5;
+        erpgroup.old.(conds.old{ind_option}).avg(ind_id,:,:) = erp_bl.old{ind_option}.avg(:,toi);
+    end
+end
+
+time = erpgroup.old.old.time(toi);
+elec = erpgroup.old.old.elec;
+channels = erpgroup.old.old.label;
+
+mergeddata = cat(4, erpgroup.old.old.avg, ...
+    erpgroup.old.new.avg);
+
+% identify frontal channels, and set everything else to zero
+idx_chans = startsWith(channels, 'F') | startsWith(channels, 'A') | startsWith(channels, 'C') & ~startsWith(channels, 'CP');
+mergeddata(:, idx_chans==0,:,:) = 0;
+
+% split into two groups
+
+mergeddata_tmp{1} = mergeddata(1:17,:,:,:);
+mergeddata_tmp{2} = mergeddata(18:end,:,:,:);
+
+mergeddata = mergeddata_tmp;
+
+num_chans = numel(channels);
+num_freqs = 1;
+num_time = numel(time);
+
+num_subj_lst = [17 16];
+num_cond = 2;
+num_grp = 2;
+
+datamat_lst = cell(num_grp); lv_evt_list = [];
+indCount_cont = 1;
+for indGroup = 1:num_grp
+    indCount = 1;    
+    for indCond = 1:num_cond
+        for indID = 1:num_subj_lst(indGroup)
+            datamat_lst{indGroup}(indCount,:) = reshape(squeeze(mergeddata{indGroup}(indID,:,:,indCond)), [], 1);
+            lv_evt_list(indCount_cont) = indCond;
+            indCount = indCount+1;
+            indCount_cont = indCount_cont+1;
+        end
+    end
+end
+datamat_lst{indGroup}(isnan(datamat_lst{indGroup})) = 0;
+
+%% set PLS options and run PLS
+
+option = [];
+option.method = 1; % [1] | 2 | 3 | 4 | 5 | 6
+option.num_perm = 1000; %( single non-negative integer )
+option.num_split = 0; %( single non-negative integer )
+option.num_boot = 1000; % ( single non-negative integer )
+option.cormode = 0; % [0] | 2 | 4 | 6
+option.meancentering_type = 0;% [0] | 1 | 2 | 3
+option.boot_type = 'strat'; %['strat'] | 'nonstrat'
+
+result = pls_analysis(datamat_lst, num_subj_lst, num_cond, option);
+
+%% rearrange into fieldtrip structure
+
+lvdat = reshape(result.boot_result.compare_u(:,1), num_chans, num_freqs, num_time);
+%udat = reshape(result.u, num_chans, num_freqs, num_time);
+
+stat = [];
+stat.prob = lvdat;
+stat.dimord = 'chan_freq_time';
+stat.clusters = [];
+stat.clusters.prob = result.perm_result.sprob; % check for significance of LV
+stat.mask = lvdat > 3 | lvdat < -3;
+stat.cfg = option;
+stat.time = time;
+
+save(fullfile(pn.data, 'c01_taskpls_erp_group.mat'),...
+    'stat', 'result', 'lvdat', 'lv_evt_list', 'num_chans', 'num_freqs', 'num_time')

+ 225 - 0
code/extended/b2a_taskPLS_novelty_frontal_erp_2group_plotLV1.m

@@ -0,0 +1,225 @@
+% Create an overview plot featuring the results of the multivariate PLS
+% comparing spectral changes during the stimulus period under load
+
+clear all; cla; clc;
+
+currentFile = mfilename('fullpath');
+[pathstr,~,~] = fileparts(currentFile);
+cd(fullfile(pathstr,'..'))
+rootpath = pwd;
+
+pn.data         = fullfile(rootpath, 'data', 'stats');
+pn.figures      = fullfile(rootpath, 'figures');
+pn.tools        = fullfile(rootpath, 'tools');
+    addpath(genpath(fullfile(pn.tools, '[MEG]PLS', 'MEGPLS_PIPELINE_v2.02b')))
+    addpath(fullfile(pn.tools, 'fieldtrip')); ft_defaults;
+    addpath(genpath(fullfile(pn.tools, 'RainCloudPlots')));
+    addpath(fullfile(pn.tools, 'BrewerMap'));
+    addpath(fullfile(pn.tools, 'winsor'));
+
+% set custom colormap
+cBrew = brewermap(500,'RdBu');
+cBrew = flipud(cBrew);
+colormap(cBrew)
+
+load(fullfile(pn.data, 'c01_taskpls_erp_group.mat'),...
+    'stat', 'result', 'lvdat', 'lv_evt_list', 'num_chans', 'num_freqs', 'num_time')
+load(fullfile(rootpath, 'data','erp', ['sub-001_erp.mat']));
+elec = erp.scene_category{1}.elec;
+
+result.perm_result.sprob
+
+indLV = 1;
+
+lvdat = reshape(result.boot_result.compare_u(:,indLV), num_chans, num_freqs, num_time);
+stat.prob = lvdat;
+stat.mask = lvdat > 3 | lvdat < -3;
+
+% maskNaN = double(stat.mask);
+% maskNaN(maskNaN==0) = NaN;
+
+%% invert solution
+
+% stat.mask = stat.mask;
+% stat.prob = stat.prob.*-1;
+% result.vsc = result.vsc.*-1;
+% result.usc = result.usc.*-1;
+
+h = figure('units','centimeter','position',[0 0 15 10]);
+set(gcf,'renderer','Painters')
+statsPlot = [];
+statsPlot = cat(1, statsPlot,squeeze(nanmax(abs(stat.prob(1:64,:,:)),[],1)));
+plot(stat.time,statsPlot, 'k')
+xlabel('Time [s from stim onset]'); ylabel('max abs BSR');
+title({'ERP changes'; ['p = ', num2str(round(result.perm_result.sprob(indLV),4))]})
+set(findall(gcf,'-property','FontSize'),'FontSize',18)
+% figureName = ['b01_pls_traces'];
+% saveas(h, fullfile(pn.figures, figureName), 'epsc');
+% saveas(h, fullfile(pn.figures, figureName), 'png');
+
+
+h = figure('units','centimeter','position',[0 0 15 10]);
+set(gcf,'renderer','Painters')
+statsPlot = [];
+statsPlot = cat(1, statsPlot,squeeze(mean(stat.prob(1:64,:,:),1)));
+plot(stat.time,statsPlot, 'k')
+xlabel('Time [s from stim onset]'); ylabel('mean BSR');
+title({'ERP changes'; ['p = ', num2str(round(result.perm_result.sprob(indLV),4))]})
+set(findall(gcf,'-property','FontSize'),'FontSize',18)
+%xlim([0 0.3])
+% figureName = ['b01_pls_traces'];
+% saveas(h, fullfile(pn.figures, figureName), 'epsc');
+% saveas(h, fullfile(pn.figures, figureName), 'png');
+
+%% plot multivariate topographies
+
+h = figure('units','centimeters','position',[0 0 10 10]);
+set(gcf,'renderer','Painters')
+
+cfg = [];
+cfg.layout = 'biosemi64.lay';
+cfg.parameter = 'powspctrm';
+cfg.comment = 'no';
+cfg.colormap = cBrew;
+cfg.colorbar = 'EastOutside';
+
+plotData = [];
+plotData.label = elec.label; % {1 x N}
+plotData.dimord = 'chan';
+cfg.zlim = [-2 2]; 
+cfg.figure = h;
+plotData.powspctrm = squeeze(nanmean(stat.mask(:,:,:).*...
+    stat.prob(:,:,:),3)); 
+ft_topoplotER(cfg,plotData);
+cb = colorbar('location', 'EastOutside'); set(get(cb,'ylabel'),'string','Mean BSR');
+figureName = ['b01_lv1'];
+% saveas(h, fullfile(pn.figures, figureName), 'epsc');
+% saveas(h, fullfile(pn.figures, figureName), 'png');
+
+%% plot using raincloud plot
+
+groupsizes=result.num_subj_lst;
+conditions=lv_evt_list;
+conds = {'old'; 'new'};
+condData = []; uData = [];
+for indGroup = 1:2
+    if indGroup == 1
+        relevantEntries = 1:groupsizes(1)*numel(conds);
+    elseif indGroup == 2
+        relevantEntries = groupsizes(1)*numel(conds)+1:...
+             groupsizes(1)*numel(conds)+groupsizes(2)*numel(conds);
+    end
+    for indCond = 1:numel(conds)
+        targetEntries = relevantEntries(conditions(relevantEntries)==indCond);        
+        condData{indGroup}(indCond,:) = result.vsc(targetEntries,indLV);
+        uData{indGroup}(indCond,:) = result.usc(targetEntries,indLV);
+    end
+end
+
+%% plot RainCloudPlot (within-subject centered)
+
+cBrew(1,:) = 2.*[.3 .1 .1];
+cBrew(2,:) = 2.*[.3 .1 .1];
+
+idx_outlier = cell(1); idx_standard = cell(1);
+for indGroup = 1:2
+    dataToPlot = uData{indGroup}';
+    % define outlier as lin. modulation that is more than three scaled median absolute deviations (MAD) away from the median
+    X = [1 1; 1 2]; b=X\dataToPlot'; IndividualSlopes = b(2,:);
+    outliers = isoutlier(IndividualSlopes, 'median');
+    idx_outlier{indGroup} = find(outliers);
+    idx_standard{indGroup} = find(outliers==0);
+end
+
+h = figure('units','centimeter','position',[0 0 25 10]);
+for indGroup = 1:2
+    dataToPlot = uData{indGroup}';
+    % read into cell array of the appropriate dimensions
+    data = []; data_ws = [];
+    for i = 1:2
+        for j = 1:1
+            data{i, j} = dataToPlot(:,i);
+            % individually demean for within-subject visualization
+            data_ws{i, j} = dataToPlot(:,i)-...
+                nanmean(dataToPlot(:,:),2)+...
+                repmat(nanmean(nanmean(dataToPlot(:,:),2),1),size(dataToPlot(:,:),1),1);
+            data_nooutlier{i, j} = data{i, j};
+            data_nooutlier{i, j}(idx_outlier{indGroup}) = [];
+            data_ws_nooutlier{i, j} = data_ws{i, j};
+            data_ws_nooutlier{i, j}(idx_outlier{indGroup}) = [];
+            % sort outliers to back in original data for improved plot overlap
+            data_ws{i, j} = [data_ws{i, j}(idx_standard{indGroup}); data_ws{i, j}(idx_outlier{indGroup})];
+        end
+    end
+
+    % IMPORTANT: plot individually centered estimates, stats on uncentered estimates!
+
+    subplot(1,2,indGroup);
+    set(gcf,'renderer','Painters')
+        cla;
+        cl = cBrew(indGroup,:);
+        [~, dist] = rm_raincloud_fixedSpacing(data_ws, [.8 .8 .8],1);
+        h_rc = rm_raincloud_fixedSpacing(data_ws_nooutlier, cl,1,[],[],[],dist);
+        view([90 -90]);
+        axis ij
+    box(gca,'off')
+    set(gca, 'YTickLabels', {conds{2}; conds{1}});
+    yticks = get(gca, 'ytick'); ylim([yticks(1)-(yticks(2)-yticks(1))./2, yticks(2)+(yticks(2)-yticks(1))./1.5]);
+
+    minmax = [min(min(cat(2,data_ws{:}))), max(max(cat(2,data_ws{:})))];
+    xlim(minmax+[-0.2*diff(minmax), 0.2*diff(minmax)])
+    ylabel('novelty'); xlabel({'Brainscore'; '[Individually centered]'})
+
+    % test linear effect
+    curData = [data_nooutlier{1, 1}, data_nooutlier{2, 1}];
+    X = [1 1; 1 2]; b=X\curData'; IndividualSlopes = b(2,:);
+    [~, p, ci, stats] = ttest(IndividualSlopes);
+    title(['M:', num2str(round(mean(IndividualSlopes),3)), '; p=', num2str(round(p,3))])
+end
+% figureName = ['b01_rcp'];
+% saveas(h, fullfile(pn.figures, figureName), 'epsc');
+% saveas(h, fullfile(pn.figures, figureName), 'png');
+
+%% plot potential differences between age groups
+
+data2Plot{1,1} = diff(uData{1})';
+data2Plot{2,1} = diff(uData{2})';
+fields_title{1} = 'Brainscores';
+
+% plot linear estimates using bar charts with individual values
+
+colorm = [.6 .6 .6; 1 .6 .6; .6 .8 1];
+
+indParam = 1%:numel(fields_name)
+    h = figure('units','centimeters','position',[.1 .1 7 10]);
+    plot_data{1} = data2Plot{1,indParam};
+    plot_data{2} = data2Plot{2,indParam};
+    set(gcf,'renderer','Painters')
+    cla;
+    hold on;
+    for indGroup = 1:2
+        if ttest(plot_data{indGroup})==1 & nanmean(plot_data{indGroup})>0
+            bar(indGroup, nanmean(plot_data{indGroup}), 'FaceColor', colorm(2,:), 'EdgeColor', 'none', 'BarWidth', 0.8);
+        elseif ttest(plot_data{indGroup})==1 & nanmean(plot_data{indGroup})<0
+            bar(indGroup, nanmean(plot_data{indGroup}), 'FaceColor', colorm(3,:), 'EdgeColor', 'none', 'BarWidth', 0.8);
+        elseif ttest(plot_data{indGroup})==0
+            bar(indGroup, nanmean(plot_data{indGroup}), 'FaceColor', colorm(1,:), 'EdgeColor', 'none', 'BarWidth', 0.8);
+        end
+        % plot individual values on top
+        scatter(repmat(indGroup,numel(plot_data{indGroup}),1)+(rand(numel(plot_data{indGroup}),1)-.5).*.4,...
+            plot_data{indGroup}, 20, 'filled', 'MarkerFaceColor', [.3 .3 .3]);
+    end
+    xlim([.25 2.75]); %ylim([1.3 2])
+    set(gca,'xtick',[1,2]); set(gca,'xTickLabel',{'YA'; 'OA'});
+    xlabel('Age Group'); ylabel([fields_title{indParam}])
+    set(findall(gcf,'-property','FontSize'),'FontSize',20)
+    [htest, p] = ttest2(plot_data{1}, plot_data{2});
+    if p>10^-3
+        title(['p = ', num2str(round(p,2))]);
+    else
+        tit = sprintf('p = %.1e',p);
+        title(tit);
+    end
+%     figureName = ['l1comp_', fields_title{indParam}];
+%     saveas(h, fullfile(pn.figures, figureName), 'epsc');
+%     saveas(h, fullfile(pn.figures, figureName), 'png');

+ 109 - 0
code/prior/b1_taskPLS_scenecat_N1.m

@@ -0,0 +1,109 @@
+% Set up EEG PLS for a task PLS using spectral power
+
+clear all; cla; clc;
+
+currentFile = mfilename('fullpath');
+[pathstr,~,~] = fileparts(currentFile);
+cd(fullfile(pathstr,'..'))
+rootpath = pwd;
+
+pn.data_eeg = fullfile(rootpath, '..', 'eegmp_preproc', 'data', 'outputs', 'eeg');
+pn.data_erp = fullfile(rootpath, 'data', 'erp');
+pn.data_erf = fullfile(rootpath, 'data', 'erf');
+pn.data = fullfile(rootpath, 'data', 'stats'); mkdir(pn.data);
+pn.tools = fullfile(rootpath, 'tools');
+    addpath(fullfile(rootpath, '..', 'eegmp_preproc', 'tools', 'fieldtrip')); ft_defaults
+    addpath(genpath(fullfile(pn.tools, '[MEG]PLS', 'MEGPLS_PIPELINE_v2.02b')))
+    addpath(fullfile(pn.tools, 'BrewerMap'));
+    addpath(fullfile(pn.tools, 'shadedErrorBar'));
+
+%% add seed for reproducibility
+
+rng(0, 'twister');
+    
+%% load event info
+
+load(fullfile(pn.data_eeg, ['sub-001_task-xxxx_eeg_art.mat']), 'events');
+
+parameter = {'scene_category'; 'old'; 'behavior'; 'subsequent_memory'};
+for ind_param = 1:numel(parameter)
+    conds.(parameter{ind_param}) = unique(events.(parameter{ind_param}));
+end
+
+%% load erp
+
+for ind_id = 1:33
+    id = sprintf('sub-%03d', ind_id);
+    load(fullfile(pn.data_erp, [id,'_erp_bl.mat']));
+    for ind_option = 1:numel(conds.scene_category)
+        if ind_id == 1
+             erpgroup.scene_category.(conds.scene_category{ind_option}) = erp_bl.scene_category{ind_option};
+             erpgroup.scene_category.(conds.scene_category{ind_option}) = ...
+                 rmfield(erpgroup.scene_category.(conds.scene_category{ind_option}), {'avg', 'var', 'dof'});
+             erpgroup.scene_category.(conds.scene_category{ind_option}).dimord = 'sub_chan_time';
+        end
+        % only include time points from 0 to 300 ms
+        time = erp_bl.scene_category{ind_option}.time;
+        toi = time >0 & time <0.3;        
+        erpgroup.scene_category.(conds.scene_category{ind_option}).avg(ind_id,:,:) = erp_bl.scene_category{ind_option}.avg(:,toi);
+    end
+end
+
+time = erpgroup.scene_category.manmade.time(toi);
+elec = erpgroup.scene_category.manmade.elec;
+channels = erpgroup.scene_category.manmade.label;
+
+mergeddata = cat(4, erpgroup.scene_category.manmade.avg, ...
+    erpgroup.scene_category.natural.avg);
+
+num_chans = numel(channels);
+num_freqs = 1;
+num_time = numel(time);
+
+num_subj_lst = [33];
+num_cond = 2;
+num_grp = 1;
+
+datamat_lst = cell(num_grp); lv_evt_list = [];
+indCount_cont = 1;
+indCount = 1;
+indGroup = 1;
+for indCond = 1:num_cond
+    for indID = 1:num_subj_lst(indGroup)
+        datamat_lst{indGroup}(indCount,:) = reshape(squeeze(mergeddata(indID,:,:,indCond)), [], 1);
+        lv_evt_list(indCount_cont) = indCond;
+        indCount = indCount+1;
+        indCount_cont = indCount_cont+1;
+    end
+end
+datamat_lst{indGroup}(isnan(datamat_lst{indGroup})) = 0;
+
+%% set PLS options and run PLS
+
+option = [];
+option.method = 1; % [1] | 2 | 3 | 4 | 5 | 6
+option.num_perm = 1000; %( single non-negative integer )
+option.num_split = 0; %( single non-negative integer )
+option.num_boot = 1000; % ( single non-negative integer )
+option.cormode = 0; % [0] | 2 | 4 | 6
+option.meancentering_type = 0;% [0] | 1 | 2 | 3
+option.boot_type = 'strat'; %['strat'] | 'nonstrat'
+
+result = pls_analysis(datamat_lst, num_subj_lst, num_cond, option);
+
+%% rearrange into fieldtrip structure
+
+lvdat = reshape(result.boot_result.compare_u(:,1), num_chans, num_freqs, num_time);
+%udat = reshape(result.u, num_chans, num_freqs, num_time);
+
+stat = [];
+stat.prob = lvdat;
+stat.dimord = 'chan_freq_time';
+stat.clusters = [];
+stat.clusters.prob = result.perm_result.sprob; % check for significance of LV
+stat.mask = lvdat > 3 | lvdat < -3;
+stat.cfg = option;
+stat.time = time;
+
+save(fullfile(pn.data, 'b01_taskpls_erp.mat'),...
+    'stat', 'result', 'lvdat', 'lv_evt_list', 'num_chans', 'num_freqs', 'num_time')

+ 111 - 0
code/prior/b1_taskPLS_scenecat_N1_avg.m

@@ -0,0 +1,111 @@
+% Set up EEG PLS for a task PLS using spectral power
+
+clear all; cla; clc;
+
+currentFile = mfilename('fullpath');
+[pathstr,~,~] = fileparts(currentFile);
+cd(fullfile(pathstr,'..'))
+rootpath = pwd;
+
+pn.data_eeg = fullfile(rootpath, '..', 'eegmp_preproc', 'data', 'outputs', 'eeg');
+pn.data_erp = fullfile(rootpath, 'data', 'erp');
+pn.data_erf = fullfile(rootpath, 'data', 'erf');
+pn.data = fullfile(rootpath, 'data', 'stats'); mkdir(pn.data);
+pn.tools = fullfile(rootpath, 'tools');
+    addpath(fullfile(rootpath, '..', 'eegmp_preproc', 'tools', 'fieldtrip')); ft_defaults
+    addpath(genpath(fullfile(pn.tools, '[MEG]PLS', 'MEGPLS_PIPELINE_v2.02b')))
+    addpath(fullfile(pn.tools, 'BrewerMap'));
+    addpath(fullfile(pn.tools, 'shadedErrorBar'));
+
+%% add seed for reproducibility
+
+rng(0, 'twister');
+    
+%% load event info
+
+load(fullfile(pn.data_eeg, ['sub-001_task-xxxx_eeg_art.mat']), 'events');
+
+parameter = {'scene_category'; 'old'; 'behavior'; 'subsequent_memory'};
+for ind_param = 1:numel(parameter)
+    conds.(parameter{ind_param}) = unique(events.(parameter{ind_param}));
+end
+
+%% load erp
+
+for ind_id = 1:33
+    id = sprintf('sub-%03d', ind_id);
+    load(fullfile(pn.data_erp, [id,'_erp.mat']));
+    for ind_option = 1:numel(conds.scene_category)
+        if ind_id == 1
+             erpgroup.scene_category.(conds.scene_category{ind_option}) = erp.scene_category{ind_option};
+             erpgroup.scene_category.(conds.scene_category{ind_option}) = ...
+                 rmfield(erpgroup.scene_category.(conds.scene_category{ind_option}), {'avg', 'var', 'dof'});
+             erpgroup.scene_category.(conds.scene_category{ind_option}).dimord = 'sub_chan_time';
+        end
+        % average in N1 time window
+        time = erpgroup.scene_category.(conds.scene_category{ind_option}).time;
+        toi = time >0.08 & time <0.12;
+        erpgroup.scene_category.(conds.scene_category{ind_option}).avg(ind_id,:,:) = nanmean(erp.scene_category{ind_option}.avg(:,toi),2);
+    end
+end
+
+% average in N1 time window
+
+time = 0.1;
+elec = erpgroup.scene_category.manmade.elec;
+channels = erpgroup.scene_category.manmade.label;
+
+mergeddata = cat(4, erpgroup.scene_category.manmade.avg, ...
+    erpgroup.scene_category.natural.avg);
+
+num_chans = numel(channels);
+num_freqs = 1;
+num_time = numel(time);
+
+num_subj_lst = [33];
+num_cond = 2;
+num_grp = 1;
+
+datamat_lst = cell(num_grp); lv_evt_list = [];
+indCount_cont = 1;
+indCount = 1;
+indGroup = 1;
+for indCond = 1:num_cond
+    for indID = 1:num_subj_lst(indGroup)
+        datamat_lst{indGroup}(indCount,:) = reshape(squeeze(mergeddata(indID,:,:,indCond)), [], 1);
+        lv_evt_list(indCount_cont) = indCond;
+        indCount = indCount+1;
+        indCount_cont = indCount_cont+1;
+    end
+end
+datamat_lst{indGroup}(isnan(datamat_lst{indGroup})) = 0;
+
+%% set PLS options and run PLS
+
+option = [];
+option.method = 1; % [1] | 2 | 3 | 4 | 5 | 6
+option.num_perm = 1000; %( single non-negative integer )
+option.num_split = 0; %( single non-negative integer )
+option.num_boot = 1000; % ( single non-negative integer )
+option.cormode = 0; % [0] | 2 | 4 | 6
+option.meancentering_type = 0;% [0] | 1 | 2 | 3
+option.boot_type = 'strat'; %['strat'] | 'nonstrat'
+
+result = pls_analysis(datamat_lst, num_subj_lst, num_cond, option);
+
+%% rearrange into fieldtrip structure
+
+lvdat = reshape(result.boot_result.compare_u(:,1), num_chans, num_freqs, num_time);
+%udat = reshape(result.u, num_chans, num_freqs, num_time);
+
+stat = [];
+stat.prob = lvdat;
+stat.dimord = 'chan_freq_time';
+stat.clusters = [];
+stat.clusters.prob = result.perm_result.sprob; % check for significance of LV
+stat.mask = lvdat > 3 | lvdat < -3;
+stat.cfg = option;
+stat.time = time;
+
+save(fullfile(pn.data, 'b01_taskpls_erp_avg.mat'),...
+    'stat', 'result', 'lvdat', 'lv_evt_list', 'num_chans', 'num_freqs', 'num_time')

+ 153 - 0
code/prior/b1_taskPLS_scenecat_N1_avg_plotLV1.m

@@ -0,0 +1,153 @@
+% Create an overview plot featuring the results of the multivariate PLS
+% comparing spectral changes during the stimulus period under load
+
+clear all; cla; clc;
+
+currentFile = mfilename('fullpath');
+[pathstr,~,~] = fileparts(currentFile);
+cd(fullfile(pathstr,'..'))
+rootpath = pwd;
+
+pn.data         = fullfile(rootpath, 'data', 'stats');
+pn.figures      = fullfile(rootpath, 'figures');
+pn.tools        = fullfile(rootpath, 'tools');
+    addpath(genpath(fullfile(pn.tools, '[MEG]PLS', 'MEGPLS_PIPELINE_v2.02b')))
+    addpath(fullfile(pn.tools, 'fieldtrip')); ft_defaults;
+    addpath(genpath(fullfile(pn.tools, 'RainCloudPlots')));
+    addpath(fullfile(pn.tools, 'BrewerMap'));
+    addpath(fullfile(pn.tools, 'winsor'));
+
+% set custom colormap
+cBrew = brewermap(500,'RdBu');
+cBrew = flipud(cBrew);
+colormap(cBrew)
+
+load(fullfile(pn.data, 'b01_taskpls_erp_avg.mat'),...
+    'stat', 'result', 'lvdat', 'lv_evt_list', 'num_chans', 'num_freqs', 'num_time')
+load(fullfile(rootpath, 'data','erp', ['sub-001_erp.mat']));
+elec = erp.scene_category{1}.elec;
+
+result.perm_result.sprob
+
+indLV = 1;
+
+lvdat = reshape(result.boot_result.compare_u(:,indLV), num_chans, num_freqs, num_time);
+stat.prob = lvdat;
+stat.mask = lvdat > 3 | lvdat < -3;
+
+% maskNaN = double(stat.mask);
+% maskNaN(maskNaN==0) = NaN;
+
+%% plot multivariate topographies
+
+h = figure('units','centimeters','position',[0 0 10 10]);
+set(gcf,'renderer','Painters')
+
+cfg = [];
+cfg.layout = 'biosemi64.lay';
+cfg.parameter = 'powspctrm';
+cfg.comment = 'no';
+cfg.colormap = cBrew;
+cfg.colorbar = 'EastOutside';
+
+plotData = [];
+plotData.label = elec.label; % {1 x N}
+plotData.dimord = 'chan';
+cfg.zlim = [-6 6]; 
+cfg.figure = h;
+plotData.powspctrm = squeeze(stat.mask.*stat.prob); 
+ft_topoplotER(cfg,plotData);
+cb = colorbar('location', 'EastOutside'); set(get(cb,'ylabel'),'string','Mean BSR');
+figureName = ['b01_lv1'];
+% saveas(h, fullfile(pn.figures, figureName), 'epsc');
+% saveas(h, fullfile(pn.figures, figureName), 'png');
+
+%% plot using raincloud plot
+
+groupsizes=result.num_subj_lst;
+conditions=lv_evt_list;
+conds = {'manmade'; 'natural'};
+condData = []; uData = [];
+for indGroup = 1
+    if indGroup == 1
+        relevantEntries = 1:groupsizes(1)*numel(conds);
+    elseif indGroup == 2
+        relevantEntries = groupsizes(1)*numel(conds)+1:...
+             groupsizes(1)*numel(conds)+groupsizes(2)*numel(conds);
+    end
+    for indCond = 1:numel(conds)
+        targetEntries = relevantEntries(conditions(relevantEntries)==indCond);        
+        condData{indGroup}(indCond,:) = result.vsc(targetEntries,indLV);
+        uData{indGroup}(indCond,:) = result.usc(targetEntries,indLV);
+    end
+end
+
+%% plot RainCloudPlot (within-subject centered)
+
+cBrew(1,:) = 2.*[.3 .1 .1];
+cBrew(2,:) = [.6 .6 .6];
+
+idx_outlier = cell(1); idx_standard = cell(1);
+for indGroup = 1
+    dataToPlot = uData{indGroup}';
+    % define outlier as lin. modulation that is more than three scaled median absolute deviations (MAD) away from the median
+    X = [1 1; 1 2]; b=X\dataToPlot'; IndividualSlopes = b(2,:);
+    outliers = isoutlier(IndividualSlopes, 'median');
+    idx_outlier{indGroup} = find(outliers);
+    idx_standard{indGroup} = find(outliers==0);
+end
+
+h = figure('units','centimeter','position',[0 0 25 10]);
+for indGroup = 1
+    dataToPlot = uData{indGroup}';
+    % read into cell array of the appropriate dimensions
+    data = []; data_ws = [];
+    for i = 1:2
+        for j = 1:1
+            data{i, j} = dataToPlot(:,i);
+            % individually demean for within-subject visualization
+            data_ws{i, j} = dataToPlot(:,i)-...
+                nanmean(dataToPlot(:,:),2)+...
+                repmat(nanmean(nanmean(dataToPlot(:,:),2),1),size(dataToPlot(:,:),1),1);
+            data_nooutlier{i, j} = data{i, j};
+            data_nooutlier{i, j}(idx_outlier{indGroup}) = [];
+            data_ws_nooutlier{i, j} = data_ws{i, j};
+            data_ws_nooutlier{i, j}(idx_outlier{indGroup}) = [];
+            % sort outliers to back in original data for improved plot overlap
+            data_ws{i, j} = [data_ws{i, j}(idx_standard{indGroup}); data_ws{i, j}(idx_outlier{indGroup})];
+        end
+    end
+
+    % IMPORTANT: plot individually centered estimates, stats on uncentered estimates!
+
+    subplot(1,2,indGroup);
+    set(gcf,'renderer','Painters')
+        cla;
+        cl = cBrew(indGroup,:);
+        [~, dist] = rm_raincloud_fixedSpacing(data_ws, [.8 .8 .8],1);
+        h_rc = rm_raincloud_fixedSpacing(data_ws_nooutlier, cl,1,[],[],[],dist);
+        view([90 -90]);
+        axis ij
+    box(gca,'off')
+    set(gca, 'YTickLabels', {'natural'; 'manmade'});
+    yticks = get(gca, 'ytick'); ylim([yticks(1)-(yticks(2)-yticks(1))./2, yticks(2)+(yticks(2)-yticks(1))./1.5]);
+
+    minmax = [min(min(cat(2,data_ws{:}))), max(max(cat(2,data_ws{:})))];
+    xlim(minmax+[-0.2*diff(minmax), 0.2*diff(minmax)])
+    ylabel('scene category'); xlabel({'Brainscore'; '[Individually centered]'})
+
+    % test linear effect
+    curData = [data_nooutlier{1, 1}, data_nooutlier{2, 1}];
+    X = [1 1; 1 2]; b=X\curData'; IndividualSlopes = b(2,:);
+    [~, p, ci, stats] = ttest(IndividualSlopes);
+    title(['M:', num2str(round(mean(IndividualSlopes),3)), '; p=', num2str(round(p,3))])
+end
+figureName = ['b01_rcp'];
+% saveas(h, fullfile(pn.figures, figureName), 'epsc');
+% saveas(h, fullfile(pn.figures, figureName), 'png');
+
+
+%% get channels to visualize
+
+positive = find(squeeze(stat.mask.*stat.prob)>0);
+negative = find(squeeze(stat.mask.*stat.prob)<0);

+ 181 - 0
code/prior/b1_taskPLS_scenecat_N1_plotLV1.m

@@ -0,0 +1,181 @@
+% Create an overview plot featuring the results of the multivariate PLS
+% comparing spectral changes during the stimulus period under load
+
+clear all; cla; clc;
+
+currentFile = mfilename('fullpath');
+[pathstr,~,~] = fileparts(currentFile);
+cd(fullfile(pathstr,'..'))
+rootpath = pwd;
+
+pn.data         = fullfile(rootpath, 'data', 'stats');
+pn.figures      = fullfile(rootpath, 'figures');
+pn.tools        = fullfile(rootpath, 'tools');
+    addpath(genpath(fullfile(pn.tools, '[MEG]PLS', 'MEGPLS_PIPELINE_v2.02b')))
+    addpath(fullfile(pn.tools, 'fieldtrip')); ft_defaults;
+    addpath(genpath(fullfile(pn.tools, 'RainCloudPlots')));
+    addpath(fullfile(pn.tools, 'BrewerMap'));
+    addpath(fullfile(pn.tools, 'winsor'));
+
+% set custom colormap
+cBrew = brewermap(500,'RdBu');
+cBrew = flipud(cBrew);
+colormap(cBrew)
+
+load(fullfile(pn.data, 'b01_taskpls_erp.mat'),...
+    'stat', 'result', 'lvdat', 'lv_evt_list', 'num_chans', 'num_freqs', 'num_time')
+load(fullfile(rootpath, 'data','erp', ['sub-001_erp.mat']));
+elec = erp.scene_category{1}.elec;
+
+result.perm_result.sprob
+
+indLV = 1;
+
+lvdat = reshape(result.boot_result.compare_u(:,indLV), num_chans, num_freqs, num_time);
+stat.prob = lvdat;
+stat.mask = lvdat > 3 | lvdat < -3;
+
+% maskNaN = double(stat.mask);
+% maskNaN(maskNaN==0) = NaN;
+
+%% invert solution
+
+% stat.mask = stat.mask;
+% stat.prob = stat.prob.*-1;
+% result.vsc = result.vsc.*-1;
+% result.usc = result.usc.*-1;
+
+h = figure('units','centimeter','position',[0 0 15 10]);
+set(gcf,'renderer','Painters')
+statsPlot = [];
+statsPlot = cat(1, statsPlot,squeeze(nanmax(abs(stat.prob(1:64,:,:)),[],1)));
+plot(stat.time,statsPlot, 'k')
+xlabel('Time [s from stim onset]'); ylabel('max abs BSR');
+title({'ERP changes'; ['p = ', num2str(round(result.perm_result.sprob(indLV),4))]})
+set(findall(gcf,'-property','FontSize'),'FontSize',18)
+figureName = ['b01_pls_traces'];
+saveas(h, fullfile(pn.figures, figureName), 'epsc');
+saveas(h, fullfile(pn.figures, figureName), 'png');
+
+
+h = figure('units','centimeter','position',[0 0 15 10]);
+set(gcf,'renderer','Painters')
+statsPlot = [];
+statsPlot = cat(1, statsPlot,squeeze(mean(stat.prob(1:64,:,:),1)));
+plot(stat.time,statsPlot, 'k')
+xlabel('Time [s from stim onset]'); ylabel('mean BSR');
+title({'ERP changes'; ['p = ', num2str(round(result.perm_result.sprob(indLV),4))]})
+set(findall(gcf,'-property','FontSize'),'FontSize',18)
+xlim([0 0.3])
+figureName = ['b01_pls_traces'];
+saveas(h, fullfile(pn.figures, figureName), 'epsc');
+saveas(h, fullfile(pn.figures, figureName), 'png');
+
+%% plot multivariate topographies
+
+h = figure('units','centimeters','position',[0 0 10 10]);
+set(gcf,'renderer','Painters')
+
+cfg = [];
+cfg.layout = 'biosemi64.lay';
+cfg.parameter = 'powspctrm';
+cfg.comment = 'no';
+cfg.colormap = cBrew;
+cfg.colorbar = 'EastOutside';
+
+plotData = [];
+plotData.label = elec.label(1:66); % {1 x N}
+plotData.dimord = 'chan';
+cfg.zlim = [-3 3]; 
+cfg.figure = h;
+plotData.powspctrm = squeeze(nanmean(stat.mask(:,:,stat.time >0.08 & stat.time <0.12).*...
+    stat.prob(:,:,stat.time >0.08 & stat.time <0.12),3)); 
+ft_topoplotER(cfg,plotData);
+cb = colorbar('location', 'EastOutside'); set(get(cb,'ylabel'),'string','Mean BSR');
+figureName = ['b01_lv1'];
+% saveas(h, fullfile(pn.figures, figureName), 'epsc');
+% saveas(h, fullfile(pn.figures, figureName), 'png');
+
+%% plot using raincloud plot
+
+groupsizes=result.num_subj_lst;
+conditions=lv_evt_list;
+conds = {'manmade'; 'natural'};
+condData = []; uData = [];
+for indGroup = 1
+    if indGroup == 1
+        relevantEntries = 1:groupsizes(1)*numel(conds);
+    elseif indGroup == 2
+        relevantEntries = groupsizes(1)*numel(conds)+1:...
+             groupsizes(1)*numel(conds)+groupsizes(2)*numel(conds);
+    end
+    for indCond = 1:numel(conds)
+        targetEntries = relevantEntries(conditions(relevantEntries)==indCond);        
+        condData{indGroup}(indCond,:) = result.vsc(targetEntries,indLV);
+        uData{indGroup}(indCond,:) = result.usc(targetEntries,indLV);
+    end
+end
+
+%% plot RainCloudPlot (within-subject centered)
+
+cBrew(1,:) = 2.*[.3 .1 .1];
+cBrew(2,:) = [.6 .6 .6];
+
+idx_outlier = cell(1); idx_standard = cell(1);
+for indGroup = 1
+    dataToPlot = uData{indGroup}';
+    % define outlier as lin. modulation that is more than three scaled median absolute deviations (MAD) away from the median
+    X = [1 1; 1 2]; b=X\dataToPlot'; IndividualSlopes = b(2,:);
+    outliers = isoutlier(IndividualSlopes, 'median');
+    idx_outlier{indGroup} = find(outliers);
+    idx_standard{indGroup} = find(outliers==0);
+end
+
+h = figure('units','centimeter','position',[0 0 25 10]);
+for indGroup = 1
+    dataToPlot = uData{indGroup}';
+    % read into cell array of the appropriate dimensions
+    data = []; data_ws = [];
+    for i = 1:2
+        for j = 1:1
+            data{i, j} = dataToPlot(:,i);
+            % individually demean for within-subject visualization
+            data_ws{i, j} = dataToPlot(:,i)-...
+                nanmean(dataToPlot(:,:),2)+...
+                repmat(nanmean(nanmean(dataToPlot(:,:),2),1),size(dataToPlot(:,:),1),1);
+            data_nooutlier{i, j} = data{i, j};
+            data_nooutlier{i, j}(idx_outlier{indGroup}) = [];
+            data_ws_nooutlier{i, j} = data_ws{i, j};
+            data_ws_nooutlier{i, j}(idx_outlier{indGroup}) = [];
+            % sort outliers to back in original data for improved plot overlap
+            data_ws{i, j} = [data_ws{i, j}(idx_standard{indGroup}); data_ws{i, j}(idx_outlier{indGroup})];
+        end
+    end
+
+    % IMPORTANT: plot individually centered estimates, stats on uncentered estimates!
+
+    subplot(1,2,indGroup);
+    set(gcf,'renderer','Painters')
+        cla;
+        cl = cBrew(indGroup,:);
+        [~, dist] = rm_raincloud_fixedSpacing(data_ws, [.8 .8 .8],1);
+        h_rc = rm_raincloud_fixedSpacing(data_ws_nooutlier, cl,1,[],[],[],dist);
+        view([90 -90]);
+        axis ij
+    box(gca,'off')
+    set(gca, 'YTickLabels', {'natural'; 'manmade'});
+    yticks = get(gca, 'ytick'); ylim([yticks(1)-(yticks(2)-yticks(1))./2, yticks(2)+(yticks(2)-yticks(1))./1.5]);
+
+    minmax = [min(min(cat(2,data_ws{:}))), max(max(cat(2,data_ws{:})))];
+    xlim(minmax+[-0.2*diff(minmax), 0.2*diff(minmax)])
+    ylabel('scene category'); xlabel({'Brainscore'; '[Individually centered]'})
+
+    % test linear effect
+    curData = [data_nooutlier{1, 1}, data_nooutlier{2, 1}];
+    X = [1 1; 1 2]; b=X\curData'; IndividualSlopes = b(2,:);
+    [~, p, ci, stats] = ttest(IndividualSlopes);
+    title(['M:', num2str(round(mean(IndividualSlopes),3)), '; p=', num2str(round(p,3))])
+end
+figureName = ['b01_rcp'];
+% saveas(h, fullfile(pn.figures, figureName), 'epsc');
+% saveas(h, fullfile(pn.figures, figureName), 'png');

+ 113 - 0
code/prior/b2a_taskPLS_novelty_frontal_erp.m

@@ -0,0 +1,113 @@
+% Set up EEG PLS for a task PLS using spectral power
+
+clear all; cla; clc;
+
+currentFile = mfilename('fullpath');
+[pathstr,~,~] = fileparts(currentFile);
+cd(fullfile(pathstr,'..'))
+rootpath = pwd;
+
+pn.data_eeg = fullfile(rootpath, '..', 'eegmp_preproc', 'data', 'outputs', 'eeg');
+pn.data_erp = fullfile(rootpath, 'data', 'erp');
+pn.data_erf = fullfile(rootpath, 'data', 'erf');
+pn.data = fullfile(rootpath, 'data', 'stats'); mkdir(pn.data);
+pn.tools = fullfile(rootpath, 'tools');
+    addpath(fullfile(rootpath, '..', 'eegmp_preproc', 'tools', 'fieldtrip')); ft_defaults
+    addpath(genpath(fullfile(pn.tools, '[MEG]PLS', 'MEGPLS_PIPELINE_v2.02b')))
+    addpath(fullfile(pn.tools, 'BrewerMap'));
+    addpath(fullfile(pn.tools, 'shadedErrorBar'));
+
+%% add seed for reproducibility
+
+rng(0, 'twister');
+    
+%% load event info
+
+load(fullfile(pn.data_eeg, ['sub-001_task-xxxx_eeg_art.mat']), 'events');
+
+parameter = {'scene_category'; 'old'; 'behavior'; 'subsequent_memory'};
+for ind_param = 1:numel(parameter)
+    conds.(parameter{ind_param}) = unique(events.(parameter{ind_param}));
+end
+
+%% load erp
+
+for ind_id = 1:33
+    id = sprintf('sub-%03d', ind_id); disp(id)
+    load(fullfile(pn.data_erp, [id,'_erp_bl.mat']));
+    for ind_option = 1:numel(conds.old)
+        if ind_id == 1
+             erpgroup.old.(conds.old{ind_option}) = erp_bl.old{ind_option};
+             erpgroup.old.(conds.old{ind_option}) = ...
+                 rmfield(erpgroup.old.(conds.old{ind_option}), {'avg', 'var', 'dof'});
+             erpgroup.old.(conds.old{ind_option}).dimord = 'sub_chan_time';
+        end
+        % only include time points from 300 - 500 ms
+        time = erpgroup.old.(conds.old{ind_option}).time;
+        toi = time >0.3 & time <0.5;
+        erpgroup.old.(conds.old{ind_option}).avg(ind_id,:,:) = erp_bl.old{ind_option}.avg(:,toi);
+    end
+end
+
+time = erpgroup.old.old.time(toi);
+elec = erpgroup.old.old.elec;
+channels = erpgroup.old.old.label;
+
+mergeddata = cat(4, erpgroup.old.old.avg, ...
+    erpgroup.old.new.avg);
+
+% identify frontal channels, and set everything else to zero
+idx_chans = startsWith(channels, 'F') | startsWith(channels, 'A') | startsWith(channels, 'C') & ~startsWith(channels, 'CP');
+mergeddata(:, idx_chans==0,:,:) = 0;
+
+num_chans = numel(channels);
+num_freqs = 1;
+num_time = numel(time);
+
+num_subj_lst = [33];
+num_cond = 2;
+num_grp = 1;
+
+datamat_lst = cell(num_grp); lv_evt_list = [];
+indCount_cont = 1;
+indCount = 1;
+indGroup = 1;
+for indCond = 1:num_cond
+    for indID = 1:num_subj_lst(indGroup)
+        datamat_lst{indGroup}(indCount,:) = reshape(squeeze(mergeddata(indID,:,:,indCond)), [], 1);
+        lv_evt_list(indCount_cont) = indCond;
+        indCount = indCount+1;
+        indCount_cont = indCount_cont+1;
+    end
+end
+datamat_lst{indGroup}(isnan(datamat_lst{indGroup})) = 0;
+
+%% set PLS options and run PLS
+
+option = [];
+option.method = 1; % [1] | 2 | 3 | 4 | 5 | 6
+option.num_perm = 1000; %( single non-negative integer )
+option.num_split = 0; %( single non-negative integer )
+option.num_boot = 1000; % ( single non-negative integer )
+option.cormode = 0; % [0] | 2 | 4 | 6
+option.meancentering_type = 0;% [0] | 1 | 2 | 3
+option.boot_type = 'strat'; %['strat'] | 'nonstrat'
+
+result = pls_analysis(datamat_lst, num_subj_lst, num_cond, option);
+
+%% rearrange into fieldtrip structure
+
+lvdat = reshape(result.boot_result.compare_u(:,1), num_chans, num_freqs, num_time);
+%udat = reshape(result.u, num_chans, num_freqs, num_time);
+
+stat = [];
+stat.prob = lvdat;
+stat.dimord = 'chan_freq_time';
+stat.clusters = [];
+stat.clusters.prob = result.perm_result.sprob; % check for significance of LV
+stat.mask = lvdat > 3 | lvdat < -3;
+stat.cfg = option;
+stat.time = time;
+
+save(fullfile(pn.data, 'c01_taskpls_erp.mat'),...
+    'stat', 'result', 'lvdat', 'lv_evt_list', 'num_chans', 'num_freqs', 'num_time')

+ 181 - 0
code/prior/b2a_taskPLS_novelty_frontal_erp_plotLV1.m

@@ -0,0 +1,181 @@
+% Create an overview plot featuring the results of the multivariate PLS
+% comparing spectral changes during the stimulus period under load
+
+clear all; cla; clc;
+
+currentFile = mfilename('fullpath');
+[pathstr,~,~] = fileparts(currentFile);
+cd(fullfile(pathstr,'..'))
+rootpath = pwd;
+
+pn.data         = fullfile(rootpath, 'data', 'stats');
+pn.figures      = fullfile(rootpath, 'figures');
+pn.tools        = fullfile(rootpath, 'tools');
+    addpath(genpath(fullfile(pn.tools, '[MEG]PLS', 'MEGPLS_PIPELINE_v2.02b')))
+    addpath(fullfile(pn.tools, 'fieldtrip')); ft_defaults;
+    addpath(genpath(fullfile(pn.tools, 'RainCloudPlots')));
+    addpath(fullfile(pn.tools, 'BrewerMap'));
+    addpath(fullfile(pn.tools, 'winsor'));
+
+% set custom colormap
+cBrew = brewermap(500,'RdBu');
+cBrew = flipud(cBrew);
+colormap(cBrew)
+
+load(fullfile(pn.data, 'c01_taskpls_erp.mat'),...
+    'stat', 'result', 'lvdat', 'lv_evt_list', 'num_chans', 'num_freqs', 'num_time')
+load(fullfile(rootpath, 'data','erp', ['sub-001_erp.mat']));
+elec = erp.scene_category{1}.elec;
+
+result.perm_result.sprob
+
+indLV = 1;
+
+lvdat = reshape(result.boot_result.compare_u(:,indLV), num_chans, num_freqs, num_time);
+stat.prob = lvdat;
+stat.mask = lvdat > 3 | lvdat < -3;
+
+% maskNaN = double(stat.mask);
+% maskNaN(maskNaN==0) = NaN;
+
+%% invert solution
+
+% stat.mask = stat.mask;
+% stat.prob = stat.prob.*-1;
+% result.vsc = result.vsc.*-1;
+% result.usc = result.usc.*-1;
+
+h = figure('units','centimeter','position',[0 0 15 10]);
+set(gcf,'renderer','Painters')
+statsPlot = [];
+statsPlot = cat(1, statsPlot,squeeze(nanmax(abs(stat.prob(1:64,:,:)),[],1)));
+plot(stat.time,statsPlot, 'k')
+xlabel('Time [s from stim onset]'); ylabel('max abs BSR');
+title({'ERP changes'; ['p = ', num2str(round(result.perm_result.sprob(indLV),4))]})
+set(findall(gcf,'-property','FontSize'),'FontSize',18)
+% figureName = ['b01_pls_traces'];
+% saveas(h, fullfile(pn.figures, figureName), 'epsc');
+% saveas(h, fullfile(pn.figures, figureName), 'png');
+
+
+h = figure('units','centimeter','position',[0 0 15 10]);
+set(gcf,'renderer','Painters')
+statsPlot = [];
+statsPlot = cat(1, statsPlot,squeeze(mean(stat.prob(1:64,:,:),1)));
+plot(stat.time,statsPlot, 'k')
+xlabel('Time [s from stim onset]'); ylabel('mean BSR');
+title({'ERP changes'; ['p = ', num2str(round(result.perm_result.sprob(indLV),4))]})
+set(findall(gcf,'-property','FontSize'),'FontSize',18)
+%xlim([0 0.3])
+% figureName = ['b01_pls_traces'];
+% saveas(h, fullfile(pn.figures, figureName), 'epsc');
+% saveas(h, fullfile(pn.figures, figureName), 'png');
+
+%% plot multivariate topographies
+
+h = figure('units','centimeters','position',[0 0 10 10]);
+set(gcf,'renderer','Painters')
+
+cfg = [];
+cfg.layout = 'biosemi64.lay';
+cfg.parameter = 'powspctrm';
+cfg.comment = 'no';
+cfg.colormap = cBrew;
+cfg.colorbar = 'EastOutside';
+
+plotData = [];
+plotData.label = elec.label(1:66); % {1 x N}
+plotData.dimord = 'chan';
+cfg.zlim = [-6 6]; 
+cfg.figure = h;
+plotData.powspctrm = squeeze(nanmean(stat.mask(:,:,:).*...
+    stat.prob(:,:,:),3)); 
+ft_topoplotER(cfg,plotData);
+cb = colorbar('location', 'EastOutside'); set(get(cb,'ylabel'),'string','Mean BSR');
+figureName = ['b01_lv1'];
+% saveas(h, fullfile(pn.figures, figureName), 'epsc');
+% saveas(h, fullfile(pn.figures, figureName), 'png');
+
+%% plot using raincloud plot
+
+groupsizes=result.num_subj_lst;
+conditions=lv_evt_list;
+conds = {'old'; 'new'};
+condData = []; uData = [];
+for indGroup = 1
+    if indGroup == 1
+        relevantEntries = 1:groupsizes(1)*numel(conds);
+    elseif indGroup == 2
+        relevantEntries = groupsizes(1)*numel(conds)+1:...
+             groupsizes(1)*numel(conds)+groupsizes(2)*numel(conds);
+    end
+    for indCond = 1:numel(conds)
+        targetEntries = relevantEntries(conditions(relevantEntries)==indCond);        
+        condData{indGroup}(indCond,:) = result.vsc(targetEntries,indLV);
+        uData{indGroup}(indCond,:) = result.usc(targetEntries,indLV);
+    end
+end
+
+%% plot RainCloudPlot (within-subject centered)
+
+cBrew(1,:) = 2.*[.3 .1 .1];
+cBrew(2,:) = [.6 .6 .6];
+
+idx_outlier = cell(1); idx_standard = cell(1);
+for indGroup = 1
+    dataToPlot = uData{indGroup}';
+    % define outlier as lin. modulation that is more than three scaled median absolute deviations (MAD) away from the median
+    X = [1 1; 1 2]; b=X\dataToPlot'; IndividualSlopes = b(2,:);
+    outliers = isoutlier(IndividualSlopes, 'median');
+    idx_outlier{indGroup} = find(outliers);
+    idx_standard{indGroup} = find(outliers==0);
+end
+
+h = figure('units','centimeter','position',[0 0 25 10]);
+for indGroup = 1
+    dataToPlot = uData{indGroup}';
+    % read into cell array of the appropriate dimensions
+    data = []; data_ws = [];
+    for i = 1:2
+        for j = 1:1
+            data{i, j} = dataToPlot(:,i);
+            % individually demean for within-subject visualization
+            data_ws{i, j} = dataToPlot(:,i)-...
+                nanmean(dataToPlot(:,:),2)+...
+                repmat(nanmean(nanmean(dataToPlot(:,:),2),1),size(dataToPlot(:,:),1),1);
+            data_nooutlier{i, j} = data{i, j};
+            data_nooutlier{i, j}(idx_outlier{indGroup}) = [];
+            data_ws_nooutlier{i, j} = data_ws{i, j};
+            data_ws_nooutlier{i, j}(idx_outlier{indGroup}) = [];
+            % sort outliers to back in original data for improved plot overlap
+            data_ws{i, j} = [data_ws{i, j}(idx_standard{indGroup}); data_ws{i, j}(idx_outlier{indGroup})];
+        end
+    end
+
+    % IMPORTANT: plot individually centered estimates, stats on uncentered estimates!
+
+    subplot(1,2,indGroup);
+    set(gcf,'renderer','Painters')
+        cla;
+        cl = cBrew(indGroup,:);
+        [~, dist] = rm_raincloud_fixedSpacing(data_ws, [.8 .8 .8],1);
+        h_rc = rm_raincloud_fixedSpacing(data_ws_nooutlier, cl,1,[],[],[],dist);
+        view([90 -90]);
+        axis ij
+    box(gca,'off')
+    set(gca, 'YTickLabels', {conds{2}; conds{1}});
+    yticks = get(gca, 'ytick'); ylim([yticks(1)-(yticks(2)-yticks(1))./2, yticks(2)+(yticks(2)-yticks(1))./1.5]);
+
+    minmax = [min(min(cat(2,data_ws{:}))), max(max(cat(2,data_ws{:})))];
+    xlim(minmax+[-0.2*diff(minmax), 0.2*diff(minmax)])
+    ylabel('novelty'); xlabel({'Brainscore'; '[Individually centered]'})
+
+    % test linear effect
+    curData = [data_nooutlier{1, 1}, data_nooutlier{2, 1}];
+    X = [1 1; 1 2]; b=X\curData'; IndividualSlopes = b(2,:);
+    [~, p, ci, stats] = ttest(IndividualSlopes);
+    title(['M:', num2str(round(mean(IndividualSlopes),3)), '; p=', num2str(round(p,3))])
+end
+% figureName = ['b01_rcp'];
+% saveas(h, fullfile(pn.figures, figureName), 'epsc');
+% saveas(h, fullfile(pn.figures, figureName), 'png');

+ 156 - 0
code/prior/b2a_taskPLS_novelty_frontal_erp_plot_trace.m

@@ -0,0 +1,156 @@
+
+currentFile = mfilename('fullpath');
+[pathstr,~,~] = fileparts(currentFile);
+cd(fullfile(pathstr,'..'))
+rootpath = pwd;
+
+pn.data_eeg = fullfile(rootpath, '..', 'eegmp_preproc', 'data', 'outputs', 'eeg');
+pn.data_erp = fullfile(rootpath, 'data', 'erp');
+pn.data_erf = fullfile(rootpath, 'data', 'erf');
+pn.tools = fullfile(rootpath, 'tools');
+    addpath(fullfile(rootpath, '..', 'eegmp_preproc', 'tools', 'fieldtrip')); ft_defaults
+    addpath(fullfile(pn.tools, 'BrewerMap'));
+    addpath(fullfile(pn.tools, 'shadedErrorBar'));
+    
+%% load erp
+
+for ind_id = 1:33
+    id = sprintf('sub-%03d', ind_id);
+    load(fullfile(pn.data_erp, [id,'_erp_bl.mat']));
+    for ind_option = 1:numel(conds.old)
+        if ind_id == 1
+             erpgroup.old.(conds.old{ind_option}) = erp_bl.old{ind_option};
+             erpgroup.old.(conds.old{ind_option}) = ...
+                 rmfield(erpgroup.old.(conds.old{ind_option}), {'avg', 'var', 'dof'});
+             erpgroup.old.(conds.old{ind_option}).dimord = 'sub_chan_time';
+        end
+        erpgroup.old.(conds.old{ind_option}).avg(ind_id,:,:) = erp_bl.old{ind_option}.avg;
+    end
+end
+
+time = erpgroup.old.old.time;
+elec = erpgroup.old.old.elec;
+channels = erpgroup.old.old.label;
+
+%idx_chans = find(ismember(channels, {'O1', 'Oz', 'O2'}));
+%idx_chans = find(ismember(channels, {'PO7', 'PO8'}));
+%idx_chans = find(ismember(channels, {'Pz', 'CPz', 'P1'}));
+
+mergeddata = cat(4, erpgroup.old.old.avg, ...
+    erpgroup.old.new.avg);
+
+%% plot ERP topography
+
+% set custom colormap
+cBrew = brewermap(500,'RdBu');
+cBrew = flipud(cBrew);
+colormap(cBrew)
+
+h = figure('units','centimeters','position',[0 0 10 10]);
+set(gcf,'renderer','Painters')
+
+cfg = [];
+cfg.layout = 'biosemi64.lay';
+cfg.parameter = 'powspctrm';
+cfg.comment = 'no';
+cfg.colormap = cBrew;
+cfg.colorbar = 'EastOutside';
+
+plotData = [];
+plotData.label = elec.label; % {1 x N}
+plotData.dimord = 'chan';
+plotData.powspctrm = squeeze(nanmean(nanmean(nanmean(mergeddata(:,:,time>=0.3& time <=0.5,1:2),3),1),4))'; 
+
+cfg.zlim = [-14 14]*10^-4; 
+cfg.figure = h;
+ft_topoplotER(cfg,plotData);
+cb = colorbar('location', 'EastOutside'); set(get(cb,'ylabel'),'string','Amplitude');
+% figureName = ['xxx'];
+% saveas(h, fullfile(pn.figures, figureName), 'epsc');
+% saveas(h, fullfile(pn.figures, figureName), 'png');
+
+%% visualize frontal ERP
+
+idx_chans = [38];
+
+% avg across channels and conditions
+condAvg = squeeze(nanmean(nanmean(mergeddata(:,idx_chans,:,1:2),2),4));
+
+h = figure('units','centimeters','position',[0 0 10 8]);
+cla; hold on;
+% highlight relevant phase in background
+patches.timeVec = [0.3 0.5];
+patches.colorVec = [1 .95 .8];
+for indP = 1:size(patches.timeVec,2)-1
+    YLim = [-8 2]*10^-4;
+    p = patch([patches.timeVec(indP) patches.timeVec(indP+1) patches.timeVec(indP+1) patches.timeVec(indP)], ...
+                [YLim(1) YLim(1)  YLim(2), YLim(2)], patches.colorVec(indP,:));
+    p.EdgeColor = 'none';
+end
+% new value = old value ? subject average + grand average
+curData = squeeze(nanmean(mergeddata(:,idx_chans,:,1),2));
+curData = curData-condAvg+repmat(nanmean(condAvg,1),size(condAvg,1),1);
+standError = nanstd(curData,1)./sqrt(size(curData,1));
+l1 = shadedErrorBar(time,nanmean(curData,1),standError, 'lineprops', {'color', 'k','linewidth', 2}, 'patchSaturation', .1);
+curData = squeeze(nanmean(mergeddata(:,idx_chans,:,2),2));
+curData = curData-condAvg+repmat(nanmean(condAvg,1),size(condAvg,1),1);
+standError = nanstd(curData,1)./sqrt(size(curData,1));
+l2 = shadedErrorBar(time,nanmean(curData,1),standError, 'lineprops', {'color', 'r','linewidth', 2}, 'patchSaturation', .1);
+% ax = gca; ax.YDir = 'reverse';
+legend([l1.mainLine, l2.mainLine],{'old', 'new'}, ...
+    'location', 'southwest'); legend('boxoff')
+xlabel('Time (s) from stim onset')
+xlim([-.05 .6]); %ylim([-.03 .18])
+ylabel({'ERP';'(microVolts)'});
+xlabel({'Time (s)'});    
+set(findall(gcf,'-property','FontSize'),'FontSize',14)
+
+%% plot difference
+
+idx_chans = [38];
+
+h = figure('units','centimeters','position',[0 0 10 8]);
+cla; hold on;
+% highlight relevant phase in background
+patches.timeVec = [0.3 0.5];
+patches.colorVec = [1 .95 .8];
+for indP = 1:size(patches.timeVec,2)-1
+    YLim = [-10 5]*10^-5;
+    p = patch([patches.timeVec(indP) patches.timeVec(indP+1) patches.timeVec(indP+1) patches.timeVec(indP)], ...
+                [YLim(1) YLim(1)  YLim(2), YLim(2)], patches.colorVec(indP,:));
+    p.EdgeColor = 'none';
+end
+% new value = old value ? subject average + grand average
+curData = squeeze(mergeddata(:,idx_chans,:,2)-mergeddata(:,idx_chans,:,1));
+standError = nanstd(curData,1)./sqrt(size(curData,1));
+l1 = shadedErrorBar(time,nanmean(curData,1),standError, 'lineprops', {'color', 'k','linewidth', 2}, 'patchSaturation', .1);
+legend([l1.mainLine],{'new-old'}, ...
+    'location', 'southwest'); legend('boxoff')
+xlabel('Time (s) from stim onset')
+xlim([-.05 .6]); %ylim([-.03 .18])
+ylabel({'ERP';'(microVolts)'});
+xlabel({'Time (s)'});    
+set(findall(gcf,'-property','FontSize'),'FontSize',14)
+
+
+%% plot difference between conditions
+
+h = figure('units','centimeters','position',[0 0 10 10]);
+set(gcf,'renderer','Painters')
+
+cfg = [];
+cfg.layout = 'biosemi64.lay';
+cfg.parameter = 'powspctrm';
+cfg.comment = 'no';
+cfg.colormap = cBrew;
+cfg.colorbar = 'EastOutside';
+
+plotData = [];
+plotData.label = elec.label; % {1 x N}
+plotData.dimord = 'chan';
+oldminnew = mergeddata(:,:,:,1)-mergeddata(:,:,:,2);
+plotData.powspctrm = squeeze(nanmean(nanmean(oldminnew(:,:,time>=.3 & time <=.5),3),1))'; 
+
+cfg.figure = h;
+ft_topoplotER(cfg,plotData);
+cb = colorbar('location', 'EastOutside'); set(get(cb,'ylabel'),'string','Amplitude');

+ 106 - 0
code/prior/b2b_taskPLS_novelty_frontal_theta.m

@@ -0,0 +1,106 @@
+% Set up EEG PLS for a task PLS using spectral power
+
+clear all; cla; clc;
+
+currentFile = mfilename('fullpath');
+[pathstr,~,~] = fileparts(currentFile);
+cd(fullfile(pathstr,'..'))
+rootpath = pwd;
+
+pn.data_eeg = fullfile(rootpath, '..', 'eegmp_preproc', 'data', 'outputs', 'eeg');
+pn.data_erp = fullfile(rootpath, 'data', 'erp');
+pn.data_erf = fullfile(rootpath, 'data', 'erf');
+pn.data = fullfile(rootpath, 'data', 'stats'); mkdir(pn.data);
+pn.tools = fullfile(rootpath, 'tools');
+    addpath(fullfile(rootpath, '..', 'eegmp_preproc', 'tools', 'fieldtrip')); ft_defaults
+    addpath(genpath(fullfile(pn.tools, '[MEG]PLS', 'MEGPLS_PIPELINE_v2.02b')))
+    addpath(fullfile(pn.tools, 'BrewerMap'));
+    addpath(fullfile(pn.tools, 'shadedErrorBar'));
+
+%% add seed for reproducibility
+
+rng(0, 'twister');
+
+%% load erp
+
+for ind_id = 1:33
+    id = sprintf('sub-%03d', ind_id); disp(id)
+    load(fullfile(pn.data_erf, [id,'_erf.mat']));
+    for ind_option = 1:numel(conds.old)
+        if ind_id == 1
+             erpgroup.old.(conds.old{ind_option}) = erf.old{ind_option};
+             erpgroup.old.(conds.old{ind_option}) = ...
+                 rmfield(erpgroup.old.(conds.old{ind_option}), {'powspctrm'});
+             erpgroup.old.(conds.old{ind_option}).dimord = 'sub_chan_freq_time';
+             freq = erpgroup.old.(conds.old{ind_option}).freq;
+             idx_freq = freq >2 & freq <8;
+        end
+        % only include time points from 300 - 500 ms
+        time = erf.old{ind_option}.time;
+        toi = time >0.3 & time <0.5;        
+        erpgroup.old.(conds.old{ind_option}).avg(ind_id,:,:,:) = erf.old{ind_option}.powspctrm(:,idx_freq,toi);
+    end
+end
+
+time = erpgroup.old.old.time(toi);
+freq = erpgroup.old.old.freq(idx_freq);
+channels = erpgroup.old.old.label;
+
+mergeddata = cat(5, erpgroup.old.old.avg, erpgroup.old.new.avg);
+
+% identify frontal channels, and set everything else to zero
+idx_chans = startsWith(channels, 'F') | startsWith(channels, 'A') | startsWith(channels, 'C') & ~startsWith(channels, 'CP');
+mergeddata(:, idx_chans==0,:,:,:) = 0;
+
+num_chans = numel(channels);
+num_freqs = numel(freq);
+num_time = numel(time);
+
+num_subj_lst = [33];
+num_cond = 2;
+num_grp = 1;
+
+datamat_lst = cell(num_grp); lv_evt_list = [];
+indCount_cont = 1;
+indCount = 1;
+indGroup = 1;
+for indCond = 1:num_cond
+    for indID = 1:num_subj_lst(indGroup)
+        datamat_lst{indGroup}(indCount,:) = reshape(squeeze(mergeddata(indID,:,:,:,indCond)), [], 1);
+        lv_evt_list(indCount_cont) = indCond;
+        indCount = indCount+1;
+        indCount_cont = indCount_cont+1;
+    end
+end
+datamat_lst{indGroup}(isnan(datamat_lst{indGroup})) = 0;
+
+%% set PLS options and run PLS
+
+option = [];
+option.method = 1; % [1] | 2 | 3 | 4 | 5 | 6
+option.num_perm = 1000; %( single non-negative integer )
+option.num_split = 0; %( single non-negative integer )
+option.num_boot = 1000; % ( single non-negative integer )
+option.cormode = 0; % [0] | 2 | 4 | 6
+option.meancentering_type = 0;% [0] | 1 | 2 | 3
+option.boot_type = 'strat'; %['strat'] | 'nonstrat'
+
+result = pls_analysis(datamat_lst, num_subj_lst, num_cond, option);
+
+%% rearrange into fieldtrip structure
+
+lvdat = reshape(result.boot_result.compare_u(:,1), num_chans, num_freqs, num_time);
+%udat = reshape(result.u, num_chans, num_freqs, num_time);
+
+stat = [];
+stat.prob = lvdat;
+stat.dimord = 'chan_freq_time';
+stat.clusters = [];
+stat.clusters.prob = result.perm_result.sprob; % check for significance of LV
+stat.mask = lvdat > 3 | lvdat < -3;
+stat.cfg = option;
+stat.freq = freq;
+stat.time = time;
+
+save(fullfile(pn.data, 'b2b_taskpls_theta.mat'),...
+    'stat', 'result', 'lvdat', 'lv_evt_list', 'num_chans', 'num_freqs', 'num_time')

+ 189 - 0
code/prior/b2b_taskPLS_novelty_frontal_theta_plotLV1.m

@@ -0,0 +1,189 @@
+% Create an overview plot featuring the results of the multivariate PLS
+% comparing spectral changes during the stimulus period under load
+
+clear all; cla; clc;
+
+currentFile = mfilename('fullpath');
+[pathstr,~,~] = fileparts(currentFile);
+cd(fullfile(pathstr,'..'))
+rootpath = pwd;
+
+pn.data         = fullfile(rootpath, 'data', 'stats');
+pn.figures      = fullfile(rootpath, 'figures');
+pn.tools        = fullfile(rootpath, 'tools');
+    addpath(genpath(fullfile(pn.tools, '[MEG]PLS', 'MEGPLS_PIPELINE_v2.02b')))
+    addpath(fullfile(pn.tools, 'fieldtrip')); ft_defaults;
+    addpath(genpath(fullfile(pn.tools, 'RainCloudPlots')));
+    addpath(fullfile(pn.tools, 'BrewerMap'));
+    addpath(fullfile(pn.tools, 'winsor'));
+
+% set custom colormap
+cBrew = brewermap(500,'RdBu');
+cBrew = flipud(cBrew);
+colormap(cBrew)
+
+load(fullfile(pn.data, 'b2b_taskpls_theta.mat'),...
+    'stat', 'result', 'lvdat', 'lv_evt_list', 'num_chans', 'num_freqs', 'num_time')
+load(fullfile(rootpath, 'data','erp', ['sub-001_erp.mat']));
+elec = erp.scene_category{1}.elec;
+
+result.perm_result.sprob
+
+indLV = 1;
+
+lvdat = reshape(result.boot_result.compare_u(:,indLV), num_chans, num_freqs, num_time);
+stat.prob = lvdat;
+stat.mask = lvdat > 3 | lvdat < -3;
+
+% maskNaN = double(stat.mask);
+% maskNaN(maskNaN==0) = NaN;
+
+%% invert solution
+
+stat.mask = stat.mask;
+stat.prob = stat.prob.*-1;
+result.vsc = result.vsc.*-1;
+result.usc = result.usc.*-1;
+
+% h = figure('units','centimeter','position',[0 0 15 10]);
+% set(gcf,'renderer','Painters')
+% statsPlot = [];
+% statsPlot = cat(1, statsPlot,squeeze(nanmax(abs(stat.prob(1:64,:,:)),[],1)));
+% plot(stat.time,statsPlot, 'k')
+% xlabel('Time [s from stim onset]'); ylabel('max abs BSR');
+% title({'ERP changes'; ['p = ', num2str(round(result.perm_result.sprob(indLV),4))]})
+% set(findall(gcf,'-property','FontSize'),'FontSize',18)
+% figureName = ['b01_pls_traces'];
+% saveas(h, fullfile(pn.figures, figureName), 'epsc');
+% saveas(h, fullfile(pn.figures, figureName), 'png');
+
+% h = figure('units','centimeter','position',[0 0 15 10]);
+% set(gcf,'renderer','Painters')
+% statsPlot = [];
+% statsPlot = cat(1, statsPlot,squeeze(mean(stat.prob(1:64,:,:),1)));
+% plot(stat.time,statsPlot, 'k')
+% xlabel('Time [s from stim onset]'); ylabel('mean BSR');
+% title({'ERP changes'; ['p = ', num2str(round(result.perm_result.sprob(indLV),4))]})
+% set(findall(gcf,'-property','FontSize'),'FontSize',18)
+% %xlim([0 0.3])
+% % figureName = ['b01_pls_traces'];
+% % saveas(h, fullfile(pn.figures, figureName), 'epsc');
+% % saveas(h, fullfile(pn.figures, figureName), 'png');
+
+%% plot multivariate topographies
+
+h = figure('units','centimeters','position',[0 0 10 10]);
+set(gcf,'renderer','Painters')
+
+cfg = [];
+cfg.layout = 'biosemi64.lay';
+cfg.parameter = 'powspctrm';
+cfg.comment = 'no';
+cfg.colormap = cBrew;
+cfg.colorbar = 'EastOutside';
+
+plotData = [];
+plotData.label = elec.label; % {1 x N}
+plotData.dimord = 'chan';
+cfg.zlim = [-6 6]; 
+cfg.figure = h;
+plotData.powspctrm = squeeze(nanmax(nanmax(stat.mask(:,:,:).*...
+    stat.prob(:,:,:),[],3),[],2));
+
+[~, sortind] = sort(plotData.powspctrm, 'descend');
+cfg.marker = 'off'; 
+cfg.highlight = 'yes';
+cfg.highlightchannel = plotData.label(sortind(1:3));
+cfg.highlightcolor = [0 0 0];
+cfg.highlightsymbol = '.';
+cfg.highlightsize = 15;
+
+ft_topoplotER(cfg,plotData);
+cb = colorbar('location', 'EastOutside'); set(get(cb,'ylabel'),'string','Max BSR');
+figureName = ['b01_lv1'];
+% saveas(h, fullfile(pn.figures, figureName), 'epsc');
+% saveas(h, fullfile(pn.figures, figureName), 'png');
+
+%% plot using raincloud plot
+
+groupsizes=result.num_subj_lst;
+conditions=lv_evt_list;
+conds = {'old'; 'new'};
+condData = []; uData = [];
+for indGroup = 1
+    if indGroup == 1
+        relevantEntries = 1:groupsizes(1)*numel(conds);
+    elseif indGroup == 2
+        relevantEntries = groupsizes(1)*numel(conds)+1:...
+             groupsizes(1)*numel(conds)+groupsizes(2)*numel(conds);
+    end
+    for indCond = 1:numel(conds)
+        targetEntries = relevantEntries(conditions(relevantEntries)==indCond);        
+        condData{indGroup}(indCond,:) = -1.*result.vsc(targetEntries,indLV);
+        uData{indGroup}(indCond,:) = -1.*result.usc(targetEntries,indLV);
+    end
+end
+
+%% plot RainCloudPlot (within-subject centered)
+
+cBrew(1,:) = 2.*[.3 .1 .1];
+cBrew(2,:) = [.6 .6 .6];
+
+idx_outlier = cell(1); idx_standard = cell(1);
+for indGroup = 1
+    dataToPlot = uData{indGroup}';
+    % define outlier as lin. modulation that is more than three scaled median absolute deviations (MAD) away from the median
+    X = [1 1; 1 2]; b=X\dataToPlot'; IndividualSlopes = b(2,:);
+    outliers = isoutlier(IndividualSlopes, 'median');
+    idx_outlier{indGroup} = find(outliers);
+    idx_standard{indGroup} = find(outliers==0);
+end
+
+h = figure('units','centimeter','position',[0 0 25 10]);
+for indGroup = 1
+    dataToPlot = uData{indGroup}';
+    % read into cell array of the appropriate dimensions
+    data = []; data_ws = [];
+    for i = 1:2
+        for j = 1:1
+            data{i, j} = dataToPlot(:,i);
+            % individually demean for within-subject visualization
+            data_ws{i, j} = dataToPlot(:,i)-...
+                nanmean(dataToPlot(:,:),2)+...
+                repmat(nanmean(nanmean(dataToPlot(:,:),2),1),size(dataToPlot(:,:),1),1);
+            data_nooutlier{i, j} = data{i, j};
+            data_nooutlier{i, j}(idx_outlier{indGroup}) = [];
+            data_ws_nooutlier{i, j} = data_ws{i, j};
+            data_ws_nooutlier{i, j}(idx_outlier{indGroup}) = [];
+            % sort outliers to back in original data for improved plot overlap
+            data_ws{i, j} = [data_ws{i, j}(idx_standard{indGroup}); data_ws{i, j}(idx_outlier{indGroup})];
+        end
+    end
+
+    % IMPORTANT: plot individually centered estimates, stats on uncentered estimates!
+
+    subplot(1,2,indGroup);
+    set(gcf,'renderer','Painters')
+        cla;
+        cl = cBrew(indGroup,:);
+        [~, dist] = rm_raincloud_fixedSpacing(data_ws, [.8 .8 .8],1);
+        h_rc = rm_raincloud_fixedSpacing(data_ws_nooutlier, cl,1,[],[],[],dist);
+        view([90 -90]);
+        axis ij
+    box(gca,'off')
+    set(gca, 'YTickLabels', {conds{2}; conds{1}});
+    yticks = get(gca, 'ytick'); ylim([yticks(1)-(yticks(2)-yticks(1))./2, yticks(2)+(yticks(2)-yticks(1))./1.5]);
+
+    minmax = [min(min(cat(2,data_ws{:}))), max(max(cat(2,data_ws{:})))];
+    xlim(minmax+[-0.2*diff(minmax), 0.2*diff(minmax)])
+    ylabel('novelty'); xlabel({'Brainscore'; '[Individually centered]'})
+
+    % test linear effect
+    curData = [data_nooutlier{1, 1}, data_nooutlier{2, 1}];
+    X = [1 1; 1 2]; b=X\curData'; IndividualSlopes = b(2,:);
+    [~, p, ci, stats] = ttest(IndividualSlopes);
+    title(['M:', num2str(round(mean(IndividualSlopes),3)), '; p=', num2str(round(p,3))])
+end
+% figureName = ['b01_rcp'];
+% saveas(h, fullfile(pn.figures, figureName), 'epsc');
+% saveas(h, fullfile(pn.figures, figureName), 'png');

+ 116 - 0
code/prior/b2c_taskPLS_novelty_posterior_alpha.m

@@ -0,0 +1,116 @@
+% Set up EEG PLS for a task PLS using spectral power
+
+clear all; cla; clc;
+
+currentFile = mfilename('fullpath');
+[pathstr,~,~] = fileparts(currentFile);
+cd(fullfile(pathstr,'..'))
+rootpath = pwd;
+
+pn.data_eeg = fullfile(rootpath, '..', 'eegmp_preproc', 'data', 'outputs', 'eeg');
+pn.data_erp = fullfile(rootpath, 'data', 'erp');
+pn.data_erf = fullfile(rootpath, 'data', 'erf');
+pn.data = fullfile(rootpath, 'data', 'stats'); mkdir(pn.data);
+pn.tools = fullfile(rootpath, 'tools');
+    addpath(fullfile(rootpath, '..', 'eegmp_preproc', 'tools', 'fieldtrip')); ft_defaults
+    addpath(genpath(fullfile(pn.tools, '[MEG]PLS', 'MEGPLS_PIPELINE_v2.02b')))
+    addpath(fullfile(pn.tools, 'BrewerMap'));
+    addpath(fullfile(pn.tools, 'shadedErrorBar'));
+
+%% add seed for reproducibility
+
+rng(0, 'twister');
+    
+%% load event info
+
+load(fullfile(pn.data_eeg, ['sub-001_task-xxxx_eeg_art.mat']), 'events');
+
+parameter = {'scene_category'; 'old'; 'behavior'; 'subsequent_memory'};
+for ind_param = 1:numel(parameter)
+    conds.(parameter{ind_param}) = unique(events.(parameter{ind_param}));
+end
+
+%% load erp
+
+for ind_id = 1:33
+    id = sprintf('sub-%03d', ind_id); disp(id)
+    load(fullfile(pn.data_erf, [id,'_erf.mat']));
+    for ind_option = 1:numel(conds.old)
+        if ind_id == 1
+             erpgroup.old.(conds.old{ind_option}) = erf.old{ind_option};
+             erpgroup.old.(conds.old{ind_option}) = ...
+                 rmfield(erpgroup.old.(conds.old{ind_option}), {'powspctrm'});
+             erpgroup.old.(conds.old{ind_option}).dimord = 'sub_chan_freq_time';
+             freq = erpgroup.old.(conds.old{ind_option}).freq;
+             idx_freq = freq >7 & freq <13;
+        end
+        % only include time points from 300 - 500 ms
+        time = erf.old{ind_option}.time;
+        toi = time >0.3 & time <0.5;        
+        erpgroup.old.(conds.old{ind_option}).avg(ind_id,:,:,:) = erf.old{ind_option}.powspctrm(:,idx_freq,toi);
+    end
+end
+
+time = erpgroup.old.old.time(toi);
+freq = erpgroup.old.old.freq(idx_freq);
+channels = erpgroup.old.old.label;
+
+mergeddata = cat(5, erpgroup.old.old.avg, ...
+    erpgroup.old.new.avg);
+
+% identify parieto-occipital channels, and set everything else to zero
+idx_chans = startsWith(channels, 'P') | startsWith(channels, 'O');
+mergeddata(:, idx_chans==0,:,:,:) = 0;
+
+num_chans = numel(channels);
+num_freqs = numel(freq);
+num_time = numel(time);
+
+num_subj_lst = [33];
+num_cond = 2;
+num_grp = 1;
+
+datamat_lst = cell(num_grp); lv_evt_list = [];
+indCount_cont = 1;
+indCount = 1;
+indGroup = 1;
+for indCond = 1:num_cond
+    for indID = 1:num_subj_lst(indGroup)
+        datamat_lst{indGroup}(indCount,:) = reshape(squeeze(mergeddata(indID,:,:,:,indCond)), [], 1);
+        lv_evt_list(indCount_cont) = indCond;
+        indCount = indCount+1;
+        indCount_cont = indCount_cont+1;
+    end
+end
+datamat_lst{indGroup}(isnan(datamat_lst{indGroup})) = 0;
+
+%% set PLS options and run PLS
+
+option = [];
+option.method = 1; % [1] | 2 | 3 | 4 | 5 | 6
+option.num_perm = 1000; %( single non-negative integer )
+option.num_split = 0; %( single non-negative integer )
+option.num_boot = 1000; % ( single non-negative integer )
+option.cormode = 0; % [0] | 2 | 4 | 6
+option.meancentering_type = 0;% [0] | 1 | 2 | 3
+option.boot_type = 'strat'; %['strat'] | 'nonstrat'
+
+result = pls_analysis(datamat_lst, num_subj_lst, num_cond, option);
+
+%% rearrange into fieldtrip structure
+
+lvdat = reshape(result.boot_result.compare_u(:,1), num_chans, num_freqs, num_time);
+%udat = reshape(result.u, num_chans, num_freqs, num_time);
+
+stat = [];
+stat.prob = lvdat;
+stat.dimord = 'chan_freq_time';
+stat.clusters = [];
+stat.clusters.prob = result.perm_result.sprob; % check for significance of LV
+stat.mask = lvdat > 3 | lvdat < -3;
+stat.cfg = option;
+stat.freq = freq;
+stat.time = time;
+
+save(fullfile(pn.data, 'b2c_taskpls_alpha.mat'),...
+    'stat', 'result', 'lvdat', 'lv_evt_list', 'num_chans', 'num_freqs', 'num_time')

+ 179 - 0
code/prior/b2c_taskPLS_novelty_posterior_alpha_LV1.m

@@ -0,0 +1,179 @@
+% Create an overview plot featuring the results of the multivariate PLS
+% comparing spectral changes during the stimulus period under load
+
+clear all; cla; clc;
+
+currentFile = mfilename('fullpath');
+[pathstr,~,~] = fileparts(currentFile);
+cd(fullfile(pathstr,'..'))
+rootpath = pwd;
+
+pn.data         = fullfile(rootpath, 'data', 'stats');
+pn.figures      = fullfile(rootpath, 'figures');
+pn.tools        = fullfile(rootpath, 'tools');
+    addpath(genpath(fullfile(pn.tools, '[MEG]PLS', 'MEGPLS_PIPELINE_v2.02b')))
+    addpath(fullfile(pn.tools, 'fieldtrip')); ft_defaults;
+    addpath(genpath(fullfile(pn.tools, 'RainCloudPlots')));
+    addpath(fullfile(pn.tools, 'BrewerMap'));
+    addpath(fullfile(pn.tools, 'winsor'));
+
+% set custom colormap
+cBrew = brewermap(500,'RdBu');
+cBrew = flipud(cBrew);
+colormap(cBrew)
+
+load(fullfile(pn.data, 'b2c_taskpls_alpha.mat'),...
+    'stat', 'result', 'lvdat', 'lv_evt_list', 'num_chans', 'num_freqs', 'num_time')
+load(fullfile(rootpath, 'data','erp', ['sub-001_erp.mat']));
+elec = erp.scene_category{1}.elec;
+
+result.perm_result.sprob
+
+indLV = 1;
+
+lvdat = reshape(result.boot_result.compare_u(:,indLV), num_chans, num_freqs, num_time);
+stat.prob = lvdat;
+stat.mask = lvdat > 3 | lvdat < -3;
+
+% maskNaN = double(stat.mask);
+% maskNaN(maskNaN==0) = NaN;
+
+%% invert solution
+
+% stat.mask = stat.mask;
+% stat.prob = stat.prob.*-1;
+% result.vsc = result.vsc.*-1;
+% result.usc = result.usc.*-1;
+
+h = figure('units','centimeter','position',[0 0 15 10]);
+set(gcf,'renderer','Painters')
+statsPlot = [];
+statsPlot = cat(1, statsPlot,squeeze(nanmax(abs(stat.prob(1:64,:,:)),[],1)));
+plot(stat.time,statsPlot, 'k')
+xlabel('Time [s from stim onset]'); ylabel('max abs BSR');
+title({'ERP changes'; ['p = ', num2str(round(result.perm_result.sprob(indLV),4))]})
+set(findall(gcf,'-property','FontSize'),'FontSize',18)
+% figureName = ['b01_pls_traces'];
+% saveas(h, fullfile(pn.figures, figureName), 'epsc');
+% saveas(h, fullfile(pn.figures, figureName), 'png');
+
+
+h = figure('units','centimeter','position',[0 0 15 10]);
+set(gcf,'renderer','Painters')
+statsPlot = [];
+statsPlot = cat(1, statsPlot,squeeze(mean(stat.prob(1:64,:,:),1)));
+plot(stat.time,statsPlot, 'k')
+xlabel('Time [s from stim onset]'); ylabel('mean BSR');
+title({'ERP changes'; ['p = ', num2str(round(result.perm_result.sprob(indLV),4))]})
+set(findall(gcf,'-property','FontSize'),'FontSize',18)
+%xlim([0 0.3])
+% figureName = ['b01_pls_traces'];
+% saveas(h, fullfile(pn.figures, figureName), 'epsc');
+% saveas(h, fullfile(pn.figures, figureName), 'png');
+
+%% plot multivariate topographies
+
+h = figure('units','centimeters','position',[0 0 10 10]);
+set(gcf,'renderer','Painters')
+
+cfg = [];
+cfg.layout = 'biosemi64.lay';
+cfg.parameter = 'powspctrm';
+cfg.comment = 'no';
+cfg.colormap = cBrew;
+cfg.colorbar = 'EastOutside';
+
+plotData = [];
+plotData.label = elec.label; % {1 x N}
+plotData.dimord = 'chan';
+cfg.zlim = [-2 2]; 
+cfg.figure = h;
+plotData.powspctrm = squeeze(nanmean(stat.mask(:,:,:).*...
+    stat.prob(:,:,:),3)); 
+ft_topoplotER(cfg,plotData);
+cb = colorbar('location', 'EastOutside'); set(get(cb,'ylabel'),'string','Mean BSR');
+figureName = ['b01_lv1'];
+% saveas(h, fullfile(pn.figures, figureName), 'epsc');
+% saveas(h, fullfile(pn.figures, figureName), 'png');
+
+%% plot RainCloudPlot (within-subject centered)
+
+groupsizes=result.num_subj_lst;
+conditions=lv_evt_list;
+conds = {'manmade'; 'natural'};
+condData = []; uData = [];
+for indGroup = 1
+    if indGroup == 1
+        relevantEntries = 1:groupsizes(1)*numel(conds);
+    elseif indGroup == 2
+        relevantEntries = groupsizes(1)*numel(conds)+1:...
+             groupsizes(1)*numel(conds)+groupsizes(2)*numel(conds);
+    end
+    for indCond = 1:numel(conds)
+        targetEntries = relevantEntries(conditions(relevantEntries)==indCond);        
+        condData{indGroup}(indCond,:) = result.vsc(targetEntries,indLV);
+        uData{indGroup}(indCond,:) = result.usc(targetEntries,indLV);
+    end
+end
+
+cBrew(1,:) = 2.*[.3 .1 .1];
+cBrew(2,:) = [.6 .6 .6];
+
+idx_outlier = cell(1); idx_standard = cell(1);
+for indGroup = 1
+    dataToPlot = uData{indGroup}';
+    % define outlier as lin. modulation that is more than three scaled median absolute deviations (MAD) away from the median
+    X = [1 1; 1 2]; b=X\dataToPlot'; IndividualSlopes = b(2,:);
+    outliers = isoutlier(IndividualSlopes, 'median');
+    idx_outlier{indGroup} = find(outliers);
+    idx_standard{indGroup} = find(outliers==0);
+end
+
+h = figure('units','centimeter','position',[0 0 25 10]);
+for indGroup = 1
+    dataToPlot = uData{indGroup}';
+    % read into cell array of the appropriate dimensions
+    data = []; data_ws = [];
+    for i = 1:2
+        for j = 1:1
+            data{i, j} = dataToPlot(:,i);
+            % individually demean for within-subject visualization
+            data_ws{i, j} = dataToPlot(:,i)-...
+                nanmean(dataToPlot(:,:),2)+...
+                repmat(nanmean(nanmean(dataToPlot(:,:),2),1),size(dataToPlot(:,:),1),1);
+            data_nooutlier{i, j} = data{i, j};
+            data_nooutlier{i, j}(idx_outlier{indGroup}) = [];
+            data_ws_nooutlier{i, j} = data_ws{i, j};
+            data_ws_nooutlier{i, j}(idx_outlier{indGroup}) = [];
+            % sort outliers to back in original data for improved plot overlap
+            data_ws{i, j} = [data_ws{i, j}(idx_standard{indGroup}); data_ws{i, j}(idx_outlier{indGroup})];
+        end
+    end
+
+    % IMPORTANT: plot individually centered estimates, stats on uncentered estimates!
+
+    subplot(1,2,indGroup);
+    set(gcf,'renderer','Painters')
+        cla;
+        cl = cBrew(indGroup,:);
+        [~, dist] = rm_raincloud_fixedSpacing(data_ws, [.8 .8 .8],1);
+        h_rc = rm_raincloud_fixedSpacing(data_ws_nooutlier, cl,1,[],[],[],dist);
+        view([90 -90]);
+        axis ij
+    box(gca,'off')
+    set(gca, 'YTickLabels', {'natural'; 'manmade'});
+    yticks = get(gca, 'ytick'); ylim([yticks(1)-(yticks(2)-yticks(1))./2, yticks(2)+(yticks(2)-yticks(1))./1.5]);
+
+    minmax = [min(min(cat(2,data_ws{:}))), max(max(cat(2,data_ws{:})))];
+    xlim(minmax+[-0.2*diff(minmax), 0.2*diff(minmax)])
+    ylabel('scene category'); xlabel({'Brainscore'; '[Individually centered]'})
+
+    % test linear effect
+    curData = [data_nooutlier{1, 1}, data_nooutlier{2, 1}];
+    X = [1 1; 1 2]; b=X\curData'; IndividualSlopes = b(2,:);
+    [~, p, ci, stats] = ttest(IndividualSlopes);
+    title(['M:', num2str(round(mean(IndividualSlopes),3)), '; p=', num2str(round(p,3))])
+end
+% figureName = ['b01_rcp'];
+% saveas(h, fullfile(pn.figures, figureName), 'epsc');
+% saveas(h, fullfile(pn.figures, figureName), 'png');

+ 127 - 0
code/prior/b2x_novelty_plot_theta_alpha.m

@@ -0,0 +1,127 @@
+clear all; cla; clc;
+
+currentFile = mfilename('fullpath');
+[pathstr,~,~] = fileparts(currentFile);
+cd(fullfile(pathstr,'..'))
+rootpath = pwd;
+
+pn.data_eeg = fullfile(rootpath, '..', 'eegmp_preproc', 'data', 'outputs', 'eeg');
+pn.data_erp = fullfile(rootpath, 'data', 'erp');
+pn.data_erf = fullfile(rootpath, 'data', 'erf');
+pn.data = fullfile(rootpath, 'data', 'stats'); mkdir(pn.data);
+pn.tools = fullfile(rootpath, 'tools');
+    addpath(fullfile(rootpath, '..', 'eegmp_preproc', 'tools', 'fieldtrip')); ft_defaults
+    addpath(genpath(fullfile(pn.tools, '[MEG]PLS', 'MEGPLS_PIPELINE_v2.02b')))
+    addpath(fullfile(pn.tools, 'BrewerMap'));
+    addpath(fullfile(pn.tools, 'shadedErrorBar'));
+
+%% add seed for reproducibility
+
+rng(0, 'twister');
+
+%% load erp
+
+for ind_id = 1:33
+    id = sprintf('sub-%03d', ind_id); disp(id)
+    load(fullfile(pn.data_erf, [id,'_erf.mat']));
+    for ind_option = 1:numel(conds.old)
+        if ind_id == 1
+             erpgroup.old.(conds.old{ind_option}) = erf.old{ind_option};
+             erpgroup.old.(conds.old{ind_option}) = ...
+                 rmfield(erpgroup.old.(conds.old{ind_option}), {'powspctrm'});
+             erpgroup.old.(conds.old{ind_option}).dimord = 'sub_chan_freq_time';
+             freq = erpgroup.old.(conds.old{ind_option}).freq;
+        end
+        idx_freq_t = freq >2 & freq <8;
+        thetagroup.old.(conds.old{ind_option}).avg(ind_id,:,:,:) = squeeze(nanmean(erf.old{ind_option}.powspctrm(:,idx_freq_t,:),2));
+        idx_freq_a = freq >7 & freq <13;
+        alphagroup.old.(conds.old{ind_option}).avg(ind_id,:,:,:) = squeeze(nanmean(erf.old{ind_option}.powspctrm(:,idx_freq_a,:),2));
+    end
+end
+
+time = erpgroup.old.old.time;
+channels = erpgroup.old.old.label;
+
+% identify frontal channels
+%idx_chans_t = startsWith(channels, 'F') | startsWith(channels, 'A') | startsWith(channels, 'C') & ~startsWith(channels, 'CP');
+
+% identify parieto-occipital channels
+idx_chans_a = startsWith(channels, 'P') | startsWith(channels, 'O');
+
+%% visualize for frontal theta
+
+mergeddata = cat(4, thetagroup.old.old.avg, thetagroup.old.new.avg);
+
+%figure; imagesc(squeeze(nanmean(thetagroup.old.new.avg-thetagroup.old.old.avg,1)))
+
+idx_chans = [33,38,47];
+condAvg = squeeze(nanmean(nanmean(mergeddata(:,idx_chans,:,1:2),2),4));
+
+h = figure('units','centimeters','position',[0 0 10 8]);
+cla; hold on;
+% highlight relevant phase in background
+patches.timeVec = [0.3 0.5];
+patches.colorVec = [1 .95 .8];
+for indP = 1:size(patches.timeVec,2)-1
+    YLim = [-5 -4.8];
+    p = patch([patches.timeVec(indP) patches.timeVec(indP+1) patches.timeVec(indP+1) patches.timeVec(indP)], ...
+                [YLim(1) YLim(1)  YLim(2), YLim(2)], patches.colorVec(indP,:));
+    p.EdgeColor = 'none';
+end
+% new value = old value ? subject average + grand average
+curData = squeeze(nanmean(mergeddata(:,idx_chans,:,1),2));
+curData = curData-condAvg+repmat(nanmean(condAvg,1),size(condAvg,1),1);
+standError = nanstd(curData,1)./sqrt(size(curData,1));
+l1 = shadedErrorBar(time,nanmean(curData,1),standError, 'lineprops', ...
+    {'color', 'k','linewidth', 2}, 'patchSaturation', .1);
+curData = squeeze(nanmean(mergeddata(:,idx_chans,:,2),2));
+curData = curData-condAvg+repmat(nanmean(condAvg,1),size(condAvg,1),1);
+standError = nanstd(curData,1)./sqrt(size(curData,1));
+l2 = shadedErrorBar(time,nanmean(curData,1),standError, 'lineprops', ...
+    {'color', 'r','linewidth', 2}, 'patchSaturation', .1);
+xlabel('Time (s) from stim onset')
+legend([l1.mainLine, l2.mainLine],{'old', 'new'}, ...
+    'location', 'southeast'); legend('boxoff')
+xlim([-.5 1.5]); ylim(YLim)
+%xlim([-.05 .3]);
+ylabel({'theta power';'(log10)'});
+xlabel({'Time (s)'});    
+set(findall(gcf,'-property','FontSize'),'FontSize',12)
+
+%% visualize for posterior alpha
+
+mergeddata = cat(4, alphagroup.old.old.avg, alphagroup.old.new.avg);
+
+idx_chans = idx_chans_a;
+condAvg = squeeze(nanmean(nanmean(mergeddata(:,idx_chans,:,1:2),2),4));
+
+h = figure('units','centimeters','position',[0 0 10 8]);
+cla; hold on;
+% highlight relevant phase in background
+patches.timeVec = [0.3 0.5];
+patches.colorVec = [1 .95 .8];
+for indP = 1:size(patches.timeVec,2)-1
+    YLim = [-5.2 -4.5];
+    p = patch([patches.timeVec(indP) patches.timeVec(indP+1) patches.timeVec(indP+1) patches.timeVec(indP)], ...
+                [YLim(1) YLim(1)  YLim(2), YLim(2)], patches.colorVec(indP,:));
+    p.EdgeColor = 'none';
+end
+% new value = old value ? subject average + grand average
+curData = squeeze(nanmean(mergeddata(:,idx_chans,:,1),2));
+curData = curData-condAvg+repmat(nanmean(condAvg,1),size(condAvg,1),1);
+standError = nanstd(curData,1)./sqrt(size(curData,1));
+l1 = shadedErrorBar(time,nanmean(curData,1),standError, 'lineprops', ...
+    {'color', 'k','linewidth', 3}, 'patchSaturation', .1);
+curData = squeeze(nanmean(mergeddata(:,idx_chans,:,2),2));
+curData = curData-condAvg+repmat(nanmean(condAvg,1),size(condAvg,1),1);
+standError = nanstd(curData,1)./sqrt(size(curData,1));
+l2 = shadedErrorBar(time,nanmean(curData,1),standError, 'lineprops', ...
+    {'color', 'r','linewidth', 3}, 'patchSaturation', .1);
+xlabel('Time (s) from stim onset')
+legend([l1.mainLine, l2.mainLine],{'old', 'new'}, 'location', 'northeast'); legend('boxoff')
+xlim([-.5 1.5]); ylim(YLim)
+%xlim([-.05 .3]);
+ylabel({'alpha power';'(log10)'});
+xlabel({'Time (s)'});    
+set(findall(gcf,'-property','FontSize'),'FontSize',15)
+

+ 106 - 0
code/prior/b3a_taskPLS_recognition_erp.m

@@ -0,0 +1,106 @@
+% Set up EEG PLS for a task PLS using spectral power
+
+clear all; cla; clc;
+
+currentFile = mfilename('fullpath');
+[pathstr,~,~] = fileparts(currentFile);
+cd(fullfile(pathstr,'..'))
+rootpath = pwd;
+
+pn.data_eeg = fullfile(rootpath, '..', 'eegmp_preproc', 'data', 'outputs', 'eeg');
+pn.data_erp = fullfile(rootpath, 'data', 'erp');
+pn.data_erf = fullfile(rootpath, 'data', 'erf');
+pn.data = fullfile(rootpath, 'data', 'stats'); mkdir(pn.data);
+pn.tools = fullfile(rootpath, 'tools');
+    addpath(fullfile(rootpath, '..', 'eegmp_preproc', 'tools', 'fieldtrip')); ft_defaults
+    addpath(genpath(fullfile(pn.tools, '[MEG]PLS', 'MEGPLS_PIPELINE_v2.02b')))
+    addpath(fullfile(pn.tools, 'BrewerMap'));
+    addpath(fullfile(pn.tools, 'shadedErrorBar'));
+
+%% add seed for reproducibility
+
+rng(0, 'twister');
+    
+%% load event info
+
+load(fullfile(pn.data_eeg, ['sub-001_task-xxxx_eeg_art.mat']), 'events');
+
+parameter = {'scene_category'; 'old'; 'behavior'; 'subsequent_memory'};
+for ind_param = 1:numel(parameter)
+    conds.(parameter{ind_param}) = unique(events.(parameter{ind_param}));
+end
+
+%% load erp_bl
+
+for ind_id = 1:33
+    id = sprintf('sub-%03d', ind_id); disp(id)
+    load(fullfile(pn.data_erp, [id,'_erp_bl.mat']));
+    for ind_option = 1:4%numel(conds.behavior)
+        if ind_id == 1
+             erpgroup.behavior.(conds.behavior{ind_option}) = erp_bl.behavior{ind_option};
+             erpgroup.behavior.(conds.behavior{ind_option}) = ...
+                 rmfield(erpgroup.behavior.(conds.behavior{ind_option}), {'avg', 'var', 'dof'});
+             erpgroup.behavior.(conds.behavior{ind_option}).dimord = 'sub_chan_time';
+        end
+        erpgroup.behavior.(conds.behavior{ind_option}).avg(ind_id,:,:) = erp_bl.behavior{ind_option}.avg;
+    end
+end
+
+time = erpgroup.behavior.hit.time;
+elec = erpgroup.behavior.hit.elec;
+channels = erpgroup.behavior.hit.label;
+
+mergeddata = cat(4, erpgroup.behavior.hit.avg, ...
+    erpgroup.behavior.miss.avg);
+
+num_chans = numel(channels);
+num_freqs = 1;
+num_time = numel(time);
+
+num_subj_lst = [33];
+num_cond = 2;
+num_grp = 1;
+
+datamat_lst = cell(num_grp); lv_evt_list = [];
+indCount_cont = 1;
+indCount = 1;
+indGroup = 1;
+for indCond = 1:num_cond
+    for indID = 1:num_subj_lst(indGroup)
+        datamat_lst{indGroup}(indCount,:) = reshape(squeeze(mergeddata(indID,:,:,indCond)), [], 1);
+        lv_evt_list(indCount_cont) = indCond;
+        indCount = indCount+1;
+        indCount_cont = indCount_cont+1;
+    end
+end
+datamat_lst{indGroup}(isnan(datamat_lst{indGroup})) = 0;
+
+%% set PLS options and run PLS
+
+option = [];
+option.method = 1; % [1] | 2 | 3 | 4 | 5 | 6
+option.num_perm = 1000; %( single non-negative integer )
+option.num_split = 0; %( single non-negative integer )
+option.num_boot = 1000; % ( single non-negative integer )
+option.cormode = 0; % [0] | 2 | 4 | 6
+option.meancentering_type = 0;% [0] | 1 | 2 | 3
+option.boot_type = 'strat'; %['strat'] | 'nonstrat'
+
+result = pls_analysis(datamat_lst, num_subj_lst, num_cond, option);
+
+%% rearrange into fieldtrip structure
+
+lvdat = reshape(result.boot_result.compare_u(:,1), num_chans, num_freqs, num_time);
+%udat = reshape(result.u, num_chans, num_freqs, num_time);
+
+stat = [];
+stat.prob = lvdat;
+stat.dimord = 'chan_freq_time';
+stat.clusters = [];
+stat.clusters.prob = result.perm_result.sprob; % check for significance of LV
+stat.mask = lvdat > 3 | lvdat < -3;
+stat.cfg = option;
+stat.time = time;
+
+save(fullfile(pn.data, 'd01_taskpls_erp.mat'),...
+    'stat', 'result', 'lvdat', 'lv_evt_list', 'num_chans', 'num_freqs', 'num_time')

+ 176 - 0
code/prior/b3a_taskPLS_recognition_erp_LV1.m

@@ -0,0 +1,176 @@
+% Create an overview plot featuring the results of the multivariate PLS
+% comparing spectral changes during the stimulus period under load
+
+clear all; cla; clc;
+
+currentFile = mfilename('fullpath');
+[pathstr,~,~] = fileparts(currentFile);
+cd(fullfile(pathstr,'..'))
+rootpath = pwd;
+
+pn.data         = fullfile(rootpath, 'data', 'stats');
+pn.figures      = fullfile(rootpath, 'figures');
+pn.tools        = fullfile(rootpath, 'tools');
+    addpath(genpath(fullfile(pn.tools, '[MEG]PLS', 'MEGPLS_PIPELINE_v2.02b')))
+    addpath(fullfile(pn.tools, 'fieldtrip')); ft_defaults;
+    addpath(genpath(fullfile(pn.tools, 'RainCloudPlots')));
+    addpath(fullfile(pn.tools, 'BrewerMap'));
+    addpath(fullfile(pn.tools, 'winsor'));
+
+% set custom colormap
+cBrew = brewermap(500,'RdBu');
+cBrew = flipud(cBrew);
+colormap(cBrew)
+
+load(fullfile(pn.data, 'd01_taskpls_erp.mat'),...
+    'stat', 'result', 'lvdat', 'lv_evt_list', 'num_chans', 'num_freqs', 'num_time')
+load(fullfile(rootpath, 'data','erp', ['sub-001_erp.mat']));
+elec = erp.scene_category{1}.elec;
+
+result.perm_result.sprob
+
+indLV = 1;
+
+lvdat = reshape(result.boot_result.compare_u(:,indLV), num_chans, num_freqs, num_time);
+stat.prob = lvdat;
+stat.mask = lvdat > 3 | lvdat < -3;
+
+% maskNaN = double(stat.mask);
+% maskNaN(maskNaN==0) = NaN;
+
+%% invert solution
+
+stat.mask = stat.mask;
+stat.prob = stat.prob.*-1;
+result.vsc = result.vsc.*-1;
+result.usc = result.usc.*-1;
+
+h = figure('units','centimeter','position',[0 0 15 10]);
+set(gcf,'renderer','Painters')
+statsPlot = [];
+statsPlot = cat(1, statsPlot,squeeze(nanmax(abs(stat.prob(1:64,:,:)),[],1)));
+plot(stat.time,statsPlot, 'k')
+xlabel('Time [s from stim onset]'); ylabel('max abs BSR');
+title({'ERP changes'; ['p = ', num2str(round(result.perm_result.sprob(indLV),4))]})
+set(findall(gcf,'-property','FontSize'),'FontSize',18)
+% figureName = ['b01_pls_traces'];
+% saveas(h, fullfile(pn.figures, figureName), 'epsc');
+% saveas(h, fullfile(pn.figures, figureName), 'png');
+
+
+h = figure('units','centimeter','position',[0 0 15 10]);
+set(gcf,'renderer','Painters')
+statsPlot = [];
+statsPlot = cat(1, statsPlot,squeeze(mean(stat.prob(1:64,:,:),1)));
+plot(stat.time,statsPlot, 'k')
+xlabel('Time [s from stim onset]'); ylabel('mean BSR');
+title({'ERP changes'; ['p = ', num2str(round(result.perm_result.sprob(indLV),4))]})
+set(findall(gcf,'-property','FontSize'),'FontSize',18)
+%xlim([0 0.3])
+% figureName = ['b01_pls_traces'];
+% saveas(h, fullfile(pn.figures, figureName), 'epsc');
+% saveas(h, fullfile(pn.figures, figureName), 'png');
+
+%% plot multivariate topographies
+
+h = figure('units','centimeters','position',[0 0 10 10]);
+set(gcf,'renderer','Painters')
+
+cfg = [];
+cfg.layout = 'biosemi64.lay';
+cfg.parameter = 'powspctrm';
+cfg.comment = 'no';
+cfg.colormap = cBrew;
+cfg.colorbar = 'EastOutside';
+
+plotData = [];
+plotData.label = elec.label; % {1 x N}
+plotData.dimord = 'chan';
+cfg.zlim = [-1 1]; 
+cfg.figure = h;
+plotData.powspctrm = squeeze(nanmean(stat.mask(:,:,:).*...
+    stat.prob(:,:,:),3)); 
+ft_topoplotER(cfg,plotData);
+cb = colorbar('location', 'EastOutside'); set(get(cb,'ylabel'),'string','Mean BSR');
+figureName = ['b01_lv1'];
+% saveas(h, fullfile(pn.figures, figureName), 'epsc');
+% saveas(h, fullfile(pn.figures, figureName), 'png');
+
+%% plot using raincloud plot
+
+groupsizes=result.num_subj_lst;
+conditions=lv_evt_list;
+conds = {'hit'; 'miss'};
+condData = []; uData = [];
+for indGroup = 1
+    if indGroup == 1
+        relevantEntries = 1:groupsizes(1)*numel(conds);
+    elseif indGroup == 2
+        relevantEntries = groupsizes(1)*numel(conds)+1:...
+             groupsizes(1)*numel(conds)+groupsizes(2)*numel(conds);
+    end
+    for indCond = 1:numel(conds)
+        targetEntries = relevantEntries(conditions(relevantEntries)==indCond);        
+        condData{indGroup}(indCond,:) = -1.*result.vsc(targetEntries,indLV);
+        uData{indGroup}(indCond,:) = -1.*result.usc(targetEntries,indLV);
+    end
+end
+
+cBrew(1,:) = 2.*[.3 .1 .1];
+cBrew(2,:) = [.6 .6 .6];
+
+idx_outlier = cell(1); idx_standard = cell(1);
+for indGroup = 1
+    dataToPlot = uData{indGroup}';
+    % define outlier as lin. modulation that is more than three scaled median absolute deviations (MAD) away from the median
+    X = [1 1; 1 2]; b=X\dataToPlot'; IndividualSlopes = b(2,:);
+    outliers = isoutlier(IndividualSlopes, 'median');
+    idx_outlier{indGroup} = find(outliers);
+    idx_standard{indGroup} = find(outliers==0);
+end
+
+h = figure('units','centimeter','position',[0 0 25 10]);
+for indGroup = 1
+    dataToPlot = uData{indGroup}';
+    % read into cell array of the appropriate dimensions
+    data = []; data_ws = [];
+    for i = 1:2
+        for j = 1:1
+            data{i, j} = dataToPlot(:,i);
+            % individually demean for within-subject visualization
+            data_ws{i, j} = dataToPlot(:,i)-...
+                nanmean(dataToPlot(:,:),2)+...
+                repmat(nanmean(nanmean(dataToPlot(:,:),2),1),size(dataToPlot(:,:),1),1);
+            data_nooutlier{i, j} = data{i, j};
+            data_nooutlier{i, j}(idx_outlier{indGroup}) = [];
+            data_ws_nooutlier{i, j} = data_ws{i, j};
+            data_ws_nooutlier{i, j}(idx_outlier{indGroup}) = [];
+            % sort outliers to back in original data for improved plot overlap
+            data_ws{i, j} = [data_ws{i, j}(idx_standard{indGroup}); data_ws{i, j}(idx_outlier{indGroup})];
+        end
+    end
+
+    % IMPORTANT: plot individually centered estimates, stats on uncentered estimates!
+
+    subplot(1,2,indGroup);
+    set(gcf,'renderer','Painters')
+        cla;
+        cl = cBrew(indGroup,:);
+        [~, dist] = rm_raincloud_fixedSpacing(data_ws, [.8 .8 .8],1);
+        h_rc = rm_raincloud_fixedSpacing(data_ws_nooutlier, cl,1,[],[],[],dist);
+        view([90 -90]);
+        axis ij
+    box(gca,'off')
+    set(gca, 'YTickLabels', {conds{2}; conds{1}});
+    yticks = get(gca, 'ytick'); ylim([yticks(1)-(yticks(2)-yticks(1))./2, yticks(2)+(yticks(2)-yticks(1))./1.5]);
+
+    minmax = [min(min(cat(2,data_ws{:}))), max(max(cat(2,data_ws{:})))];
+    xlim(minmax+[-0.2*diff(minmax), 0.2*diff(minmax)])
+    ylabel('scene category'); xlabel({'Brainscore'; '[Individually centered]'})
+
+    % test linear effect
+    curData = [data_nooutlier{1, 1}, data_nooutlier{2, 1}];
+    X = [1 1; 1 2]; b=X\curData'; IndividualSlopes = b(2,:);
+    [~, p, ci, stats] = ttest(IndividualSlopes);
+    title(['M:', num2str(round(mean(IndividualSlopes),3)), '; p=', num2str(round(p,3))])
+end

+ 107 - 0
code/prior/b3b_taskPLS_recognition_erf.m

@@ -0,0 +1,107 @@
+% Set up EEG PLS for a task PLS using spectral power
+
+clear all; cla; clc;
+
+currentFile = mfilename('fullpath');
+[pathstr,~,~] = fileparts(currentFile);
+cd(fullfile(pathstr,'..'))
+rootpath = pwd;
+
+pn.data_eeg = fullfile(rootpath, '..', 'eegmp_preproc', 'data', 'outputs', 'eeg');
+pn.data_erp = fullfile(rootpath, 'data', 'erp');
+pn.data_erf = fullfile(rootpath, 'data', 'erf');
+pn.data = fullfile(rootpath, 'data', 'stats'); mkdir(pn.data);
+pn.tools = fullfile(rootpath, 'tools');
+    addpath(fullfile(rootpath, '..', 'eegmp_preproc', 'tools', 'fieldtrip')); ft_defaults
+    addpath(genpath(fullfile(pn.tools, '[MEG]PLS', 'MEGPLS_PIPELINE_v2.02b')))
+    addpath(fullfile(pn.tools, 'BrewerMap'));
+    addpath(fullfile(pn.tools, 'shadedErrorBar'));
+
+%% add seed for reproducibility
+
+rng(0, 'twister');
+    
+%% load event info
+
+load(fullfile(pn.data_eeg, ['sub-001_task-xxxx_eeg_art.mat']), 'events');
+
+parameter = {'scene_category'; 'old'; 'behavior'; 'subsequent_memory'};
+for ind_param = 1:numel(parameter)
+    conds.(parameter{ind_param}) = unique(events.(parameter{ind_param}));
+end
+
+%% load erp
+
+for ind_id = 1:33
+    id = sprintf('sub-%03d', ind_id); disp(id)
+    load(fullfile(pn.data_erf, [id,'_erf.mat']));
+    for ind_option = 1:4%numel(conds.behavior)
+        if ind_id == 1
+             erpgroup.behavior.(conds.behavior{ind_option}) = erf.behavior{ind_option};
+             erpgroup.behavior.(conds.behavior{ind_option}) = ...
+                 rmfield(erpgroup.behavior.(conds.behavior{ind_option}), {'powspctrm'});
+             erpgroup.behavior.(conds.behavior{ind_option}).dimord = 'sub_chan_freq_time';
+        end
+        erpgroup.behavior.(conds.behavior{ind_option}).avg(ind_id,:,:,:) = erf.behavior{ind_option}.powspctrm;
+    end
+end
+
+time = erpgroup.behavior.hit.time;
+freq = erpgroup.behavior.hit.freq;
+channels = erpgroup.behavior.hit.label;
+
+mergeddata = cat(5, erpgroup.behavior.hit.avg, ...
+    erpgroup.behavior.miss.avg);
+
+num_chans = numel(channels);
+num_freqs = numel(freq);
+num_time = numel(time);
+
+num_subj_lst = [33];
+num_cond = 2;
+num_grp = 1;
+
+datamat_lst = cell(num_grp); lv_evt_list = [];
+indCount_cont = 1;
+indCount = 1;
+indGroup = 1;
+for indCond = 1:num_cond
+    for indID = 1:num_subj_lst(indGroup)
+        datamat_lst{indGroup}(indCount,:) = reshape(squeeze(mergeddata(indID,:,:,:,indCond)), [], 1);
+        lv_evt_list(indCount_cont) = indCond;
+        indCount = indCount+1;
+        indCount_cont = indCount_cont+1;
+    end
+end
+datamat_lst{indGroup}(isnan(datamat_lst{indGroup})) = 0;
+
+%% set PLS options and run PLS
+
+option = [];
+option.method = 1; % [1] | 2 | 3 | 4 | 5 | 6
+option.num_perm = 1000; %( single non-negative integer )
+option.num_split = 0; %( single non-negative integer )
+option.num_boot = 1000; % ( single non-negative integer )
+option.cormode = 0; % [0] | 2 | 4 | 6
+option.meancentering_type = 0;% [0] | 1 | 2 | 3
+option.boot_type = 'strat'; %['strat'] | 'nonstrat'
+
+result = pls_analysis(datamat_lst, num_subj_lst, num_cond, option);
+
+%% rearrange into fieldtrip structure
+
+lvdat = reshape(result.boot_result.compare_u(:,1), num_chans, num_freqs, num_time);
+%udat = reshape(result.u, num_chans, num_freqs, num_time);
+
+stat = [];
+stat.prob = lvdat;
+stat.dimord = 'chan_freq_time';
+stat.clusters = [];
+stat.clusters.prob = result.perm_result.sprob; % check for significance of LV
+stat.mask = lvdat > 3 | lvdat < -3;
+stat.cfg = option;
+stat.freq = freq;
+stat.time = time;
+
+save(fullfile(pn.data, 'b3b_taskpls_erf.mat'),...
+    'stat', 'result', 'lvdat', 'lv_evt_list', 'num_chans', 'num_freqs', 'num_time')

+ 165 - 0
code/prior/b3b_taskPLS_recognition_erf_LV1.m

@@ -0,0 +1,165 @@
+% Create an overview plot featuring the results of the multivariate PLS
+% comparing spectral changes during the stimulus period under load
+
+clear all; cla; clc;
+
+currentFile = mfilename('fullpath');
+[pathstr,~,~] = fileparts(currentFile);
+cd(fullfile(pathstr,'..'))
+rootpath = pwd;
+
+pn.data         = fullfile(rootpath, 'data', 'stats');
+pn.figures      = fullfile(rootpath, 'figures');
+pn.tools        = fullfile(rootpath, 'tools');
+    addpath(genpath(fullfile(pn.tools, '[MEG]PLS', 'MEGPLS_PIPELINE_v2.02b')))
+    addpath(fullfile(pn.tools, 'fieldtrip')); ft_defaults;
+    addpath(genpath(fullfile(pn.tools, 'RainCloudPlots')));
+    addpath(fullfile(pn.tools, 'BrewerMap'));
+    addpath(fullfile(pn.tools, 'winsor'));
+
+% set custom colormap
+cBrew = brewermap(500,'RdBu');
+cBrew = flipud(cBrew);
+colormap(cBrew)
+
+load(fullfile(pn.data, 'b3b_taskpls_erf.mat'),...
+    'stat', 'result', 'lvdat', 'lv_evt_list', 'num_chans', 'num_freqs', 'num_time')
+load(fullfile(rootpath, 'data','erp', ['sub-001_erp.mat']));
+elec = erp.scene_category{1}.elec;
+
+result.perm_result.sprob
+
+indLV = 1;
+
+lvdat = reshape(result.boot_result.compare_u(:,indLV), num_chans, num_freqs, num_time);
+stat.prob = lvdat;
+stat.mask = lvdat > 3 | lvdat < -3;
+
+% maskNaN = double(stat.mask);
+% maskNaN(maskNaN==0) = NaN;
+
+%% invert solution
+
+% stat.mask = stat.mask;
+% stat.prob = stat.prob.*-1;
+% result.vsc = result.vsc.*-1;
+% result.usc = result.usc.*-1;
+
+h = figure('units','centimeter','position',[0 0 15 10]);
+set(gcf,'renderer','Painters')
+statsPlot = [];
+statsPlot = cat(1, statsPlot,squeeze(nanmax(abs(stat.prob(1:64,:,:)),[],1)));
+imagesc(stat.time,[],statsPlot, [-8 8])
+xlabel('Time [s from stim onset]'); ylabel('max abs BSR');
+title({'ERF changes'; ['p = ', num2str(round(result.perm_result.sprob(indLV),4))]})
+set(findall(gcf,'-property','FontSize'),'FontSize',18)
+colorbar;
+colormap(cBrew)
+
+% figureName = ['b01_pls_traces'];
+% saveas(h, fullfile(pn.figures, figureName), 'epsc');
+% saveas(h, fullfile(pn.figures, figureName), 'png');
+
+%% plot multivariate topographies
+
+h = figure('units','centimeters','position',[0 0 10 10]);
+set(gcf,'renderer','Painters')
+
+cfg = [];
+cfg.layout = 'biosemi64.lay';
+cfg.parameter = 'powspctrm';
+cfg.comment = 'no';
+cfg.colormap = cBrew;
+cfg.colorbar = 'EastOutside';
+
+plotData = [];
+plotData.label = elec.label; % {1 x N}
+plotData.dimord = 'chan';
+cfg.zlim = [-1 1]; 
+cfg.figure = h;
+plotData.powspctrm = squeeze(nanmean(nanmean(stat.mask(:,:,:).*...
+    stat.prob(:,:,:),3),2)); 
+ft_topoplotER(cfg,plotData);
+cb = colorbar('location', 'EastOutside'); set(get(cb,'ylabel'),'string','Mean BSR');
+figureName = ['b01_lv1'];
+% saveas(h, fullfile(pn.figures, figureName), 'epsc');
+% saveas(h, fullfile(pn.figures, figureName), 'png');
+
+%% plot using raincloud plot
+
+groupsizes=result.num_subj_lst;
+conditions=lv_evt_list;
+conds = {'hit'; 'miss'};
+condData = []; uData = [];
+for indGroup = 1
+    if indGroup == 1
+        relevantEntries = 1:groupsizes(1)*numel(conds);
+    elseif indGroup == 2
+        relevantEntries = groupsizes(1)*numel(conds)+1:...
+             groupsizes(1)*numel(conds)+groupsizes(2)*numel(conds);
+    end
+    for indCond = 1:numel(conds)
+        targetEntries = relevantEntries(conditions(relevantEntries)==indCond);        
+        condData{indGroup}(indCond,:) = result.vsc(targetEntries,indLV);
+        uData{indGroup}(indCond,:) = result.usc(targetEntries,indLV);
+    end
+end
+
+cBrew(1,:) = 2.*[.3 .1 .1];
+cBrew(2,:) = [.6 .6 .6];
+
+idx_outlier = cell(1); idx_standard = cell(1);
+for indGroup = 1
+    dataToPlot = uData{indGroup}';
+    % define outlier as lin. modulation that is more than three scaled median absolute deviations (MAD) away from the median
+    X = [1 1; 1 2]; b=X\dataToPlot'; IndividualSlopes = b(2,:);
+    outliers = isoutlier(IndividualSlopes, 'median');
+    idx_outlier{indGroup} = find(outliers);
+    idx_standard{indGroup} = find(outliers==0);
+end
+
+h = figure('units','centimeter','position',[0 0 25 10]);
+for indGroup = 1
+    dataToPlot = uData{indGroup}';
+    % read into cell array of the appropriate dimensions
+    data = []; data_ws = [];
+    for i = 1:2
+        for j = 1:1
+            data{i, j} = dataToPlot(:,i);
+            % individually demean for within-subject visualization
+            data_ws{i, j} = dataToPlot(:,i)-...
+                nanmean(dataToPlot(:,:),2)+...
+                repmat(nanmean(nanmean(dataToPlot(:,:),2),1),size(dataToPlot(:,:),1),1);
+            data_nooutlier{i, j} = data{i, j};
+            data_nooutlier{i, j}(idx_outlier{indGroup}) = [];
+            data_ws_nooutlier{i, j} = data_ws{i, j};
+            data_ws_nooutlier{i, j}(idx_outlier{indGroup}) = [];
+            % sort outliers to back in original data for improved plot overlap
+            data_ws{i, j} = [data_ws{i, j}(idx_standard{indGroup}); data_ws{i, j}(idx_outlier{indGroup})];
+        end
+    end
+
+    % IMPORTANT: plot individually centered estimates, stats on uncentered estimates!
+
+    subplot(1,2,indGroup);
+    set(gcf,'renderer','Painters')
+        cla;
+        cl = cBrew(indGroup,:);
+        [~, dist] = rm_raincloud_fixedSpacing(data_ws, [.8 .8 .8],1);
+        h_rc = rm_raincloud_fixedSpacing(data_ws_nooutlier, cl,1,[],[],[],dist);
+        view([90 -90]);
+        axis ij
+    box(gca,'off')
+    set(gca, 'YTickLabels', {conds{2}; conds{1}});
+    yticks = get(gca, 'ytick'); ylim([yticks(1)-(yticks(2)-yticks(1))./2, yticks(2)+(yticks(2)-yticks(1))./1.5]);
+
+    minmax = [min(min(cat(2,data_ws{:}))), max(max(cat(2,data_ws{:})))];
+    xlim(minmax+[-0.2*diff(minmax), 0.2*diff(minmax)])
+    ylabel('scene category'); xlabel({'Brainscore'; '[Individually centered]'})
+
+    % test linear effect
+    curData = [data_nooutlier{1, 1}, data_nooutlier{2, 1}];
+    X = [1 1; 1 2]; b=X\curData'; IndividualSlopes = b(2,:);
+    [~, p, ci, stats] = ttest(IndividualSlopes);
+    title(['M:', num2str(round(mean(IndividualSlopes),3)), '; p=', num2str(round(p,3))])
+end

+ 106 - 0
code/prior/b4a_taskPLS_memory_erp.m

@@ -0,0 +1,106 @@
+% Set up EEG PLS for a task PLS using spectral power
+
+clear all; cla; clc;
+
+currentFile = mfilename('fullpath');
+[pathstr,~,~] = fileparts(currentFile);
+cd(fullfile(pathstr,'..'))
+rootpath = pwd;
+
+pn.data_eeg = fullfile(rootpath, '..', 'eegmp_preproc', 'data', 'outputs', 'eeg');
+pn.data_erp = fullfile(rootpath, 'data', 'erp');
+pn.data_erf = fullfile(rootpath, 'data', 'erf');
+pn.data = fullfile(rootpath, 'data', 'stats'); mkdir(pn.data);
+pn.tools = fullfile(rootpath, 'tools');
+    addpath(fullfile(rootpath, '..', 'eegmp_preproc', 'tools', 'fieldtrip')); ft_defaults
+    addpath(genpath(fullfile(pn.tools, '[MEG]PLS', 'MEGPLS_PIPELINE_v2.02b')))
+    addpath(fullfile(pn.tools, 'BrewerMap'));
+    addpath(fullfile(pn.tools, 'shadedErrorBar'));
+
+%% add seed for reproducibility
+
+rng(0, 'twister');
+    
+%% load event info
+
+load(fullfile(pn.data_eeg, ['sub-001_task-xxxx_eeg_art.mat']), 'events');
+
+parameter = {'scene_category'; 'old'; 'behavior'; 'subsequent_memory'};
+for ind_param = 1:numel(parameter)
+    conds.(parameter{ind_param}) = unique(events.(parameter{ind_param}));
+end
+
+%% load erp_bl
+
+for ind_id = 1:33
+    id = sprintf('sub-%03d', ind_id); disp(id)
+    load(fullfile(pn.data_erp, [id,'_erp_bl.mat']));
+    for ind_option = 2:3
+        if ind_id == 1
+             erpgroup.subsequent_memory.(conds.subsequent_memory{ind_option}) = erp_bl.subsequent_memory{ind_option};
+             erpgroup.subsequent_memory.(conds.subsequent_memory{ind_option}) = ...
+                 rmfield(erpgroup.subsequent_memory.(conds.subsequent_memory{ind_option}), {'avg', 'var', 'dof'});
+             erpgroup.subsequent_memory.(conds.subsequent_memory{ind_option}).dimord = 'sub_chan_time';
+        end
+        erpgroup.subsequent_memory.(conds.subsequent_memory{ind_option}).avg(ind_id,:,:) = erp_bl.subsequent_memory{ind_option}.avg;
+    end
+end
+
+time = erpgroup.subsequent_memory.subsequent_remembered.time;
+elec = erpgroup.subsequent_memory.subsequent_remembered.elec;
+channels = erpgroup.subsequent_memory.subsequent_remembered.label;
+
+mergeddata = cat(4, erpgroup.subsequent_memory.subsequent_forgotten.avg, ...
+    erpgroup.subsequent_memory.subsequent_remembered.avg);
+
+num_chans = numel(channels);
+num_freqs = 1;
+num_time = numel(time);
+
+num_subj_lst = [33];
+num_cond = 2;
+num_grp = 1;
+
+datamat_lst = cell(num_grp); lv_evt_list = [];
+indCount_cont = 1;
+indCount = 1;
+indGroup = 1;
+for indCond = 1:num_cond
+    for indID = 1:num_subj_lst(indGroup)
+        datamat_lst{indGroup}(indCount,:) = reshape(squeeze(mergeddata(indID,:,:,indCond)), [], 1);
+        lv_evt_list(indCount_cont) = indCond;
+        indCount = indCount+1;
+        indCount_cont = indCount_cont+1;
+    end
+end
+datamat_lst{indGroup}(isnan(datamat_lst{indGroup})) = 0;
+
+%% set PLS options and run PLS
+
+option = [];
+option.method = 1; % [1] | 2 | 3 | 4 | 5 | 6
+option.num_perm = 1000; %( single non-negative integer )
+option.num_split = 0; %( single non-negative integer )
+option.num_boot = 1000; % ( single non-negative integer )
+option.cormode = 0; % [0] | 2 | 4 | 6
+option.meancentering_type = 0;% [0] | 1 | 2 | 3
+option.boot_type = 'strat'; %['strat'] | 'nonstrat'
+
+result = pls_analysis(datamat_lst, num_subj_lst, num_cond, option);
+
+%% rearrange into fieldtrip structure
+
+lvdat = reshape(result.boot_result.compare_u(:,1), num_chans, num_freqs, num_time);
+%udat = reshape(result.u, num_chans, num_freqs, num_time);
+
+stat = [];
+stat.prob = lvdat;
+stat.dimord = 'chan_freq_time';
+stat.clusters = [];
+stat.clusters.prob = result.perm_result.sprob; % check for significance of LV
+stat.mask = lvdat > 3 | lvdat < -3;
+stat.cfg = option;
+stat.time = time;
+
+save(fullfile(pn.data, 'e01_taskpls_erp.mat'),...
+    'stat', 'result', 'lvdat', 'lv_evt_list', 'num_chans', 'num_freqs', 'num_time')

+ 176 - 0
code/prior/b4a_taskPLS_memory_erp_LV1.m

@@ -0,0 +1,176 @@
+% Create an overview plot featuring the results of the multivariate PLS
+% comparing spectral changes during the stimulus period under load
+
+clear all; cla; clc;
+
+currentFile = mfilename('fullpath');
+[pathstr,~,~] = fileparts(currentFile);
+cd(fullfile(pathstr,'..'))
+rootpath = pwd;
+
+pn.data         = fullfile(rootpath, 'data', 'stats');
+pn.figures      = fullfile(rootpath, 'figures');
+pn.tools        = fullfile(rootpath, 'tools');
+    addpath(genpath(fullfile(pn.tools, '[MEG]PLS', 'MEGPLS_PIPELINE_v2.02b')))
+    addpath(fullfile(pn.tools, 'fieldtrip')); ft_defaults;
+    addpath(genpath(fullfile(pn.tools, 'RainCloudPlots')));
+    addpath(fullfile(pn.tools, 'BrewerMap'));
+    addpath(fullfile(pn.tools, 'winsor'));
+
+% set custom colormap
+cBrew = brewermap(500,'RdBu');
+cBrew = flipud(cBrew);
+colormap(cBrew)
+
+load(fullfile(pn.data, 'e01_taskpls_erp.mat'),...
+    'stat', 'result', 'lvdat', 'lv_evt_list', 'num_chans', 'num_freqs', 'num_time')
+load(fullfile(rootpath, 'data','erp', ['sub-001_erp.mat']));
+elec = erp.scene_category{1}.elec;
+
+result.perm_result.sprob
+
+indLV = 1;
+
+lvdat = reshape(result.boot_result.compare_u(:,indLV), num_chans, num_freqs, num_time);
+stat.prob = lvdat;
+stat.mask = lvdat > 3 | lvdat < -3;
+
+% maskNaN = double(stat.mask);
+% maskNaN(maskNaN==0) = NaN;
+
+%% invert solution
+
+% stat.mask = stat.mask;
+% stat.prob = stat.prob.*-1;
+% result.vsc = result.vsc.*-1;
+% result.usc = result.usc.*-1;
+
+h = figure('units','centimeter','position',[0 0 15 10]);
+set(gcf,'renderer','Painters')
+statsPlot = [];
+statsPlot = cat(1, statsPlot,squeeze(nanmax(abs(stat.prob(1:64,:,:)),[],1)));
+plot(stat.time,statsPlot, 'k')
+xlabel('Time [s from stim onset]'); ylabel('max abs BSR');
+title({'ERP changes'; ['p = ', num2str(round(result.perm_result.sprob(indLV),4))]})
+set(findall(gcf,'-property','FontSize'),'FontSize',18)
+% figureName = ['b01_pls_traces'];
+% saveas(h, fullfile(pn.figures, figureName), 'epsc');
+% saveas(h, fullfile(pn.figures, figureName), 'png');
+
+
+h = figure('units','centimeter','position',[0 0 15 10]);
+set(gcf,'renderer','Painters')
+statsPlot = [];
+statsPlot = cat(1, statsPlot,squeeze(mean(stat.prob(1:64,:,:),1)));
+plot(stat.time,statsPlot, 'k')
+xlabel('Time [s from stim onset]'); ylabel('mean BSR');
+title({'ERP changes'; ['p = ', num2str(round(result.perm_result.sprob(indLV),4))]})
+set(findall(gcf,'-property','FontSize'),'FontSize',18)
+%xlim([0 0.3])
+% figureName = ['b01_pls_traces'];
+% saveas(h, fullfile(pn.figures, figureName), 'epsc');
+% saveas(h, fullfile(pn.figures, figureName), 'png');
+
+%% plot multivariate topographies
+
+h = figure('units','centimeters','position',[0 0 10 10]);
+set(gcf,'renderer','Painters')
+
+cfg = [];
+cfg.layout = 'biosemi64.lay';
+cfg.parameter = 'powspctrm';
+cfg.comment = 'no';
+cfg.colormap = cBrew;
+cfg.colorbar = 'EastOutside';
+
+plotData = [];
+plotData.label = elec.label; % {1 x N}
+plotData.dimord = 'chan';
+cfg.zlim = [-1 1]; 
+cfg.figure = h;
+plotData.powspctrm = squeeze(nanmean(stat.mask(:,:,:).*...
+    stat.prob(:,:,:),3)); 
+ft_topoplotER(cfg,plotData);
+cb = colorbar('location', 'EastOutside'); set(get(cb,'ylabel'),'string','Mean BSR');
+figureName = ['b01_lv1'];
+% saveas(h, fullfile(pn.figures, figureName), 'epsc');
+% saveas(h, fullfile(pn.figures, figureName), 'png');
+
+%% plot using raincloud plot
+
+groupsizes=result.num_subj_lst;
+conditions=lv_evt_list;
+conds = {'forgotten'; 'remembered'};
+condData = []; uData = [];
+for indGroup = 1
+    if indGroup == 1
+        relevantEntries = 1:groupsizes(1)*numel(conds);
+    elseif indGroup == 2
+        relevantEntries = groupsizes(1)*numel(conds)+1:...
+             groupsizes(1)*numel(conds)+groupsizes(2)*numel(conds);
+    end
+    for indCond = 1:numel(conds)
+        targetEntries = relevantEntries(conditions(relevantEntries)==indCond);        
+        condData{indGroup}(indCond,:) = result.vsc(targetEntries,indLV);
+        uData{indGroup}(indCond,:) = result.usc(targetEntries,indLV);
+    end
+end
+
+cBrew(1,:) = 2.*[.3 .1 .1];
+cBrew(2,:) = [.6 .6 .6];
+
+idx_outlier = cell(1); idx_standard = cell(1);
+for indGroup = 1
+    dataToPlot = uData{indGroup}';
+    % define outlier as lin. modulation that is more than three scaled median absolute deviations (MAD) away from the median
+    X = [1 1; 1 2]; b=X\dataToPlot'; IndividualSlopes = b(2,:);
+    outliers = isoutlier(IndividualSlopes, 'median');
+    idx_outlier{indGroup} = find(outliers);
+    idx_standard{indGroup} = find(outliers==0);
+end
+
+h = figure('units','centimeter','position',[0 0 25 10]);
+for indGroup = 1
+    dataToPlot = uData{indGroup}';
+    % read into cell array of the appropriate dimensions
+    data = []; data_ws = [];
+    for i = 1:2
+        for j = 1:1
+            data{i, j} = dataToPlot(:,i);
+            % individually demean for within-subject visualization
+            data_ws{i, j} = dataToPlot(:,i)-...
+                nanmean(dataToPlot(:,:),2)+...
+                repmat(nanmean(nanmean(dataToPlot(:,:),2),1),size(dataToPlot(:,:),1),1);
+            data_nooutlier{i, j} = data{i, j};
+            data_nooutlier{i, j}(idx_outlier{indGroup}) = [];
+            data_ws_nooutlier{i, j} = data_ws{i, j};
+            data_ws_nooutlier{i, j}(idx_outlier{indGroup}) = [];
+            % sort outliers to back in original data for improved plot overlap
+            data_ws{i, j} = [data_ws{i, j}(idx_standard{indGroup}); data_ws{i, j}(idx_outlier{indGroup})];
+        end
+    end
+
+    % IMPORTANT: plot individually centered estimates, stats on uncentered estimates!
+
+    subplot(1,2,indGroup);
+    set(gcf,'renderer','Painters')
+        cla;
+        cl = cBrew(indGroup,:);
+        [~, dist] = rm_raincloud_fixedSpacing(data_ws, [.8 .8 .8],1);
+        h_rc = rm_raincloud_fixedSpacing(data_ws_nooutlier, cl,1,[],[],[],dist);
+        view([90 -90]);
+        axis ij
+    box(gca,'off')
+    set(gca, 'YTickLabels', {conds{2}; conds{1}});
+    yticks = get(gca, 'ytick'); ylim([yticks(1)-(yticks(2)-yticks(1))./2, yticks(2)+(yticks(2)-yticks(1))./1.5]);
+
+    minmax = [min(min(cat(2,data_ws{:}))), max(max(cat(2,data_ws{:})))];
+    xlim(minmax+[-0.2*diff(minmax), 0.2*diff(minmax)])
+    ylabel('scene category'); xlabel({'Brainscore'; '[Individually centered]'})
+
+    % test linear effect
+    curData = [data_nooutlier{1, 1}, data_nooutlier{2, 1}];
+    X = [1 1; 1 2]; b=X\curData'; IndividualSlopes = b(2,:);
+    [~, p, ci, stats] = ttest(IndividualSlopes);
+    title(['M:', num2str(round(mean(IndividualSlopes),3)), '; p=', num2str(round(p,3))])
+end

+ 107 - 0
code/prior/b4b_taskPLS_memory_erf.m

@@ -0,0 +1,107 @@
+% Set up EEG PLS for a task PLS using spectral power
+
+clear all; cla; clc;
+
+currentFile = mfilename('fullpath');
+[pathstr,~,~] = fileparts(currentFile);
+cd(fullfile(pathstr,'..'))
+rootpath = pwd;
+
+pn.data_eeg = fullfile(rootpath, '..', 'eegmp_preproc', 'data', 'outputs', 'eeg');
+pn.data_erp = fullfile(rootpath, 'data', 'erp');
+pn.data_erf = fullfile(rootpath, 'data', 'erf');
+pn.data = fullfile(rootpath, 'data', 'stats'); mkdir(pn.data);
+pn.tools = fullfile(rootpath, 'tools');
+    addpath(fullfile(rootpath, '..', 'eegmp_preproc', 'tools', 'fieldtrip')); ft_defaults
+    addpath(genpath(fullfile(pn.tools, '[MEG]PLS', 'MEGPLS_PIPELINE_v2.02b')))
+    addpath(fullfile(pn.tools, 'BrewerMap'));
+    addpath(fullfile(pn.tools, 'shadedErrorBar'));
+
+%% add seed for reproducibility
+
+rng(0, 'twister');
+    
+%% load event info
+
+load(fullfile(pn.data_eeg, ['sub-001_task-xxxx_eeg_art.mat']), 'events');
+
+parameter = {'scene_category'; 'old'; 'behavior'; 'subsequent_memory'};
+for ind_param = 1:numel(parameter)
+    conds.(parameter{ind_param}) = unique(events.(parameter{ind_param}));
+end
+
+%% load erp
+
+for ind_id = 1:33
+    id = sprintf('sub-%03d', ind_id); disp(id)
+    load(fullfile(pn.data_erf, [id,'_erf.mat']));
+    for ind_option = 2:3
+        if ind_id == 1
+             erpgroup.subsequent_memory.(conds.subsequent_memory{ind_option}) = erf.subsequent_memory{ind_option};
+             erpgroup.subsequent_memory.(conds.subsequent_memory{ind_option}) = ...
+                 rmfield(erpgroup.subsequent_memory.(conds.subsequent_memory{ind_option}), {'powspctrm'});
+             erpgroup.subsequent_memory.(conds.subsequent_memory{ind_option}).dimord = 'sub_chan_freq_time';
+        end
+        erpgroup.subsequent_memory.(conds.subsequent_memory{ind_option}).avg(ind_id,:,:,:) = erf.subsequent_memory{ind_option}.powspctrm;
+    end
+end
+
+time = erpgroup.subsequent_memory.subsequent_remembered.time;
+freq = erpgroup.subsequent_memory.subsequent_remembered.freq;
+channels = erpgroup.subsequent_memory.subsequent_remembered.label;
+
+mergeddata = cat(5, erpgroup.subsequent_memory.subsequent_forgotten.avg, ...
+    erpgroup.subsequent_memory.subsequent_remembered.avg);
+
+num_chans = numel(channels);
+num_freqs = numel(freq);
+num_time = numel(time);
+
+num_subj_lst = [33];
+num_cond = 2;
+num_grp = 1;
+
+datamat_lst = cell(num_grp); lv_evt_list = [];
+indCount_cont = 1;
+indCount = 1;
+indGroup = 1;
+for indCond = 1:num_cond
+    for indID = 1:num_subj_lst(indGroup)
+        datamat_lst{indGroup}(indCount,:) = reshape(squeeze(mergeddata(indID,:,:,:,indCond)), [], 1);
+        lv_evt_list(indCount_cont) = indCond;
+        indCount = indCount+1;
+        indCount_cont = indCount_cont+1;
+    end
+end
+datamat_lst{indGroup}(isnan(datamat_lst{indGroup})) = 0;
+
+%% set PLS options and run PLS
+
+option = [];
+option.method = 1; % [1] | 2 | 3 | 4 | 5 | 6
+option.num_perm = 1000; %( single non-negative integer )
+option.num_split = 0; %( single non-negative integer )
+option.num_boot = 1000; % ( single non-negative integer )
+option.cormode = 0; % [0] | 2 | 4 | 6
+option.meancentering_type = 0;% [0] | 1 | 2 | 3
+option.boot_type = 'strat'; %['strat'] | 'nonstrat'
+
+result = pls_analysis(datamat_lst, num_subj_lst, num_cond, option);
+
+%% rearrange into fieldtrip structure
+
+lvdat = reshape(result.boot_result.compare_u(:,1), num_chans, num_freqs, num_time);
+%udat = reshape(result.u, num_chans, num_freqs, num_time);
+
+stat = [];
+stat.prob = lvdat;
+stat.dimord = 'chan_freq_time';
+stat.clusters = [];
+stat.clusters.prob = result.perm_result.sprob; % check for significance of LV
+stat.mask = lvdat > 3 | lvdat < -3;
+stat.cfg = option;
+stat.freq = freq;
+stat.time = time;
+
+save(fullfile(pn.data, 'b4b_taskpls_erf.mat'),...
+    'stat', 'result', 'lvdat', 'lv_evt_list', 'num_chans', 'num_freqs', 'num_time')

+ 198 - 0
code/prior/b4b_taskPLS_memory_erf_LV1.m

@@ -0,0 +1,198 @@
+% Create an overview plot featuring the results of the multivariate PLS
+% comparing spectral changes during the stimulus period under load
+
+clear all; cla; clc;
+
+currentFile = mfilename('fullpath');
+[pathstr,~,~] = fileparts(currentFile);
+cd(fullfile(pathstr,'..'))
+rootpath = pwd;
+
+pn.data         = fullfile(rootpath, 'data', 'stats');
+pn.figures      = fullfile(rootpath, 'figures');
+pn.tools        = fullfile(rootpath, 'tools');
+    addpath(genpath(fullfile(pn.tools, '[MEG]PLS', 'MEGPLS_PIPELINE_v2.02b')))
+    addpath(fullfile(pn.tools, 'fieldtrip')); ft_defaults;
+    addpath(genpath(fullfile(pn.tools, 'RainCloudPlots')));
+    addpath(fullfile(pn.tools, 'BrewerMap'));
+    addpath(fullfile(pn.tools, 'winsor'));
+
+% set custom colormap
+cBrew = brewermap(500,'RdBu');
+cBrew = flipud(cBrew);
+colormap(cBrew)
+
+load(fullfile(pn.data, 'b4b_taskpls_erf.mat'),...
+    'stat', 'result', 'lvdat', 'lv_evt_list', 'num_chans', 'num_freqs', 'num_time')
+load(fullfile(rootpath, 'data','erp', ['sub-001_erp.mat']));
+elec = erp.scene_category{1}.elec;
+
+result.perm_result.sprob
+
+indLV = 1;
+
+lvdat = reshape(result.boot_result.compare_u(:,indLV), num_chans, num_freqs, num_time);
+stat.prob = lvdat;
+stat.mask = lvdat > 3 | lvdat < -3;
+
+% maskNaN = double(stat.mask);
+% maskNaN(maskNaN==0) = NaN;
+
+%% invert solution
+
+% stat.mask = stat.mask;
+% stat.prob = stat.prob.*-1;
+% result.vsc = result.vsc.*-1;
+% result.usc = result.usc.*-1;
+
+h = figure('units','centimeter','position',[0 0 15 10]);
+set(gcf,'renderer','Painters')
+statsPlot = [];
+statsPlot = cat(1, statsPlot,squeeze(nanmax(abs(stat.prob(1:64,:,:)),[],1)));
+imagesc(stat.time,[],statsPlot, [-8 8])
+xlabel('Time [s from stim onset]'); ylabel('max abs BSR');
+title({'ERF changes'; ['p = ', num2str(round(result.perm_result.sprob(indLV),4))]})
+set(findall(gcf,'-property','FontSize'),'FontSize',18)
+colorbar;
+colormap(cBrew)
+
+h = figure('units','centimeter','position',[0 0 15 10]);
+set(gcf,'renderer','Painters')
+statsPlot = [];
+statsPlot = cat(1, statsPlot,squeeze(nanmin(stat.prob(1:64,:,:),[],1)));
+imagesc(stat.time,[],statsPlot, [-6 6])
+xlabel('Time [s from stim onset]'); ylabel('max abs BSR');
+title({'ERF changes'; ['p = ', num2str(round(result.perm_result.sprob(indLV),4))]})
+set(findall(gcf,'-property','FontSize'),'FontSize',18)
+colorbar;
+colormap(cBrew)
+
+h = figure('units','centimeter','position',[0 0 15 10]);
+set(gcf,'renderer','Painters')
+statsPlot = [];
+statsPlot = cat(1, statsPlot,squeeze(nanmax(stat.prob(1:64,:,:),[],1)));
+imagesc(stat.time,[],statsPlot, [-5 5])
+xlabel('Time [s from stim onset]'); ylabel('max abs BSR');
+title({'ERF changes'; ['p = ', num2str(round(result.perm_result.sprob(indLV),4))]})
+set(findall(gcf,'-property','FontSize'),'FontSize',18)
+colorbar;
+colormap(cBrew)
+
+% figureName = ['b01_pls_traces'];
+% saveas(h, fullfile(pn.figures, figureName), 'epsc');
+% saveas(h, fullfile(pn.figures, figureName), 'png');
+
+%% plot multivariate topographies
+
+h = figure('units','centimeters','position',[0 0 10 10]);
+set(gcf,'renderer','Painters')
+
+cfg = [];
+cfg.layout = 'biosemi64.lay';
+cfg.parameter = 'powspctrm';
+cfg.comment = 'no';
+cfg.colormap = cBrew;
+cfg.colorbar = 'EastOutside';
+
+plotData = [];
+plotData.label = elec.label; % {1 x N}
+plotData.dimord = 'chan';
+cfg.zlim = [-4 4]; 
+cfg.figure = h;
+plotData.powspctrm = squeeze(nanmean(nanmin(stat.mask(:,:,:).*...
+    stat.prob(:,:,:),[],3),2)); 
+ft_topoplotER(cfg,plotData);
+cb = colorbar('location', 'EastOutside'); set(get(cb,'ylabel'),'string','Mean BSR');
+figureName = ['b01_lv1'];
+% saveas(h, fullfile(pn.figures, figureName), 'epsc');
+% saveas(h, fullfile(pn.figures, figureName), 'png');
+
+plotData = [];
+plotData.label = elec.label; % {1 x N}
+plotData.dimord = 'chan';
+cfg.zlim = [-3 3]; 
+cfg.figure = h;
+plotData.powspctrm = squeeze(nanmean(nanmax(stat.mask(:,:,:).*...
+    stat.prob(:,:,:),[],3),2)); 
+ft_topoplotER(cfg,plotData);
+cb = colorbar('location', 'EastOutside'); set(get(cb,'ylabel'),'string','Mean BSR');
+figureName = ['b01_lv1'];
+
+%% plot using raincloud plot
+
+groupsizes=result.num_subj_lst;
+conditions=lv_evt_list;
+conds = {'forgotten'; 'remembered'};
+condData = []; uData = [];
+for indGroup = 1
+    if indGroup == 1
+        relevantEntries = 1:groupsizes(1)*numel(conds);
+    elseif indGroup == 2
+        relevantEntries = groupsizes(1)*numel(conds)+1:...
+             groupsizes(1)*numel(conds)+groupsizes(2)*numel(conds);
+    end
+    for indCond = 1:numel(conds)
+        targetEntries = relevantEntries(conditions(relevantEntries)==indCond);        
+        condData{indGroup}(indCond,:) = result.vsc(targetEntries,indLV);
+        uData{indGroup}(indCond,:) = result.usc(targetEntries,indLV);
+    end
+end
+
+cBrew(1,:) = 2.*[.3 .1 .1];
+cBrew(2,:) = [.6 .6 .6];
+
+idx_outlier = cell(1); idx_standard = cell(1);
+for indGroup = 1
+    dataToPlot = uData{indGroup}';
+    % define outlier as lin. modulation that is more than three scaled median absolute deviations (MAD) away from the median
+    X = [1 1; 1 2]; b=X\dataToPlot'; IndividualSlopes = b(2,:);
+    outliers = isoutlier(IndividualSlopes, 'median');
+    idx_outlier{indGroup} = find(outliers);
+    idx_standard{indGroup} = find(outliers==0);
+end
+
+h = figure('units','centimeter','position',[0 0 25 10]);
+for indGroup = 1
+    dataToPlot = uData{indGroup}';
+    % read into cell array of the appropriate dimensions
+    data = []; data_ws = [];
+    for i = 1:2
+        for j = 1:1
+            data{i, j} = dataToPlot(:,i);
+            % individually demean for within-subject visualization
+            data_ws{i, j} = dataToPlot(:,i)-...
+                nanmean(dataToPlot(:,:),2)+...
+                repmat(nanmean(nanmean(dataToPlot(:,:),2),1),size(dataToPlot(:,:),1),1);
+            data_nooutlier{i, j} = data{i, j};
+            data_nooutlier{i, j}(idx_outlier{indGroup}) = [];
+            data_ws_nooutlier{i, j} = data_ws{i, j};
+            data_ws_nooutlier{i, j}(idx_outlier{indGroup}) = [];
+            % sort outliers to back in original data for improved plot overlap
+            data_ws{i, j} = [data_ws{i, j}(idx_standard{indGroup}); data_ws{i, j}(idx_outlier{indGroup})];
+        end
+    end
+
+    % IMPORTANT: plot individually centered estimates, stats on uncentered estimates!
+
+    subplot(1,2,indGroup);
+    set(gcf,'renderer','Painters')
+        cla;
+        cl = cBrew(indGroup,:);
+        [~, dist] = rm_raincloud_fixedSpacing(data_ws, [.8 .8 .8],1);
+        h_rc = rm_raincloud_fixedSpacing(data_ws_nooutlier, cl,1,[],[],[],dist);
+        view([90 -90]);
+        axis ij
+    box(gca,'off')
+    set(gca, 'YTickLabels', {conds{2}; conds{1}});
+    yticks = get(gca, 'ytick'); ylim([yticks(1)-(yticks(2)-yticks(1))./2, yticks(2)+(yticks(2)-yticks(1))./1.5]);
+
+    minmax = [min(min(cat(2,data_ws{:}))), max(max(cat(2,data_ws{:})))];
+    xlim(minmax+[-0.2*diff(minmax), 0.2*diff(minmax)])
+    ylabel('scene category'); xlabel({'Brainscore'; '[Individually centered]'})
+
+    % test linear effect
+    curData = [data_nooutlier{1, 1}, data_nooutlier{2, 1}];
+    X = [1 1; 1 2]; b=X\curData'; IndividualSlopes = b(2,:);
+    [~, p, ci, stats] = ttest(IndividualSlopes);
+    title(['M:', num2str(round(mean(IndividualSlopes),3)), '; p=', num2str(round(p,3))])
+end

+ 224 - 0
code/prior/b_scenecat_n1.m

@@ -0,0 +1,224 @@
+
+currentFile = mfilename('fullpath');
+[pathstr,~,~] = fileparts(currentFile);
+cd(fullfile(pathstr,'..'))
+rootpath = pwd;
+
+pn.data_eeg = fullfile(rootpath, '..', 'eegmp_preproc', 'data', 'outputs', 'eeg');
+pn.data_erp = fullfile(rootpath, 'data', 'erp');
+pn.data_erf = fullfile(rootpath, 'data', 'erf');
+pn.tools = fullfile(rootpath, 'tools');
+    addpath(fullfile(rootpath, '..', 'eegmp_preproc', 'tools', 'fieldtrip')); ft_defaults
+    addpath(fullfile(pn.tools, 'BrewerMap'));
+    addpath(fullfile(pn.tools, 'shadedErrorBar'));
+    
+%% load event info
+
+load(fullfile(pn.data_eeg, ['sub-001_task-xxxx_eeg_art.mat']), 'events');
+
+parameter = {'scene_category'; 'old'; 'behavior'; 'subsequent_memory'};
+for ind_param = 1:numel(parameter)
+    conds.(parameter{ind_param}) = unique(events.(parameter{ind_param}));
+end
+
+%% load erp
+
+for ind_id = 1:33
+    id = sprintf('sub-%03d', ind_id);
+    load(fullfile(pn.data_erp, [id,'_erp.mat']));
+    for ind_option = 1:numel(conds.scene_category)
+        if ind_id == 1
+             erpgroup.scene_category.(conds.scene_category{ind_option}) = erp.scene_category{ind_option};
+             erpgroup.scene_category.(conds.scene_category{ind_option}) = ...
+                 rmfield(erpgroup.scene_category.(conds.scene_category{ind_option}), {'avg', 'var', 'dof'});
+             erpgroup.scene_category.(conds.scene_category{ind_option}).dimord = 'sub_chan_time';
+        end
+        erpgroup.scene_category.(conds.scene_category{ind_option}).avg(ind_id,:,:) = erp.scene_category{ind_option}.avg;
+    end
+end
+
+time = erpgroup.scene_category.manmade.time;
+elec = erpgroup.scene_category.manmade.elec;
+channels = erpgroup.scene_category.manmade.label;
+
+%idx_chans = find(ismember(channels, {'O1', 'Oz', 'O2'}));
+%idx_chans = find(ismember(channels, {'PO7', 'PO8'}));
+%idx_chans = find(ismember(channels, {'Pz', 'CPz', 'P1'}));
+
+mergeddata = cat(4, erpgroup.scene_category.manmade.avg, ...
+    erpgroup.scene_category.natural.avg);
+
+%% plot topography of N1
+
+% set custom colormap
+cBrew = brewermap(500,'RdBu');
+cBrew = flipud(cBrew);
+colormap(cBrew)
+
+h = figure('units','centimeters','position',[0 0 10 10]);
+set(gcf,'renderer','Painters')
+
+cfg = [];
+cfg.layout = 'biosemi64.lay';
+cfg.parameter = 'powspctrm';
+cfg.comment = 'no';
+cfg.colormap = cBrew;
+cfg.colorbar = 'EastOutside';
+
+plotData = [];
+plotData.label = elec.label(1:66); % {1 x N}
+plotData.dimord = 'chan';
+plotData.powspctrm = squeeze(nanmean(nanmean(nanmean(mergeddata(:,:,time>0.08 & time <0.12,1:2),3),1),4))'; 
+[~, sortidx] = sort(plotData.powspctrm, 'ascend');
+idx_chans = sortidx(1:6);
+
+cfg.marker = 'off'; 
+cfg.highlight = 'yes';
+cfg.highlightchannel = plotData.label(idx_chans);
+cfg.highlightcolor = [1 0 0];
+cfg.highlightsymbol = '.';
+cfg.highlightsize = 18;
+cfg.zlim = [-3 3]; 
+cfg.figure = h;
+ft_topoplotER(cfg,plotData);
+cb = colorbar('location', 'EastOutside'); set(get(cb,'ylabel'),'string','Amplitude');
+% figureName = ['xxx'];
+% saveas(h, fullfile(pn.figures, figureName), 'epsc');
+% saveas(h, fullfile(pn.figures, figureName), 'png');
+
+%% visualize N1 over negative maximum
+
+% avg across channels and conditions
+condAvg = squeeze(nanmean(nanmean(mergeddata(:,idx_chans,:,1:2),2),4));
+
+h = figure('units','centimeters','position',[0 0 10 8]);
+cla; hold on;
+% new value = old value ? subject average + grand average
+curData = squeeze(nanmean(mergeddata(:,idx_chans,:,1),2));
+curData = curData-condAvg+repmat(nanmean(condAvg,1),size(condAvg,1),1);
+standError = nanstd(curData,1)./sqrt(size(curData,1));
+l1 = shadedErrorBar(time,nanmean(curData,1),standError, 'lineprops', {'color', 'k','linewidth', 2}, 'patchSaturation', .1);
+curData = squeeze(nanmean(mergeddata(:,idx_chans,:,2),2));
+curData = curData-condAvg+repmat(nanmean(condAvg,1),size(condAvg,1),1);
+standError = nanstd(curData,1)./sqrt(size(curData,1));
+l2 = shadedErrorBar(time,nanmean(curData,1),standError, 'lineprops', {'color', 'r','linewidth', 2}, 'patchSaturation', .1);
+xlabel('Time (s) from stim onset')
+xlim([-1 2]); %ylim([-.03 .18])
+ylabel({'ERP';'(microVolts)'});
+xlabel({'Time (s)'});    
+set(findall(gcf,'-property','FontSize'),'FontSize',12)
+
+h = figure('units','centimeters','position',[0 0 15 10]);
+cla; hold on;
+% new value = old value ? subject average + grand average
+curData = squeeze(nanmean(mergeddata(:,idx_chans,:,1),2));
+curData = curData-condAvg+repmat(nanmean(condAvg,1),size(condAvg,1),1);
+standError = nanstd(curData,1)./sqrt(size(curData,1));
+l1 = shadedErrorBar(time,nanmean(curData,1),standError, 'lineprops', {'color', 'k','linewidth', 2}, 'patchSaturation', .1);
+curData = squeeze(nanmean(mergeddata(:,idx_chans,:,2),2));
+curData = curData-condAvg+repmat(nanmean(condAvg,1),size(condAvg,1),1);
+standError = nanstd(curData,1)./sqrt(size(curData,1));
+l2 = shadedErrorBar(time,nanmean(curData,1),standError, 'lineprops', {'color', 'r','linewidth', 2}, 'patchSaturation', .1);
+ax = gca; ax.YDir = 'reverse';
+xlabel('Time (s) from stim onset')
+xlim([-.5 .5]); %ylim([-.03 .18])
+ylabel({'ERP';'(microVolts)'});
+xlabel({'Time (s)'});    
+set(findall(gcf,'-property','FontSize'),'FontSize',12)
+
+% across all channels
+condAvg = squeeze(nanmean(nanmean(mergeddata(:,:,:,1:2),2),4));
+
+h = figure('units','centimeters','position',[0 0 15 10]);
+cla; hold on;
+% new value = old value ? subject average + grand average
+curData = squeeze(nanmean(mergeddata(:,:,:,1),2));
+curData = curData-condAvg+repmat(nanmean(condAvg,1),size(condAvg,1),1);
+standError = nanstd(curData,1)./sqrt(size(curData,1));
+l1 = shadedErrorBar(time,nanmean(curData,1),standError, 'lineprops', {'color', 'k','linewidth', 2}, 'patchSaturation', .1);
+curData = squeeze(nanmean(mergeddata(:,:,:,2),2));
+curData = curData-condAvg+repmat(nanmean(condAvg,1),size(condAvg,1),1);
+standError = nanstd(curData,1)./sqrt(size(curData,1));
+l2 = shadedErrorBar(time,nanmean(curData,1),standError, 'lineprops', {'color', 'r','linewidth', 2}, 'patchSaturation', .1);
+ax = gca; ax.YDir = 'reverse';
+xlabel('Time (s) from stim onset')
+xlim([0 .3]); %ylim([-.03 .18])
+ylabel({'ERP';'(microVolts)'});
+xlabel({'Time (s)'});    
+set(findall(gcf,'-property','FontSize'),'FontSize',12)
+
+%% plot difference between conditions
+
+h = figure('units','centimeters','position',[0 0 10 10]);
+set(gcf,'renderer','Painters')
+
+cfg = [];
+cfg.layout = 'biosemi64.lay';
+cfg.parameter = 'powspctrm';
+cfg.comment = 'no';
+cfg.colormap = cBrew;
+cfg.colorbar = 'EastOutside';
+
+plotData = [];
+plotData.label = elec.label(1:66); % {1 x N}
+plotData.dimord = 'chan';
+plotData.powspctrm = squeeze(nanmean(nanmean(nanmean(mergeddata(:,:,time>0.08 & time <0.12,2),3),1),4))'...
+    -squeeze(nanmean(nanmean(nanmean(mergeddata(:,:,time>0.08 & time <0.12,1),3),1),4))'; 
+[~, sortidx] = sort(plotData.powspctrm, 'ascend');
+idx_chans = sortidx(1:6);
+
+cfg.marker = 'off'; 
+cfg.highlight = 'yes';
+cfg.highlightchannel = plotData.label(idx_chans);
+cfg.highlightcolor = [1 0 0];
+cfg.highlightsymbol = '.';
+cfg.highlightsize = 18;
+%cfg.zlim = [-5 5]*10^-4; 
+cfg.figure = h;
+ft_topoplotER(cfg,plotData);
+cb = colorbar('location', 'EastOutside'); set(get(cb,'ylabel'),'string','Amplitude');
+
+
+%% visualize for negative pls channels
+
+idx_chans = [28:30];
+condAvg = squeeze(nanmean(nanmean(mergeddata(:,idx_chans,:,1:2),2),4));
+
+h = figure('units','centimeters','position',[0 0 10 8]);
+cla; hold on;
+% new value = old value ? subject average + grand average
+curData = squeeze(nanmean(mergeddata(:,idx_chans,:,1),2));
+curData = curData-condAvg+repmat(nanmean(condAvg,1),size(condAvg,1),1);
+standError = nanstd(curData,1)./sqrt(size(curData,1));
+l1 = shadedErrorBar(time,nanmean(curData,1),standError, 'lineprops', {'color', 'k','linewidth', 2}, 'patchSaturation', .1);
+curData = squeeze(nanmean(mergeddata(:,idx_chans,:,2),2));
+curData = curData-condAvg+repmat(nanmean(condAvg,1),size(condAvg,1),1);
+standError = nanstd(curData,1)./sqrt(size(curData,1));
+l2 = shadedErrorBar(time,nanmean(curData,1),standError, 'lineprops', {'color', 'r','linewidth', 2}, 'patchSaturation', .1);
+xlabel('Time (s) from stim onset')
+xlim([-1 2]); %ylim([-.03 .18])
+ylabel({'ERP';'(microVolts)'});
+xlabel({'Time (s)'});    
+set(findall(gcf,'-property','FontSize'),'FontSize',12)
+
+%% visualize for positive pls channels
+
+idx_chans = [21:23, 58:62];
+condAvg = squeeze(nanmean(nanmean(mergeddata(:,idx_chans,:,1:2),2),4));
+
+h = figure('units','centimeters','position',[0 0 10 8]);
+cla; hold on;
+% new value = old value ? subject average + grand average
+curData = squeeze(nanmean(mergeddata(:,idx_chans,:,1),2));
+curData = curData-condAvg+repmat(nanmean(condAvg,1),size(condAvg,1),1);
+standError = nanstd(curData,1)./sqrt(size(curData,1));
+l1 = shadedErrorBar(time,nanmean(curData,1),standError, 'lineprops', {'color', 'k','linewidth', 2}, 'patchSaturation', .1);
+curData = squeeze(nanmean(mergeddata(:,idx_chans,:,2),2));
+curData = curData-condAvg+repmat(nanmean(condAvg,1),size(condAvg,1),1);
+standError = nanstd(curData,1)./sqrt(size(curData,1));
+l2 = shadedErrorBar(time,nanmean(curData,1),standError, 'lineprops', {'color', 'r','linewidth', 2}, 'patchSaturation', .1);
+xlabel('Time (s) from stim onset')
+xlim([-1 2]); %ylim([-.03 .18])
+ylabel({'ERP';'(microVolts)'});
+xlabel({'Time (s)'});    
+set(findall(gcf,'-property','FontSize'),'FontSize',12)

+ 413 - 0
code/prior/b_scenecat_n1_bl.m

@@ -0,0 +1,413 @@
+
+currentFile = mfilename('fullpath');
+[pathstr,~,~] = fileparts(currentFile);
+cd(fullfile(pathstr,'..'))
+rootpath = pwd;
+
+pn.data_eeg = fullfile(rootpath, '..', 'eegmp_preproc', 'data', 'outputs', 'eeg');
+pn.data_erp = fullfile(rootpath, 'data', 'erp');
+pn.data_erf = fullfile(rootpath, 'data', 'erf');
+pn.tools = fullfile(rootpath, 'tools');
+    addpath(fullfile(rootpath, '..', 'eegmp_preproc', 'tools', 'fieldtrip')); ft_defaults
+    addpath(fullfile(pn.tools, 'BrewerMap'));
+    addpath(fullfile(pn.tools, 'shadedErrorBar'));
+    
+%% load event info
+
+load(fullfile(pn.data_eeg, ['sub-001_task-xxxx_eeg_art.mat']), 'events');
+
+parameter = {'scene_category'; 'old'; 'behavior'; 'subsequent_memory'};
+for ind_param = 1:numel(parameter)
+    conds.(parameter{ind_param}) = unique(events.(parameter{ind_param}));
+end
+
+%% load erp_bl
+
+for ind_id = 1:33
+    id = sprintf('sub-%03d', ind_id);
+    load(fullfile(pn.data_erp, [id,'_erp_bl.mat']));
+    for ind_option = 1:numel(conds.scene_category)
+        if ind_id == 1
+             erpgroup.scene_category.(conds.scene_category{ind_option}) = erp_bl.scene_category{ind_option};
+             erpgroup.scene_category.(conds.scene_category{ind_option}) = ...
+                 rmfield(erpgroup.scene_category.(conds.scene_category{ind_option}), {'avg', 'var', 'dof'});
+             erpgroup.scene_category.(conds.scene_category{ind_option}).dimord = 'sub_chan_time';
+        end
+        erpgroup.scene_category.(conds.scene_category{ind_option}).avg(ind_id,:,:) = erp_bl.scene_category{ind_option}.avg;
+    end
+end
+
+time = erpgroup.scene_category.manmade.time;
+elec = erpgroup.scene_category.manmade.elec;
+channels = erpgroup.scene_category.manmade.label;
+
+%idx_chans = find(ismember(channels, {'O1', 'Oz', 'O2'}));
+%idx_chans = find(ismember(channels, {'PO7', 'PO8'}));
+%idx_chans = find(ismember(channels, {'Pz', 'CPz', 'P1'}));
+
+mergeddata = cat(4, erpgroup.scene_category.manmade.avg, ...
+    erpgroup.scene_category.natural.avg);
+
+%% plot topography of visual N1
+
+% set custom colormap
+cBrew = brewermap(500,'RdBu');
+cBrew = flipud(cBrew);
+colormap(cBrew)
+
+h = figure('units','centimeters','position',[0 0 10 10]);
+set(gcf,'renderer','Painters')
+
+cfg = [];
+cfg.layout = 'EEG1010.lay';
+cfg.parameter = 'powspctrm';
+cfg.comment = 'no';
+cfg.colormap = cBrew;
+cfg.colorbar = 'EastOutside';
+
+plotData = [];
+plotData.label = elec.label(1:64); % {1 x N}
+plotData.dimord = 'chan';
+plotData.powspctrm = squeeze(nanmean(nanmean(nanmin(mergeddata(:,:,time>0.05 & time <0.07,1:2),[],3),1),4))'; 
+[~, sortidx] = sort(plotData.powspctrm, 'ascend');
+idx_chans = sortidx(1);
+idx_chans_visual = idx_chans;
+
+cfg.marker = 'off'; 
+cfg.highlight = 'yes';
+cfg.highlightchannel = plotData.label(idx_chans);
+cfg.highlightcolor = [1 0 0];
+cfg.highlightsymbol = '.';
+cfg.highlightsize = 18;
+cfg.zlim = [-2 2];%[-8 8]*10^-4; 
+cfg.figure = h;
+ft_topoplotER(cfg,plotData);
+cb = colorbar('location', 'EastOutside'); set(get(cb,'ylabel'),'string','Amplitude');
+
+%% visualize N1 over negative maximum
+
+% avg across channels and conditions
+condAvg = squeeze(nanmean(nanmean(mergeddata(:,idx_chans,:,1:2),2),4));
+
+h = figure('units','centimeters','position',[0 0 10 8]);
+cla; hold on;
+% new value = old value ? subject average + grand average
+curData = squeeze(nanmean(mergeddata(:,idx_chans,:,1),2));
+curData = curData-condAvg+repmat(nanmean(condAvg,1),size(condAvg,1),1);
+standError = nanstd(curData,1)./sqrt(size(curData,1));
+l1 = shadedErrorBar(time,nanmean(curData,1),standError, 'lineprops', {'color', 'k','linewidth', 2}, 'patchSaturation', .1);
+curData = squeeze(nanmean(mergeddata(:,idx_chans,:,2),2));
+curData = curData-condAvg+repmat(nanmean(condAvg,1),size(condAvg,1),1);
+standError = nanstd(curData,1)./sqrt(size(curData,1));
+l2 = shadedErrorBar(time,nanmean(curData,1),standError, 'lineprops', {'color', 'r','linewidth', 2}, 'patchSaturation', .1);
+% ax = gca; ax.YDir = 'reverse';
+xlabel('Time (s) from stim onset')
+xlim([-.05 .3]); %ylim([-.03 .18])
+ylabel({'ERP';'(microVolts)'});
+xlabel({'Time (s)'});    
+set(findall(gcf,'-property','FontSize'),'FontSize',12)
+
+%% ERP components for subjects 1-17 and 18-33 are shifted in time!
+
+h = figure('units','centimeters','position',[0 0 10 8]);
+cla; hold on;
+% new value = old value ? subject average + grand average
+curData = squeeze(nanmean(mergeddata(1:17,idx_chans,:,1),2));
+standError = nanstd(curData,1)./sqrt(size(curData,1));
+l1 = shadedErrorBar(time,nanmean(curData,1),standError, 'lineprops', {'color', 'k','linewidth', 2}, 'patchSaturation', .1);
+curData = squeeze(nanmean(mergeddata(18:end,idx_chans,:,1),2));
+standError = nanstd(curData,1)./sqrt(size(curData,1));
+l2 = shadedErrorBar(time,nanmean(curData,1),standError, 'lineprops', {'color', 'r','linewidth', 2}, 'patchSaturation', .1);
+% ax = gca; ax.YDir = 'reverse';
+xlabel('Time (s) from stim onset')
+xlim([-.025 .16]); %ylim([-.03 .18])
+ylabel({'ERP';'(microVolts)'});
+xlabel({'Time (s)'});    
+set(findall(gcf,'-property','FontSize'),'FontSize',12)
+
+%% align individual subjects N1 to first negative peak
+
+% find individual minimum (condition-specific) between 40 and 150 ms
+
+time2search = find(time>0.04 & time <0.12);
+
+newtime = 0-100*(time(2)-time(1)):(time(2)-time(1)):0+100*(time(2)-time(1));
+
+% for indID = 1:size(condAvg,1)
+%     %[peaks, locs] = findpeaks(condAvg1(indID,:));
+%     tmp = find(islocalmin(condAvg(indID,time2search), ...
+%         'FlatSelection', 'center', ...
+%         'MinSeparation', 15));
+%     minVal1(indID) = condAvg1(indID,time2search(tmp(1)));
+%     minLoc1(indID) = tmp(1);
+%     curmin = time2search(tmp(1));
+%     alignedN1_1(indID,:) = condAvg1(indID,curmin-100:curmin+100);
+%     
+%     tmp = find(islocalmin(condAvg(indID,time2search), ...
+%         'FlatSelection', 'center', ...
+%         'MinSeparation', 15));
+%     minVal2(indID) = condAvg2(indID,time2search(tmp(1)));
+%     minLoc2(indID) = tmp(1);
+%     curmin = time2search(tmp(1));
+%     alignedN1_2(indID,:) = condAvg2(indID,curmin-100:curmin+100);
+% end
+
+% alternatively: consider global minimum
+for indID = 1:size(condAvg,1)
+    [~, minLoc1(indID)] = min(condAvg(indID,time2search));
+    curmin = time2search(minLoc1(indID));
+    minVal1(indID) = condAvg1(indID,curmin);
+    alignedN1_1(indID,:) = condAvg1(indID,curmin-100:curmin+100);
+    [~, minLoc2(indID)] = min(condAvg(indID,time2search));
+    curmin = time2search(minLoc2(indID));
+    minVal1(indID) = condAvg2(indID,curmin);
+    alignedN1_2(indID,:) = condAvg2(indID,curmin-100:curmin+100);
+end
+
+mergeddata_aligned = cat(3, alignedN1_1, alignedN1_2);
+
+[h, p] = ttest(minVal1, minVal2)
+
+% avg across channels and conditions
+condAvg_al = squeeze(nanmean(mergeddata_aligned(:,:,1:2),3));
+
+% plot aligned signals
+figure; imagesc(zscore(condAvg_al,[],2))
+figure; imagesc(condAvg_al)
+
+h = figure('units','centimeters','position',[0 0 10 8]);
+cla; hold on;
+% new value = old value ? subject average + grand average
+curData = squeeze(mergeddata_aligned(:,:,1));
+curData = curData-condAvg_al+repmat(nanmean(condAvg_al,1),size(condAvg_al,1),1);
+standError = nanstd(curData,1)./sqrt(size(curData,1));
+l1 = shadedErrorBar(newtime*1000,nanmean(curData,1),standError, 'lineprops', {'color', 'k','linewidth', 2}, 'patchSaturation', .1);
+curData = squeeze(mergeddata_aligned(:,:,2));
+curData = curData-condAvg_al+repmat(nanmean(condAvg_al,1),size(condAvg_al,1),1);
+standError = nanstd(curData,1)./sqrt(size(curData,1));
+l2 = shadedErrorBar(newtime*1000,nanmean(curData,1),standError, 'lineprops', {'color', 'r','linewidth', 2}, 'patchSaturation', .1);
+% ax = gca; ax.YDir = 'reverse';
+xlabel('Time (s) from local minimum')
+xlim([-100 100]); %ylim([-.03 .18])
+ylabel({'ERP';'(microVolts)'});
+xlabel({'Time (ms) from local minimum'});    
+set(findall(gcf,'-property','FontSize'),'FontSize',12)
+
+%% plot topography of frontal N1
+
+% set custom colormap
+cBrew = brewermap(500,'RdBu');
+cBrew = flipud(cBrew);
+colormap(cBrew)
+
+h = figure('units','centimeters','position',[0 0 10 10]);
+set(gcf,'renderer','Painters')
+
+cfg = [];
+cfg.layout = 'EEG1010.lay';
+cfg.parameter = 'powspctrm';
+cfg.comment = 'no';
+cfg.colormap = cBrew;
+cfg.colorbar = 'EastOutside';
+
+plotData = [];
+plotData.label = elec.label(1:64); % {1 x N}
+plotData.dimord = 'chan';
+plotData.powspctrm = squeeze(nanmean(nanmean(nanmin(mergeddata(:,:,time>0.08 & time <0.12,1:2),[],3),1),4))'; 
+%plotData.powspctrm = squeeze(nanmean(nanmean(nanmean(mergeddata(:,:,time>0.05 & time <0.1,1:2),3),1),4))'; 
+%plotData.powspctrm = squeeze(nanmean(nanmean(nanmean(mergeddata(:,:,time>0.1 & time <0.15,1:2),3),1),4))'; 
+[~, sortidx] = sort(plotData.powspctrm, 'ascend');
+idx_chans = sortidx(1:6);
+idx_chans_frontal = idx_chans;
+
+cfg.marker = 'off'; 
+cfg.highlight = 'yes';
+cfg.highlightchannel = plotData.label(idx_chans);
+cfg.highlightcolor = [1 0 0];
+cfg.highlightsymbol = '.';
+cfg.highlightsize = 18;
+cfg.zlim = [-6 6];%[-8 8]*10^-4; 
+cfg.figure = h;
+ft_topoplotER(cfg,plotData);
+cb = colorbar('location', 'EastOutside'); set(get(cb,'ylabel'),'string','Amplitude');
+
+%% visualize N1 over negative maximum
+
+% avg across channels and conditions
+condAvg = squeeze(nanmean(nanmean(mergeddata(:,idx_chans,:,1:2),2),4));
+
+h = figure('units','centimeters','position',[0 0 10 8]);
+cla; hold on;
+% new value = old value ? subject average + grand average
+curData = squeeze(nanmean(mergeddata(:,idx_chans,:,1),2));
+curData = curData-condAvg+repmat(nanmean(condAvg,1),size(condAvg,1),1);
+standError = nanstd(curData,1)./sqrt(size(curData,1));
+l1 = shadedErrorBar(time,nanmean(curData,1),standError, 'lineprops', {'color', 'k','linewidth', 2}, 'patchSaturation', .1);
+curData = squeeze(nanmean(mergeddata(:,idx_chans,:,2),2));
+curData = curData-condAvg+repmat(nanmean(condAvg,1),size(condAvg,1),1);
+standError = nanstd(curData,1)./sqrt(size(curData,1));
+l2 = shadedErrorBar(time,nanmean(curData,1),standError, 'lineprops', {'color', 'r','linewidth', 2}, 'patchSaturation', .1);
+% ax = gca; ax.YDir = 'reverse';
+xlabel('Time (s) from stim onset')
+xlim([-.05 .3]); %ylim([-.03 .18])
+ylabel({'ERP';'(microVolts)'});
+xlabel({'Time (s)'});    
+set(findall(gcf,'-property','FontSize'),'FontSize',12)
+
+%% plot both trajectories into same plot
+
+h = figure('units','centimeters','position',[0 0 10 8]);
+cla; hold on;
+% new value = old value ? subject average + grand average
+curData = squeeze(nanmean(nanmean(mergeddata(:,idx_chans_visual,:,1:2),2),4));
+standError = nanstd(curData,1)./sqrt(size(curData,1));
+l1 = shadedErrorBar(time,nanmean(curData,1),standError, 'lineprops', {'color', 'k','linewidth', 2}, 'patchSaturation', .1);
+curData = squeeze(nanmean(nanmean(mergeddata(:,idx_chans_frontal,:,1:2),2),4));
+standError = nanstd(curData,1)./sqrt(size(curData,1));
+l2 = shadedErrorBar(time,nanmean(curData,1),standError, 'lineprops', {'color', 'r','linewidth', 2}, 'patchSaturation', .1);
+% ax = gca; ax.YDir = 'reverse';
+xlabel('Time (s) from stim onset')
+xlim([-.025 .15]); %ylim([-.03 .18])
+ylabel({'ERP';'(microVolts)'});
+xlabel({'Time (s)'});    
+set(findall(gcf,'-property','FontSize'),'FontSize',12)
+
+%% plot difference between conditions
+
+h = figure('units','centimeters','position',[0 0 10 10]);
+set(gcf,'renderer','Painters')
+
+cfg = [];
+cfg.layout = 'biosemi64.lay';
+cfg.parameter = 'powspctrm';
+cfg.comment = 'no';
+cfg.colormap = cBrew;
+cfg.colorbar = 'EastOutside';
+
+plotData = [];
+plotData.label = elec.label(1:66); % {1 x N}
+plotData.dimord = 'chan';
+plotData.powspctrm = squeeze(nanmean(nanmean(nanmean(mergeddata(:,:,time>0.08 & time <0.12,2),3),1),4))'...
+    -squeeze(nanmean(nanmean(nanmean(mergeddata(:,:,time>0.08 & time <0.12,1),3),1),4))'; 
+[~, sortidx] = sort(plotData.powspctrm, 'ascend');
+idx_chans = sortidx(1:6);
+
+cfg.marker = 'off'; 
+cfg.highlight = 'yes';
+cfg.highlightchannel = plotData.label(idx_chans);
+cfg.highlightcolor = [1 0 0];
+cfg.highlightsymbol = '.';
+cfg.highlightsize = 18;
+%cfg.zlim = [-5 5]*10^-4; 
+cfg.figure = h;
+ft_topoplotER(cfg,plotData);
+cb = colorbar('location', 'EastOutside'); set(get(cb,'ylabel'),'string','Amplitude');
+
+
+%% visualize for negative pls channels
+
+%idx_chans = [28:30];
+condAvg = squeeze(nanmean(nanmean(mergeddata(:,idx_chans,:,1:2),2),4));
+
+h = figure('units','centimeters','position',[0 0 10 8]);
+cla; hold on;
+% new value = old value ? subject average + grand average
+curData = squeeze(nanmean(mergeddata(:,idx_chans,:,1),2));
+curData = curData-condAvg+repmat(nanmean(condAvg,1),size(condAvg,1),1);
+standError = nanstd(curData,1)./sqrt(size(curData,1));
+l1 = shadedErrorBar(time,nanmean(curData,1),standError, 'lineprops', {'color', 'k','linewidth', 2}, 'patchSaturation', .1);
+curData = squeeze(nanmean(mergeddata(:,idx_chans,:,2),2));
+curData = curData-condAvg+repmat(nanmean(condAvg,1),size(condAvg,1),1);
+standError = nanstd(curData,1)./sqrt(size(curData,1));
+l2 = shadedErrorBar(time,nanmean(curData,1),standError, 'lineprops', {'color', 'r','linewidth', 2}, 'patchSaturation', .1);
+xlabel('Time (s) from stim onset')
+xlim([-.2 1]); %ylim([-.03 .18])
+xlim([-.05 .3]);
+ylabel({'ERP';'(microVolts)'});
+xlabel({'Time (s)'});    
+set(findall(gcf,'-property','FontSize'),'FontSize',12)
+
+%% visualize for positive pls channels
+
+idx_chans = [21:23, 58:62];
+condAvg = squeeze(nanmean(nanmean(mergeddata(:,idx_chans,:,1:2),2),4));
+
+h = figure('units','centimeters','position',[0 0 10 8]);
+cla; hold on;
+% new value = old value ? subject average + grand average
+curData = squeeze(nanmean(mergeddata(:,idx_chans,:,1),2));
+curData = curData-condAvg+repmat(nanmean(condAvg,1),size(condAvg,1),1);
+standError = nanstd(curData,1)./sqrt(size(curData,1));
+l1 = shadedErrorBar(time,nanmean(curData,1),standError, 'lineprops', {'color', 'k','linewidth', 2}, 'patchSaturation', .1);
+curData = squeeze(nanmean(mergeddata(:,idx_chans,:,2),2));
+curData = curData-condAvg+repmat(nanmean(condAvg,1),size(condAvg,1),1);
+standError = nanstd(curData,1)./sqrt(size(curData,1));
+l2 = shadedErrorBar(time,nanmean(curData,1),standError, 'lineprops', {'color', 'r','linewidth', 2}, 'patchSaturation', .1);
+xlabel('Time (s) from stim onset')
+xlim([-.5 1]); %ylim([-.03 .18])
+xlim([-.05 .3]);
+ylabel({'ERP';'(microVolts)'});
+xlabel({'Time (s)'});    
+set(findall(gcf,'-property','FontSize'),'FontSize',12)
+
+%% visualize for frontal channels
+
+idx_chans = [37];%[4,38,39];
+condAvg = squeeze(nanmean(nanmean(mergeddata(:,idx_chans,:,1:2),2),4));
+
+h = figure('units','centimeters','position',[0 0 10 8]);
+cla; hold on;
+% new value = old value ? subject average + grand average
+curData = squeeze(nanmean(mergeddata(:,idx_chans,:,1),2));
+curData = curData-condAvg+repmat(nanmean(condAvg,1),size(condAvg,1),1);
+standError = nanstd(curData,1)./sqrt(size(curData,1));
+l1 = shadedErrorBar(time,nanmean(curData,1),standError, 'lineprops', {'color', 'k','linewidth', 2}, 'patchSaturation', .1);
+curData = squeeze(nanmean(mergeddata(:,idx_chans,:,2),2));
+curData = curData-condAvg+repmat(nanmean(condAvg,1),size(condAvg,1),1);
+standError = nanstd(curData,1)./sqrt(size(curData,1));
+l2 = shadedErrorBar(time,nanmean(curData,1),standError, 'lineprops', {'color', 'r','linewidth', 2}, 'patchSaturation', .1);
+xlabel('Time (s) from stim onset')
+xlim([-1 2]); %ylim([-.03 .18])
+ylabel({'ERP';'(microVolts)'});
+xlabel({'Time (s)'});    
+set(findall(gcf,'-property','FontSize'),'FontSize',12)
+
+%% visualize for all channels
+
+idx_chans = [1:66];
+condAvg = squeeze(nanmean(nanmean(mergeddata(:,idx_chans,:,1:2),2),4));
+
+h = figure('units','centimeters','position',[0 0 10 8]);
+cla; hold on;
+% new value = old value ? subject average + grand average
+curData = squeeze(nanmean(mergeddata(:,idx_chans,:,1),2));
+curData = curData-condAvg+repmat(nanmean(condAvg,1),size(condAvg,1),1);
+standError = nanstd(curData,1)./sqrt(size(curData,1));
+l1 = shadedErrorBar(time,nanmean(curData,1),standError, 'lineprops', {'color', 'k','linewidth', 2}, 'patchSaturation', .1);
+curData = squeeze(nanmean(mergeddata(:,idx_chans,:,2),2));
+curData = curData-condAvg+repmat(nanmean(condAvg,1),size(condAvg,1),1);
+standError = nanstd(curData,1)./sqrt(size(curData,1));
+l2 = shadedErrorBar(time,nanmean(curData,1),standError, 'lineprops', {'color', 'r','linewidth', 2}, 'patchSaturation', .1);
+xlabel('Time (s) from stim onset')
+xlim([-.2 1]); %ylim([-.03 .18])
+xlim([-.05 .3]);
+ylabel({'ERP';'(microVolts)'});
+xlabel({'Time (s)'});    
+set(findall(gcf,'-property','FontSize'),'FontSize',12)
+
+%% plot the ERPs
+
+manmade = erpgroup.scene_category.manmade;
+manmade.avg = squeeze(nanmean(manmade.avg,1));
+manmade.dimord = 'chan_time';
+
+natural = erpgroup.scene_category.natural;
+natural.avg = squeeze(nanmean(natural.avg,1));
+natural.dimord = 'chan_time';
+
+cfg = [];
+cfg.layout = 'biosemi64.lay';
+cfg.interactive = 'yes';
+cfg.showoutline = 'yes';
+cfg.xlim = [-.2 .3];
+ft_multiplotER(cfg, natural, manmade)

+ 106 - 0
code/unbaselined/d1_taskPLS_recognition_erp.m

@@ -0,0 +1,106 @@
+% Set up EEG PLS for a task PLS using spectral power
+
+clear all; cla; clc;
+
+currentFile = mfilename('fullpath');
+[pathstr,~,~] = fileparts(currentFile);
+cd(fullfile(pathstr,'..', '..'))
+rootpath = pwd;
+
+pn.data_eeg = fullfile(rootpath, '..', 'eegmp_preproc', 'data', 'outputs', 'eeg');
+pn.data_erp = fullfile(rootpath, 'data', 'erp');
+pn.data_erf = fullfile(rootpath, 'data', 'erf');
+pn.data = fullfile(rootpath, 'data', 'test'); mkdir(pn.data);
+pn.tools = fullfile(rootpath, 'tools');
+    addpath(fullfile(rootpath, '..', 'eegmp_preproc', 'tools', 'fieldtrip')); ft_defaults
+    addpath(genpath(fullfile(pn.tools, '[MEG]PLS', 'MEGPLS_PIPELINE_v2.02b')))
+    addpath(fullfile(pn.tools, 'BrewerMap'));
+    addpath(fullfile(pn.tools, 'shadedErrorBar'));
+
+%% add seed for reproducibility
+
+rng(0, 'twister');
+    
+%% load event info
+
+load(fullfile(pn.data_eeg, ['sub-001_task-xxxx_eeg_art.mat']), 'events');
+
+parameter = {'scene_category'; 'old'; 'behavior'; 'subsequent_memory'};
+for ind_param = 1:numel(parameter)
+    conds.(parameter{ind_param}) = unique(events.(parameter{ind_param}));
+end
+
+%% load erp
+
+for ind_id = 1:33
+    id = sprintf('sub-%03d', ind_id); disp(id)
+    load(fullfile(pn.data_erp, [id,'_erp.mat']));
+    for ind_option = 1:4%numel(conds.behavior)
+        if ind_id == 1
+             erpgroup.behavior.(conds.behavior{ind_option}) = erp.behavior{ind_option};
+             erpgroup.behavior.(conds.behavior{ind_option}) = ...
+                 rmfield(erpgroup.behavior.(conds.behavior{ind_option}), {'avg', 'var', 'dof'});
+             erpgroup.behavior.(conds.behavior{ind_option}).dimord = 'sub_chan_time';
+        end
+        erpgroup.behavior.(conds.behavior{ind_option}).avg(ind_id,:,:) = erp.behavior{ind_option}.avg;
+    end
+end
+
+time = erpgroup.behavior.hit.time;
+elec = erpgroup.behavior.hit.elec;
+channels = erpgroup.behavior.hit.label;
+
+mergeddata = cat(4, erpgroup.behavior.hit.avg, ...
+    erpgroup.behavior.miss.avg);
+
+num_chans = numel(channels);
+num_freqs = 1;
+num_time = numel(time);
+
+num_subj_lst = [33];
+num_cond = 2;
+num_grp = 1;
+
+datamat_lst = cell(num_grp); lv_evt_list = [];
+indCount_cont = 1;
+indCount = 1;
+indGroup = 1;
+for indCond = 1:num_cond
+    for indID = 1:num_subj_lst(indGroup)
+        datamat_lst{indGroup}(indCount,:) = reshape(squeeze(mergeddata(indID,:,:,indCond)), [], 1);
+        lv_evt_list(indCount_cont) = indCond;
+        indCount = indCount+1;
+        indCount_cont = indCount_cont+1;
+    end
+end
+datamat_lst{indGroup}(isnan(datamat_lst{indGroup})) = 0;
+
+%% set PLS options and run PLS
+
+option = [];
+option.method = 1; % [1] | 2 | 3 | 4 | 5 | 6
+option.num_perm = 1000; %( single non-negative integer )
+option.num_split = 0; %( single non-negative integer )
+option.num_boot = 1000; % ( single non-negative integer )
+option.cormode = 0; % [0] | 2 | 4 | 6
+option.meancentering_type = 0;% [0] | 1 | 2 | 3
+option.boot_type = 'strat'; %['strat'] | 'nonstrat'
+
+result = pls_analysis(datamat_lst, num_subj_lst, num_cond, option);
+
+%% rearrange into fieldtrip structure
+
+lvdat = reshape(result.boot_result.compare_u(:,1), num_chans, num_freqs, num_time);
+%udat = reshape(result.u, num_chans, num_freqs, num_time);
+
+stat = [];
+stat.prob = lvdat;
+stat.dimord = 'chan_freq_time';
+stat.clusters = [];
+stat.clusters.prob = result.perm_result.sprob; % check for significance of LV
+stat.mask = lvdat > 3 | lvdat < -3;
+stat.cfg = option;
+stat.time = time;
+
+save(fullfile(pn.data, 'd01_taskpls_erp.mat'),...
+    'stat', 'result', 'lvdat', 'lv_evt_list', 'num_chans', 'num_freqs', 'num_time')

+ 234 - 0
code/unbaselined/d1_taskPLS_recognition_erp_LV1.m

@@ -0,0 +1,234 @@
+% Create an overview plot featuring the results of the multivariate PLS
+% comparing spectral changes during the stimulus period under load
+
+clear all; cla; clc;
+
+currentFile = mfilename('fullpath');
+[pathstr,~,~] = fileparts(currentFile);
+cd(fullfile(pathstr,'..', '..'))
+rootpath = pwd;
+
+pn.data         = fullfile(rootpath, 'data', 'test');
+pn.figures      = fullfile(rootpath, 'figures');
+pn.tools        = fullfile(rootpath, 'tools');
+    addpath(genpath(fullfile(pn.tools, '[MEG]PLS', 'MEGPLS_PIPELINE_v2.02b')))
+    addpath(fullfile(pn.tools, 'fieldtrip')); ft_defaults;
+    addpath(genpath(fullfile(pn.tools, 'RainCloudPlots')));
+    addpath(fullfile(pn.tools, 'BrewerMap'));
+    addpath(fullfile(pn.tools, 'winsor'));
+
+% set custom colormap
+cBrew = brewermap(500,'RdBu');
+cBrew = flipud(cBrew);
+colormap(cBrew)
+
+load(fullfile(pn.data, 'd01_taskpls_erp.mat'),...
+    'stat', 'result', 'lvdat', 'lv_evt_list', 'num_chans', 'num_freqs', 'num_time')
+load(fullfile(rootpath, 'data','erp', ['sub-001_erp.mat']));
+elec = erp.scene_category{1}.elec;
+
+result.perm_result.sprob
+
+indLV = 1;
+
+lvdat = reshape(result.boot_result.compare_u(:,indLV), num_chans, num_freqs, num_time);
+stat.prob = lvdat;
+stat.mask = lvdat > 3 | lvdat < -3;
+
+% maskNaN = double(stat.mask);
+% maskNaN(maskNaN==0) = NaN;
+
+%% invert solution
+
+stat.mask = stat.mask;
+stat.prob = stat.prob.*-1;
+result.vsc = result.vsc.*-1;
+result.usc = result.usc.*-1;
+
+%% plot temporal loadings
+
+h = figure('units','centimeter','position',[0 0 10 10]);
+set(gcf,'renderer','Painters')
+hold on;
+
+% highlight relevant phase in background
+patches.timeVec = [.35 .55];
+patches.colorVec = [.8 .95 1];
+for indP = 1:size(patches.timeVec,2)-1
+    YLim = [-.5 .5];
+    p = patch([patches.timeVec(indP) patches.timeVec(indP+1) patches.timeVec(indP+1) patches.timeVec(indP)], ...
+                [YLim(1) YLim(1)  YLim(2), YLim(2)], patches.colorVec(indP,:));
+    p.EdgeColor = 'none';
+end
+
+
+% highlight relevant phase in background
+patches.timeVec = [.6 .8];
+patches.colorVec = [1 .95 .8];
+for indP = 1:size(patches.timeVec,2)-1
+    YLim = [-.5 .5];
+    p = patch([patches.timeVec(indP) patches.timeVec(indP+1) patches.timeVec(indP+1) patches.timeVec(indP)], ...
+                [YLim(1) YLim(1)  YLim(2), YLim(2)], patches.colorVec(indP,:));
+    p.EdgeColor = 'none';
+end
+
+% highlight relevant phase in background
+patches.timeVec = [1.2 1.7];
+patches.colorVec = [1 .8 .7];
+for indP = 1:size(patches.timeVec,2)-1
+    YLim = [-.5 .5];
+    p = patch([patches.timeVec(indP) patches.timeVec(indP+1) patches.timeVec(indP+1) patches.timeVec(indP)], ...
+                [YLim(1) YLim(1)  YLim(2), YLim(2)], patches.colorVec(indP,:));
+    p.EdgeColor = 'none';
+end
+
+statsPlot = [];
+statsPlot = cat(1, statsPlot,squeeze(nanmean(stat.mask(1:64,:,:).*stat.prob(1:64,:,:),1)));
+plot(stat.time,statsPlot, 'k')
+xlabel('Time [s from stim onset]'); ylabel('mean BSR');
+title({'ERP changes'; ['p = ', num2str(round(result.perm_result.sprob(indLV),4))]})
+set(findall(gcf,'-property','FontSize'),'FontSize',18)
+
+%% plot early positivity/negativity
+
+h = figure('units','centimeters','position',[0 0 10 10]);
+set(gcf,'renderer','Painters')
+
+cfg = [];
+cfg.layout = 'biosemi64.lay';
+cfg.parameter = 'powspctrm';
+cfg.comment = 'no';
+cfg.colormap = cBrew;
+cfg.colorbar = 'EastOutside';
+
+plotData = [];
+plotData.label = elec.label; % {1 x N}
+plotData.dimord = 'chan';
+cfg.zlim = [-4 4]; 
+cfg.figure = h;
+plotData.powspctrm = squeeze(nanmean(stat.mask(:,:,stat.time>.35 & stat.time<.55).*...
+    stat.prob(:,:,stat.time>.35 & stat.time<.55),3)); 
+ft_topoplotER(cfg,plotData);
+cb = colorbar('location', 'EastOutside'); set(get(cb,'ylabel'),'string','Mean BSR');
+
+%% plot later positivity
+
+h = figure('units','centimeters','position',[0 0 10 10]);
+set(gcf,'renderer','Painters')
+
+cfg = [];
+cfg.layout = 'biosemi64.lay';
+cfg.parameter = 'powspctrm';
+cfg.comment = 'no';
+cfg.colormap = cBrew;
+cfg.colorbar = 'EastOutside';
+
+plotData = [];
+plotData.label = elec.label; % {1 x N}
+plotData.dimord = 'chan';
+cfg.zlim = [-5 5]; 
+cfg.figure = h;
+plotData.powspctrm = squeeze(nanmean(stat.mask(:,:,stat.time>.6 & stat.time<.8).*...
+    stat.prob(:,:,stat.time>0.6 & stat.time<.8),3)); 
+ft_topoplotER(cfg,plotData);
+cb = colorbar('location', 'EastOutside'); set(get(cb,'ylabel'),'string','Mean BSR');
+
+%% plot late negativity
+
+h = figure('units','centimeters','position',[0 0 10 10]);
+set(gcf,'renderer','Painters')
+
+cfg = [];
+cfg.layout = 'biosemi64.lay';
+cfg.parameter = 'powspctrm';
+cfg.comment = 'no';
+cfg.colormap = cBrew;
+cfg.colorbar = 'EastOutside';
+
+plotData = [];
+plotData.label = elec.label; % {1 x N}
+plotData.dimord = 'chan';
+cfg.zlim = [-2 2]; 
+cfg.figure = h;
+plotData.powspctrm = squeeze(nanmean(stat.mask(:,:,stat.time>1.2 & stat.time<1.7).*...
+    stat.prob(:,:,stat.time>1.2 & stat.time<1.7),3)); 
+ft_topoplotER(cfg,plotData);
+cb = colorbar('location', 'EastOutside'); set(get(cb,'ylabel'),'string','Mean BSR');
+
+%% plot using raincloud plot
+
+groupsizes=result.num_subj_lst;
+conditions=lv_evt_list;
+conds = {'hit'; 'miss'};
+condData = []; uData = [];
+for indGroup = 1
+    if indGroup == 1
+        relevantEntries = 1:groupsizes(1)*numel(conds);
+    elseif indGroup == 2
+        relevantEntries = groupsizes(1)*numel(conds)+1:...
+             groupsizes(1)*numel(conds)+groupsizes(2)*numel(conds);
+    end
+    for indCond = 1:numel(conds)
+        targetEntries = relevantEntries(conditions(relevantEntries)==indCond);        
+        condData{indGroup}(indCond,:) = result.vsc(targetEntries,indLV);
+        uData{indGroup}(indCond,:) = result.usc(targetEntries,indLV);
+    end
+end
+
+cBrew(1,:) = 2.*[.3 .1 .1];
+cBrew(2,:) = [.6 .6 .6];
+
+idx_outlier = cell(1); idx_standard = cell(1);
+for indGroup = 1
+    dataToPlot = uData{indGroup}';
+    % define outlier as lin. modulation that is more than three scaled median absolute deviations (MAD) away from the median
+    X = [1 1; 1 2]; b=X\dataToPlot'; IndividualSlopes = b(2,:);
+    outliers = isoutlier(IndividualSlopes, 'median');
+    idx_outlier{indGroup} = find(outliers);
+    idx_standard{indGroup} = find(outliers==0);
+end
+
+h = figure('units','centimeter','position',[0 0 10 10]);
+for indGroup = 1
+    dataToPlot = uData{indGroup}';
+    % read into cell array of the appropriate dimensions
+    data = []; data_ws = [];
+    for i = 1:2
+        for j = 1:1
+            data{i, j} = dataToPlot(:,i);
+            % individually demean for within-subject visualization
+            data_ws{i, j} = dataToPlot(:,i)-...
+                nanmean(dataToPlot(:,:),2)+...
+                repmat(nanmean(nanmean(dataToPlot(:,:),2),1),size(dataToPlot(:,:),1),1);
+            data_nooutlier{i, j} = data{i, j};
+            data_nooutlier{i, j}(idx_outlier{indGroup}) = [];
+            data_ws_nooutlier{i, j} = data_ws{i, j};
+            data_ws_nooutlier{i, j}(idx_outlier{indGroup}) = [];
+            % sort outliers to back in original data for improved plot overlap
+            data_ws{i, j} = [data_ws{i, j}(idx_standard{indGroup}); data_ws{i, j}(idx_outlier{indGroup})];
+        end
+    end
+
+    % IMPORTANT: plot individually centered estimates, stats on uncentered estimates!
+
+    set(gcf,'renderer','Painters')
+        cla;
+        cl = cBrew(indGroup,:);
+        [~, dist] = rm_raincloud_fixedSpacing(data_ws, [.8 .8 .8],1);
+        h_rc = rm_raincloud_fixedSpacing(data_ws_nooutlier, cl,1,[],[],[],dist);
+        view([90 -90]);
+        axis ij
+    box(gca,'off')
+    set(gca, 'YTickLabels', {conds{2}; conds{1}});
+    yticks = get(gca, 'ytick'); ylim([yticks(1)-(yticks(2)-yticks(1))./2, yticks(2)+(yticks(2)-yticks(1))./1.5]);
+
+    minmax = [min(min(cat(2,data_ws{:}))), max(max(cat(2,data_ws{:})))];
+    xlim(minmax+[-0.2*diff(minmax), 0.2*diff(minmax)])
+    ylabel('recognition'); xlabel({'Brainscore'; '[Individually centered]'})
+
+    % test linear effect
+    curData = [data_nooutlier{1, 1}, data_nooutlier{2, 1}];
+    X = [1 1; 1 2]; b=X\curData'; IndividualSlopes = b(2,:);
+    [~, p, ci, stats] = ttest(IndividualSlopes);
+    title(['M:', num2str(round(mean(IndividualSlopes),3)), '; p=', num2str(round(p,3))])
+end

+ 106 - 0
code/unbaselined/e1_taskPLS_memory_erp.m

@@ -0,0 +1,106 @@
+% Set up EEG PLS for a task PLS using spectral power
+
+clear all; cla; clc;
+
+currentFile = mfilename('fullpath');
+[pathstr,~,~] = fileparts(currentFile);
+cd(fullfile(pathstr,'..', '..'))
+rootpath = pwd;
+
+pn.data_eeg = fullfile(rootpath, '..', 'eegmp_preproc', 'data', 'outputs', 'eeg');
+pn.data_erp = fullfile(rootpath, 'data', 'erp');
+pn.data_erf = fullfile(rootpath, 'data', 'erf');
+pn.data = fullfile(rootpath, 'data', 'test'); mkdir(pn.data);
+pn.tools = fullfile(rootpath, 'tools');
+    addpath(fullfile(rootpath, '..', 'eegmp_preproc', 'tools', 'fieldtrip')); ft_defaults
+    addpath(genpath(fullfile(pn.tools, '[MEG]PLS', 'MEGPLS_PIPELINE_v2.02b')))
+    addpath(fullfile(pn.tools, 'BrewerMap'));
+    addpath(fullfile(pn.tools, 'shadedErrorBar'));
+
+%% add seed for reproducibility
+
+rng(0, 'twister');
+    
+%% load event info
+
+load(fullfile(pn.data_eeg, ['sub-001_task-xxxx_eeg_art.mat']), 'events');
+
+parameter = {'scene_category'; 'old'; 'behavior'; 'subsequent_memory'};
+for ind_param = 1:numel(parameter)
+    conds.(parameter{ind_param}) = unique(events.(parameter{ind_param}));
+end
+
+%% load erp
+
+for ind_id = 1:33
+    id = sprintf('sub-%03d', ind_id); disp(id)
+    load(fullfile(pn.data_erp, [id,'_erp.mat']));
+    for ind_option = 2:3
+        if ind_id == 1
+             erpgroup.subsequent_memory.(conds.subsequent_memory{ind_option}) = erp.subsequent_memory{ind_option};
+             erpgroup.subsequent_memory.(conds.subsequent_memory{ind_option}) = ...
+                 rmfield(erpgroup.subsequent_memory.(conds.subsequent_memory{ind_option}), {'avg', 'var', 'dof'});
+             erpgroup.subsequent_memory.(conds.subsequent_memory{ind_option}).dimord = 'sub_chan_time';
+        end
+        erpgroup.subsequent_memory.(conds.subsequent_memory{ind_option}).avg(ind_id,:,:) = erp.subsequent_memory{ind_option}.avg;
+    end
+end
+
+time = erpgroup.subsequent_memory.subsequent_remembered.time;
+elec = erpgroup.subsequent_memory.subsequent_remembered.elec;
+channels = erpgroup.subsequent_memory.subsequent_remembered.label;
+
+mergeddata = cat(4, erpgroup.subsequent_memory.subsequent_forgotten.avg, ...
+    erpgroup.subsequent_memory.subsequent_remembered.avg);
+
+num_chans = numel(channels);
+num_freqs = 1;
+num_time = numel(time);
+
+num_subj_lst = [33];
+num_cond = 2;
+num_grp = 1;
+
+datamat_lst = cell(num_grp); lv_evt_list = [];
+indCount_cont = 1;
+indCount = 1;
+indGroup = 1;
+for indCond = 1:num_cond
+    for indID = 1:num_subj_lst(indGroup)
+        datamat_lst{indGroup}(indCount,:) = reshape(squeeze(mergeddata(indID,:,:,indCond)), [], 1);
+        lv_evt_list(indCount_cont) = indCond;
+        indCount = indCount+1;
+        indCount_cont = indCount_cont+1;
+    end
+end
+datamat_lst{indGroup}(isnan(datamat_lst{indGroup})) = 0;
+
+%% set PLS options and run PLS
+
+option = [];
+option.method = 1; % [1] | 2 | 3 | 4 | 5 | 6
+option.num_perm = 1000; %( single non-negative integer )
+option.num_split = 0; %( single non-negative integer )
+option.num_boot = 1000; % ( single non-negative integer )
+option.cormode = 0; % [0] | 2 | 4 | 6
+option.meancentering_type = 0;% [0] | 1 | 2 | 3
+option.boot_type = 'strat'; %['strat'] | 'nonstrat'
+
+result = pls_analysis(datamat_lst, num_subj_lst, num_cond, option);
+
+%% rearrange into fieldtrip structure
+
+lvdat = reshape(result.boot_result.compare_u(:,1), num_chans, num_freqs, num_time);
+%udat = reshape(result.u, num_chans, num_freqs, num_time);
+
+stat = [];
+stat.prob = lvdat;
+stat.dimord = 'chan_freq_time';
+stat.clusters = [];
+stat.clusters.prob = result.perm_result.sprob; % check for significance of LV
+stat.mask = lvdat > 3 | lvdat < -3;
+stat.cfg = option;
+stat.time = time;
+
+save(fullfile(pn.data, 'e01_taskpls_erp.mat'),...
+    'stat', 'result', 'lvdat', 'lv_evt_list', 'num_chans', 'num_freqs', 'num_time')

+ 192 - 0
code/unbaselined/e1_taskPLS_memory_erp_LV1.m

@@ -0,0 +1,192 @@
+% Create an overview plot featuring the results of the multivariate PLS
+% comparing spectral changes during the stimulus period under load
+
+clear all; cla; clc;
+
+currentFile = mfilename('fullpath');
+[pathstr,~,~] = fileparts(currentFile);
+cd(fullfile(pathstr,'..', '..'))
+rootpath = pwd;
+
+pn.data         = fullfile(rootpath, 'data', 'test');
+pn.figures      = fullfile(rootpath, 'figures');
+pn.tools        = fullfile(rootpath, 'tools');
+    addpath(genpath(fullfile(pn.tools, '[MEG]PLS', 'MEGPLS_PIPELINE_v2.02b')))
+    addpath(fullfile(pn.tools, 'fieldtrip')); ft_defaults;
+    addpath(genpath(fullfile(pn.tools, 'RainCloudPlots')));
+    addpath(fullfile(pn.tools, 'BrewerMap'));
+    addpath(fullfile(pn.tools, 'winsor'));
+
+% set custom colormap
+cBrew = brewermap(500,'RdBu');
+cBrew = flipud(cBrew);
+colormap(cBrew)
+
+load(fullfile(pn.data, 'e01_taskpls_erp.mat'),...
+    'stat', 'result', 'lvdat', 'lv_evt_list', 'num_chans', 'num_freqs', 'num_time')
+load(fullfile(rootpath, 'data','erp', ['sub-001_erp.mat']));
+elec = erp.scene_category{1}.elec;
+
+result.perm_result.sprob
+
+indLV = 1;
+
+lvdat = reshape(result.boot_result.compare_u(:,indLV), num_chans, num_freqs, num_time);
+stat.prob = lvdat;
+stat.mask = lvdat > 3 | lvdat < -3;
+
+% maskNaN = double(stat.mask);
+% maskNaN(maskNaN==0) = NaN;
+
+%% invert solution
+
+% stat.mask = stat.mask;
+% stat.prob = stat.prob.*-1;
+% result.vsc = result.vsc.*-1;
+% result.usc = result.usc.*-1;
+
+h = figure('units','centimeter','position',[0 0 15 10]);
+set(gcf,'renderer','Painters')
+hold on;
+statsPlot = [];
+statsPlot = cat(1, statsPlot,squeeze(nanmean(stat.mask(1:64,:,:).*stat.prob(1:64,:,:),1)));
+plot(stat.time,statsPlot, 'k')
+xlabel('Time [s from stim onset]'); ylabel('max abs BSR');
+title({'ERP changes'; ['p = ', num2str(round(result.perm_result.sprob(indLV),4))]})
+set(findall(gcf,'-property','FontSize'),'FontSize',18)
+
+% h = figure('units','centimeter','position',[0 0 15 10]);
+% set(gcf,'renderer','Painters')
+% statsPlot = [];
+% statsPlot = cat(1, statsPlot,squeeze(nanmax(abs(stat.prob(1:64,:,:)),[],1)));
+% plot(stat.time,statsPlot, 'k')
+% xlabel('Time [s from stim onset]'); ylabel('max abs BSR');
+% title({'ERP changes'; ['p = ', num2str(round(result.perm_result.sprob(indLV),4))]})
+% set(findall(gcf,'-property','FontSize'),'FontSize',18)
+% % figureName = ['b01_pls_traces'];
+% % saveas(h, fullfile(pn.figures, figureName), 'epsc');
+% % saveas(h, fullfile(pn.figures, figureName), 'png');
+
+%% plot multivariate topographies
+
+h = figure('units','centimeters','position',[0 0 10 10]);
+set(gcf,'renderer','Painters')
+
+cfg = [];
+cfg.layout = 'biosemi64.lay';
+cfg.parameter = 'powspctrm';
+cfg.comment = 'no';
+cfg.colormap = cBrew;
+cfg.colorbar = 'EastOutside';
+
+plotData = [];
+plotData.label = elec.label; % {1 x N}
+plotData.dimord = 'chan';
+cfg.zlim = [-2 2]; 
+cfg.figure = h;
+plotData.powspctrm = squeeze(nanmean(stat.mask(:,:,stat.time>.3 & stat.time<.5).*...
+    stat.prob(:,:,stat.time>.3 & stat.time<.5),3)); 
+ft_topoplotER(cfg,plotData);
+cb = colorbar('location', 'EastOutside'); set(get(cb,'ylabel'),'string','Mean BSR');
+
+h = figure('units','centimeters','position',[0 0 10 10]);
+set(gcf,'renderer','Painters')
+
+cfg = [];
+cfg.layout = 'biosemi64.lay';
+cfg.parameter = 'powspctrm';
+cfg.comment = 'no';
+cfg.colormap = cBrew;
+cfg.colorbar = 'EastOutside';
+
+plotData = [];
+plotData.label = elec.label; % {1 x N}
+plotData.dimord = 'chan';
+cfg.zlim = [-.5 .5]; 
+cfg.figure = h;
+plotData.powspctrm = squeeze(nanmean(stat.mask(:,:,:).*...
+    stat.prob(:,:,:),3)); 
+ft_topoplotER(cfg,plotData);
+cb = colorbar('location', 'EastOutside'); set(get(cb,'ylabel'),'string','Mean BSR');
+
+
+%% plot using raincloud plot
+
+groupsizes=result.num_subj_lst;
+conditions=lv_evt_list;
+conds = {'forgotten'; 'remembered'};
+condData = []; uData = [];
+for indGroup = 1
+    if indGroup == 1
+        relevantEntries = 1:groupsizes(1)*numel(conds);
+    elseif indGroup == 2
+        relevantEntries = groupsizes(1)*numel(conds)+1:...
+             groupsizes(1)*numel(conds)+groupsizes(2)*numel(conds);
+    end
+    for indCond = 1:numel(conds)
+        targetEntries = relevantEntries(conditions(relevantEntries)==indCond);        
+        condData{indGroup}(indCond,:) = result.vsc(targetEntries,indLV);
+        uData{indGroup}(indCond,:) = result.usc(targetEntries,indLV);
+    end
+end
+
+cBrew(1,:) = 2.*[.3 .1 .1];
+cBrew(2,:) = [.6 .6 .6];
+
+idx_outlier = cell(1); idx_standard = cell(1);
+for indGroup = 1
+    dataToPlot = uData{indGroup}';
+    % define outlier as lin. modulation that is more than three scaled median absolute deviations (MAD) away from the median
+    X = [1 1; 1 2]; b=X\dataToPlot'; IndividualSlopes = b(2,:);
+    outliers = isoutlier(IndividualSlopes, 'median');
+    idx_outlier{indGroup} = find(outliers);
+    idx_standard{indGroup} = find(outliers==0);
+end
+
+h = figure('units','centimeter','position',[0 0 10 8]);
+for indGroup = 1
+    dataToPlot = uData{indGroup}';
+    % read into cell array of the appropriate dimensions
+    data = []; data_ws = [];
+    for i = 1:2
+        for j = 1:1
+            data{i, j} = dataToPlot(:,i);
+            % individually demean for within-subject visualization
+            data_ws{i, j} = dataToPlot(:,i)-...
+                nanmean(dataToPlot(:,:),2)+...
+                repmat(nanmean(nanmean(dataToPlot(:,:),2),1),size(dataToPlot(:,:),1),1);
+            data_nooutlier{i, j} = data{i, j};
+            data_nooutlier{i, j}(idx_outlier{indGroup}) = [];
+            data_ws_nooutlier{i, j} = data_ws{i, j};
+            data_ws_nooutlier{i, j}(idx_outlier{indGroup}) = [];
+            % sort outliers to back in original data for improved plot overlap
+            data_ws{i, j} = [data_ws{i, j}(idx_standard{indGroup}); data_ws{i, j}(idx_outlier{indGroup})];
+        end
+    end
+
+    % IMPORTANT: plot individually centered estimates, stats on uncentered estimates!
+
+    set(gcf,'renderer','Painters')
+        cla;
+        cl = cBrew(indGroup,:);
+        [~, dist] = rm_raincloud_fixedSpacing(data_ws, [.8 .8 .8],1);
+        h_rc = rm_raincloud_fixedSpacing(data_ws_nooutlier, cl,1,[],[],[],dist);
+        view([90 -90]);
+        axis ij
+    box(gca,'off')
+    set(gca, 'YTickLabels', {conds{2}; conds{1}});
+    yticks = get(gca, 'ytick'); ylim([yticks(1)-(yticks(2)-yticks(1))./2, yticks(2)+(yticks(2)-yticks(1))./1.5]);
+
+    minmax = [min(min(cat(2,data_ws{:}))), max(max(cat(2,data_ws{:})))];
+    xlim(minmax+[-0.2*diff(minmax), 0.2*diff(minmax)])
+    ylabel('scene category'); xlabel({'Brainscore'; '[Individually centered]'})
+
+    % test linear effect
+    curData = [data_nooutlier{1, 1}, data_nooutlier{2, 1}];
+    X = [1 1; 1 2]; b=X\curData'; IndividualSlopes = b(2,:);
+    [~, p, ci, stats] = ttest(IndividualSlopes);
+    %title(['M:', num2str(round(mean(IndividualSlopes),3)), '; p=', num2str(round(p,3))])
+    title(['M:', num2str(round(mean(IndividualSlopes),3)), '; p=', num2str(round(result.perm_result.sprob(indLV),3))])
+end
+
+set(findall(gcf,'-property','FontSize'),'FontSize',14)

+ 109 - 0
code/z_archive/b1_taskPLS_scenecat_N1.m

@@ -0,0 +1,109 @@
+% Set up EEG PLS for a task PLS using spectral power
+
+clear all; cla; clc;
+
+currentFile = mfilename('fullpath');
+[pathstr,~,~] = fileparts(currentFile);
+cd(fullfile(pathstr,'..'))
+rootpath = pwd;
+
+pn.data_eeg = fullfile(rootpath, '..', 'eegmp_preproc', 'data', 'outputs', 'eeg');
+pn.data_erp = fullfile(rootpath, 'data', 'erp');
+pn.data_erf = fullfile(rootpath, 'data', 'erf');
+pn.data = fullfile(rootpath, 'data', 'stats'); mkdir(pn.data);
+pn.tools = fullfile(rootpath, 'tools');
+    addpath(fullfile(rootpath, '..', 'eegmp_preproc', 'tools', 'fieldtrip')); ft_defaults
+    addpath(genpath(fullfile(pn.tools, '[MEG]PLS', 'MEGPLS_PIPELINE_v2.02b')))
+    addpath(fullfile(pn.tools, 'BrewerMap'));
+    addpath(fullfile(pn.tools, 'shadedErrorBar'));
+
+%% add seed for reproducibility
+
+rng(0, 'twister');
+    
+%% load event info
+
+load(fullfile(pn.data_eeg, ['sub-001_task-xxxx_eeg_art.mat']), 'events');
+
+parameter = {'scene_category'; 'old'; 'behavior'; 'subsequent_memory'};
+for ind_param = 1:numel(parameter)
+    conds.(parameter{ind_param}) = unique(events.(parameter{ind_param}));
+end
+
+%% load erp
+
+for ind_id = 1:33
+    id = sprintf('sub-%03d', ind_id);
+    load(fullfile(pn.data_erp, [id,'_erp_bl.mat']));
+    for ind_option = 1:numel(conds.scene_category)
+        if ind_id == 1
+             erpgroup.scene_category.(conds.scene_category{ind_option}) = erp_bl.scene_category{ind_option};
+             erpgroup.scene_category.(conds.scene_category{ind_option}) = ...
+                 rmfield(erpgroup.scene_category.(conds.scene_category{ind_option}), {'avg', 'var', 'dof'});
+             erpgroup.scene_category.(conds.scene_category{ind_option}).dimord = 'sub_chan_time';
+        end
+        % only include time points from 0 to 300 ms
+        time = erp_bl.scene_category{ind_option}.time;
+        toi = time >0 & time <0.3;        
+        erpgroup.scene_category.(conds.scene_category{ind_option}).avg(ind_id,:,:) = erp_bl.scene_category{ind_option}.avg(:,toi);
+    end
+end
+
+time = erpgroup.scene_category.manmade.time(toi);
+elec = erpgroup.scene_category.manmade.elec;
+channels = erpgroup.scene_category.manmade.label;
+
+mergeddata = cat(4, erpgroup.scene_category.manmade.avg, ...
+    erpgroup.scene_category.natural.avg);
+
+num_chans = numel(channels);
+num_freqs = 1;
+num_time = numel(time);
+
+num_subj_lst = [33];
+num_cond = 2;
+num_grp = 1;
+
+datamat_lst = cell(num_grp); lv_evt_list = [];
+indCount_cont = 1;
+indCount = 1;
+indGroup = 1;
+for indCond = 1:num_cond
+    for indID = 1:num_subj_lst(indGroup)
+        datamat_lst{indGroup}(indCount,:) = reshape(squeeze(mergeddata(indID,:,:,indCond)), [], 1);
+        lv_evt_list(indCount_cont) = indCond;
+        indCount = indCount+1;
+        indCount_cont = indCount_cont+1;
+    end
+end
+datamat_lst{indGroup}(isnan(datamat_lst{indGroup})) = 0;
+
+%% set PLS options and run PLS
+
+option = [];
+option.method = 1; % [1] | 2 | 3 | 4 | 5 | 6
+option.num_perm = 1000; %( single non-negative integer )
+option.num_split = 0; %( single non-negative integer )
+option.num_boot = 1000; % ( single non-negative integer )
+option.cormode = 0; % [0] | 2 | 4 | 6
+option.meancentering_type = 0;% [0] | 1 | 2 | 3
+option.boot_type = 'strat'; %['strat'] | 'nonstrat'
+
+result = pls_analysis(datamat_lst, num_subj_lst, num_cond, option);
+
+%% rearrange into fieldtrip structure
+
+lvdat = reshape(result.boot_result.compare_u(:,1), num_chans, num_freqs, num_time);
+%udat = reshape(result.u, num_chans, num_freqs, num_time);
+
+stat = [];
+stat.prob = lvdat;
+stat.dimord = 'chan_freq_time';
+stat.clusters = [];
+stat.clusters.prob = result.perm_result.sprob; % check for significance of LV
+stat.mask = lvdat > 3 | lvdat < -3;
+stat.cfg = option;
+stat.time = time;
+
+save(fullfile(pn.data, 'b01_taskpls_erp.mat'),...
+    'stat', 'result', 'lvdat', 'lv_evt_list', 'num_chans', 'num_freqs', 'num_time')

+ 111 - 0
code/z_archive/b1_taskPLS_scenecat_N1_avg.m

@@ -0,0 +1,111 @@
+% Set up EEG PLS for a task PLS using spectral power
+
+clear all; cla; clc;
+
+currentFile = mfilename('fullpath');
+[pathstr,~,~] = fileparts(currentFile);
+cd(fullfile(pathstr,'..'))
+rootpath = pwd;
+
+pn.data_eeg = fullfile(rootpath, '..', 'eegmp_preproc', 'data', 'outputs', 'eeg');
+pn.data_erp = fullfile(rootpath, 'data', 'erp');
+pn.data_erf = fullfile(rootpath, 'data', 'erf');
+pn.data = fullfile(rootpath, 'data', 'stats'); mkdir(pn.data);
+pn.tools = fullfile(rootpath, 'tools');
+    addpath(fullfile(rootpath, '..', 'eegmp_preproc', 'tools', 'fieldtrip')); ft_defaults
+    addpath(genpath(fullfile(pn.tools, '[MEG]PLS', 'MEGPLS_PIPELINE_v2.02b')))
+    addpath(fullfile(pn.tools, 'BrewerMap'));
+    addpath(fullfile(pn.tools, 'shadedErrorBar'));
+
+%% add seed for reproducibility
+
+rng(0, 'twister');
+    
+%% load event info
+
+load(fullfile(pn.data_eeg, ['sub-001_task-xxxx_eeg_art.mat']), 'events');
+
+parameter = {'scene_category'; 'old'; 'behavior'; 'subsequent_memory'};
+for ind_param = 1:numel(parameter)
+    conds.(parameter{ind_param}) = unique(events.(parameter{ind_param}));
+end
+
+%% load erp
+
+for ind_id = 1:33
+    id = sprintf('sub-%03d', ind_id);
+    load(fullfile(pn.data_erp, [id,'_erp.mat']));
+    for ind_option = 1:numel(conds.scene_category)
+        if ind_id == 1
+             erpgroup.scene_category.(conds.scene_category{ind_option}) = erp.scene_category{ind_option};
+             erpgroup.scene_category.(conds.scene_category{ind_option}) = ...
+                 rmfield(erpgroup.scene_category.(conds.scene_category{ind_option}), {'avg', 'var', 'dof'});
+             erpgroup.scene_category.(conds.scene_category{ind_option}).dimord = 'sub_chan_time';
+        end
+        % average in N1 time window
+        time = erpgroup.scene_category.(conds.scene_category{ind_option}).time;
+        toi = time >0.08 & time <0.12;
+        erpgroup.scene_category.(conds.scene_category{ind_option}).avg(ind_id,:,:) = nanmean(erp.scene_category{ind_option}.avg(:,toi),2);
+    end
+end
+
+% average in N1 time window
+
+time = 0.1;
+elec = erpgroup.scene_category.manmade.elec;
+channels = erpgroup.scene_category.manmade.label;
+
+mergeddata = cat(4, erpgroup.scene_category.manmade.avg, ...
+    erpgroup.scene_category.natural.avg);
+
+num_chans = numel(channels);
+num_freqs = 1;
+num_time = numel(time);
+
+num_subj_lst = [33];
+num_cond = 2;
+num_grp = 1;
+
+datamat_lst = cell(num_grp); lv_evt_list = [];
+indCount_cont = 1;
+indCount = 1;
+indGroup = 1;
+for indCond = 1:num_cond
+    for indID = 1:num_subj_lst(indGroup)
+        datamat_lst{indGroup}(indCount,:) = reshape(squeeze(mergeddata(indID,:,:,indCond)), [], 1);
+        lv_evt_list(indCount_cont) = indCond;
+        indCount = indCount+1;
+        indCount_cont = indCount_cont+1;
+    end
+end
+datamat_lst{indGroup}(isnan(datamat_lst{indGroup})) = 0;
+
+%% set PLS options and run PLS
+
+option = [];
+option.method = 1; % [1] | 2 | 3 | 4 | 5 | 6
+option.num_perm = 1000; %( single non-negative integer )
+option.num_split = 0; %( single non-negative integer )
+option.num_boot = 1000; % ( single non-negative integer )
+option.cormode = 0; % [0] | 2 | 4 | 6
+option.meancentering_type = 0;% [0] | 1 | 2 | 3
+option.boot_type = 'strat'; %['strat'] | 'nonstrat'
+
+result = pls_analysis(datamat_lst, num_subj_lst, num_cond, option);
+
+%% rearrange into fieldtrip structure
+
+lvdat = reshape(result.boot_result.compare_u(:,1), num_chans, num_freqs, num_time);
+%udat = reshape(result.u, num_chans, num_freqs, num_time);
+
+stat = [];
+stat.prob = lvdat;
+stat.dimord = 'chan_freq_time';
+stat.clusters = [];
+stat.clusters.prob = result.perm_result.sprob; % check for significance of LV
+stat.mask = lvdat > 3 | lvdat < -3;
+stat.cfg = option;
+stat.time = time;
+
+save(fullfile(pn.data, 'b01_taskpls_erp_avg.mat'),...
+    'stat', 'result', 'lvdat', 'lv_evt_list', 'num_chans', 'num_freqs', 'num_time')

+ 153 - 0
code/z_archive/b1_taskPLS_scenecat_N1_avg_plotLV1.m

@@ -0,0 +1,153 @@
+% Create an overview plot featuring the results of the multivariate PLS
+% comparing spectral changes during the stimulus period under load
+
+clear all; cla; clc;
+
+currentFile = mfilename('fullpath');
+[pathstr,~,~] = fileparts(currentFile);
+cd(fullfile(pathstr,'..'))
+rootpath = pwd;
+
+pn.data         = fullfile(rootpath, 'data', 'stats');
+pn.figures      = fullfile(rootpath, 'figures');
+pn.tools        = fullfile(rootpath, 'tools');
+    addpath(genpath(fullfile(pn.tools, '[MEG]PLS', 'MEGPLS_PIPELINE_v2.02b')))
+    addpath(fullfile(pn.tools, 'fieldtrip')); ft_defaults;
+    addpath(genpath(fullfile(pn.tools, 'RainCloudPlots')));
+    addpath(fullfile(pn.tools, 'BrewerMap'));
+    addpath(fullfile(pn.tools, 'winsor'));
+
+% set custom colormap
+cBrew = brewermap(500,'RdBu');
+cBrew = flipud(cBrew);
+colormap(cBrew)
+
+load(fullfile(pn.data, 'b01_taskpls_erp_avg.mat'),...
+    'stat', 'result', 'lvdat', 'lv_evt_list', 'num_chans', 'num_freqs', 'num_time')
+load(fullfile(rootpath, 'data','erp', ['sub-001_erp.mat']));
+elec = erp.scene_category{1}.elec;
+
+result.perm_result.sprob
+
+indLV = 1;
+
+lvdat = reshape(result.boot_result.compare_u(:,indLV), num_chans, num_freqs, num_time);
+stat.prob = lvdat;
+stat.mask = lvdat > 3 | lvdat < -3;
+
+% maskNaN = double(stat.mask);
+% maskNaN(maskNaN==0) = NaN;
+
+%% plot multivariate topographies
+
+h = figure('units','centimeters','position',[0 0 10 10]);
+set(gcf,'renderer','Painters')
+
+cfg = [];
+cfg.layout = 'biosemi64.lay';
+cfg.parameter = 'powspctrm';
+cfg.comment = 'no';
+cfg.colormap = cBrew;
+cfg.colorbar = 'EastOutside';
+
+plotData = [];
+plotData.label = elec.label; % {1 x N}
+plotData.dimord = 'chan';
+cfg.zlim = [-6 6]; 
+cfg.figure = h;
+plotData.powspctrm = squeeze(stat.mask.*stat.prob); 
+ft_topoplotER(cfg,plotData);
+cb = colorbar('location', 'EastOutside'); set(get(cb,'ylabel'),'string','Mean BSR');
+figureName = ['b01_lv1'];
+% saveas(h, fullfile(pn.figures, figureName), 'epsc');
+% saveas(h, fullfile(pn.figures, figureName), 'png');
+
+%% plot using raincloud plot
+
+groupsizes=result.num_subj_lst;
+conditions=lv_evt_list;
+conds = {'manmade'; 'natural'};
+condData = []; uData = [];
+for indGroup = 1
+    if indGroup == 1
+        relevantEntries = 1:groupsizes(1)*numel(conds);
+    elseif indGroup == 2
+        relevantEntries = groupsizes(1)*numel(conds)+1:...
+             groupsizes(1)*numel(conds)+groupsizes(2)*numel(conds);
+    end
+    for indCond = 1:numel(conds)
+        targetEntries = relevantEntries(conditions(relevantEntries)==indCond);        
+        condData{indGroup}(indCond,:) = result.vsc(targetEntries,indLV);
+        uData{indGroup}(indCond,:) = result.usc(targetEntries,indLV);
+    end
+end
+
+%% plot RainCloudPlot (within-subject centered)
+
+cBrew(1,:) = 2.*[.3 .1 .1];
+cBrew(2,:) = [.6 .6 .6];
+
+idx_outlier = cell(1); idx_standard = cell(1);
+for indGroup = 1
+    dataToPlot = uData{indGroup}';
+    % define outlier as lin. modulation that is more than three scaled median absolute deviations (MAD) away from the median
+    X = [1 1; 1 2]; b=X\dataToPlot'; IndividualSlopes = b(2,:);
+    outliers = isoutlier(IndividualSlopes, 'median');
+    idx_outlier{indGroup} = find(outliers);
+    idx_standard{indGroup} = find(outliers==0);
+end
+
+h = figure('units','centimeter','position',[0 0 25 10]);
+for indGroup = 1
+    dataToPlot = uData{indGroup}';
+    % read into cell array of the appropriate dimensions
+    data = []; data_ws = [];
+    for i = 1:2
+        for j = 1:1
+            data{i, j} = dataToPlot(:,i);
+            % individually demean for within-subject visualization
+            data_ws{i, j} = dataToPlot(:,i)-...
+                nanmean(dataToPlot(:,:),2)+...
+                repmat(nanmean(nanmean(dataToPlot(:,:),2),1),size(dataToPlot(:,:),1),1);
+            data_nooutlier{i, j} = data{i, j};
+            data_nooutlier{i, j}(idx_outlier{indGroup}) = [];
+            data_ws_nooutlier{i, j} = data_ws{i, j};
+            data_ws_nooutlier{i, j}(idx_outlier{indGroup}) = [];
+            % sort outliers to back in original data for improved plot overlap
+            data_ws{i, j} = [data_ws{i, j}(idx_standard{indGroup}); data_ws{i, j}(idx_outlier{indGroup})];
+        end
+    end
+
+    % IMPORTANT: plot individually centered estimates, stats on uncentered estimates!
+
+    subplot(1,2,indGroup);
+    set(gcf,'renderer','Painters')
+        cla;
+        cl = cBrew(indGroup,:);
+        [~, dist] = rm_raincloud_fixedSpacing(data_ws, [.8 .8 .8],1);
+        h_rc = rm_raincloud_fixedSpacing(data_ws_nooutlier, cl,1,[],[],[],dist);
+        view([90 -90]);
+        axis ij
+    box(gca,'off')
+    set(gca, 'YTickLabels', {'natural'; 'manmade'});
+    yticks = get(gca, 'ytick'); ylim([yticks(1)-(yticks(2)-yticks(1))./2, yticks(2)+(yticks(2)-yticks(1))./1.5]);
+
+    minmax = [min(min(cat(2,data_ws{:}))), max(max(cat(2,data_ws{:})))];
+    xlim(minmax+[-0.2*diff(minmax), 0.2*diff(minmax)])
+    ylabel('scene category'); xlabel({'Brainscore'; '[Individually centered]'})
+
+    % test linear effect
+    curData = [data_nooutlier{1, 1}, data_nooutlier{2, 1}];
+    X = [1 1; 1 2]; b=X\curData'; IndividualSlopes = b(2,:);
+    [~, p, ci, stats] = ttest(IndividualSlopes);
+    title(['M:', num2str(round(mean(IndividualSlopes),3)), '; p=', num2str(round(p,3))])
+end
+figureName = ['b01_rcp'];
+% saveas(h, fullfile(pn.figures, figureName), 'epsc');
+% saveas(h, fullfile(pn.figures, figureName), 'png');
+
+
+%% get channels to visualize
+
+positive = find(squeeze(stat.mask.*stat.prob)>0);
+negative = find(squeeze(stat.mask.*stat.prob)<0);

+ 181 - 0
code/z_archive/b1_taskPLS_scenecat_N1_plotLV1.m

@@ -0,0 +1,181 @@
+% Create an overview plot featuring the results of the multivariate PLS
+% comparing spectral changes during the stimulus period under load
+
+clear all; cla; clc;
+
+currentFile = mfilename('fullpath');
+[pathstr,~,~] = fileparts(currentFile);
+cd(fullfile(pathstr,'..'))
+rootpath = pwd;
+
+pn.data         = fullfile(rootpath, 'data', 'stats');
+pn.figures      = fullfile(rootpath, 'figures');
+pn.tools        = fullfile(rootpath, 'tools');
+    addpath(genpath(fullfile(pn.tools, '[MEG]PLS', 'MEGPLS_PIPELINE_v2.02b')))
+    addpath(fullfile(pn.tools, 'fieldtrip')); ft_defaults;
+    addpath(genpath(fullfile(pn.tools, 'RainCloudPlots')));
+    addpath(fullfile(pn.tools, 'BrewerMap'));
+    addpath(fullfile(pn.tools, 'winsor'));
+
+% set custom colormap
+cBrew = brewermap(500,'RdBu');
+cBrew = flipud(cBrew);
+colormap(cBrew)
+
+load(fullfile(pn.data, 'b01_taskpls_erp.mat'),...
+    'stat', 'result', 'lvdat', 'lv_evt_list', 'num_chans', 'num_freqs', 'num_time')
+load(fullfile(rootpath, 'data','erp', ['sub-001_erp.mat']));
+elec = erp.scene_category{1}.elec;
+
+result.perm_result.sprob
+
+indLV = 1;
+
+lvdat = reshape(result.boot_result.compare_u(:,indLV), num_chans, num_freqs, num_time);
+stat.prob = lvdat;
+stat.mask = lvdat > 3 | lvdat < -3;
+
+% maskNaN = double(stat.mask);
+% maskNaN(maskNaN==0) = NaN;
+
+%% invert solution
+
+% stat.mask = stat.mask;
+% stat.prob = stat.prob.*-1;
+% result.vsc = result.vsc.*-1;
+% result.usc = result.usc.*-1;
+
+h = figure('units','centimeter','position',[0 0 15 10]);
+set(gcf,'renderer','Painters')
+statsPlot = [];
+statsPlot = cat(1, statsPlot,squeeze(nanmax(abs(stat.prob(1:64,:,:)),[],1)));
+plot(stat.time,statsPlot, 'k')
+xlabel('Time [s from stim onset]'); ylabel('max abs BSR');
+title({'ERP changes'; ['p = ', num2str(round(result.perm_result.sprob(indLV),4))]})
+set(findall(gcf,'-property','FontSize'),'FontSize',18)
+figureName = ['b01_pls_traces'];
+saveas(h, fullfile(pn.figures, figureName), 'epsc');
+saveas(h, fullfile(pn.figures, figureName), 'png');
+
+
+h = figure('units','centimeter','position',[0 0 15 10]);
+set(gcf,'renderer','Painters')
+statsPlot = [];
+statsPlot = cat(1, statsPlot,squeeze(mean(stat.prob(1:64,:,:),1)));
+plot(stat.time,statsPlot, 'k')
+xlabel('Time [s from stim onset]'); ylabel('mean BSR');
+title({'ERP changes'; ['p = ', num2str(round(result.perm_result.sprob(indLV),4))]})
+set(findall(gcf,'-property','FontSize'),'FontSize',18)
+xlim([0 0.3])
+figureName = ['b01_pls_traces'];
+saveas(h, fullfile(pn.figures, figureName), 'epsc');
+saveas(h, fullfile(pn.figures, figureName), 'png');
+
+%% plot multivariate topographies
+
+h = figure('units','centimeters','position',[0 0 10 10]);
+set(gcf,'renderer','Painters')
+
+cfg = [];
+cfg.layout = 'biosemi64.lay';
+cfg.parameter = 'powspctrm';
+cfg.comment = 'no';
+cfg.colormap = cBrew;
+cfg.colorbar = 'EastOutside';
+
+plotData = [];
+plotData.label = elec.label; % {1 x N}
+plotData.dimord = 'chan';
+cfg.zlim = [-6 6]; 
+cfg.figure = h;
+plotData.powspctrm = squeeze(nanmean(stat.mask(:,:,stat.time >0.08 & stat.time <0.12).*...
+    stat.prob(:,:,stat.time >0.08 & stat.time <0.12),3)); 
+ft_topoplotER(cfg,plotData);
+cb = colorbar('location', 'EastOutside'); set(get(cb,'ylabel'),'string','Mean BSR');
+figureName = ['b01_lv1'];
+% saveas(h, fullfile(pn.figures, figureName), 'epsc');
+% saveas(h, fullfile(pn.figures, figureName), 'png');
+
+%% plot using raincloud plot
+
+groupsizes=result.num_subj_lst;
+conditions=lv_evt_list;
+conds = {'manmade'; 'natural'};
+condData = []; uData = [];
+for indGroup = 1
+    if indGroup == 1
+        relevantEntries = 1:groupsizes(1)*numel(conds);
+    elseif indGroup == 2
+        relevantEntries = groupsizes(1)*numel(conds)+1:...
+             groupsizes(1)*numel(conds)+groupsizes(2)*numel(conds);
+    end
+    for indCond = 1:numel(conds)
+        targetEntries = relevantEntries(conditions(relevantEntries)==indCond);        
+        condData{indGroup}(indCond,:) = result.vsc(targetEntries,indLV);
+        uData{indGroup}(indCond,:) = result.usc(targetEntries,indLV);
+    end
+end
+
+%% plot RainCloudPlot (within-subject centered)
+
+cBrew(1,:) = 2.*[.3 .1 .1];
+cBrew(2,:) = [.6 .6 .6];
+
+idx_outlier = cell(1); idx_standard = cell(1);
+for indGroup = 1
+    dataToPlot = uData{indGroup}';
+    % define outlier as lin. modulation that is more than three scaled median absolute deviations (MAD) away from the median
+    X = [1 1; 1 2]; b=X\dataToPlot'; IndividualSlopes = b(2,:);
+    outliers = isoutlier(IndividualSlopes, 'median');
+    idx_outlier{indGroup} = find(outliers);
+    idx_standard{indGroup} = find(outliers==0);
+end
+
+h = figure('units','centimeter','position',[0 0 25 10]);
+for indGroup = 1
+    dataToPlot = uData{indGroup}';
+    % read into cell array of the appropriate dimensions
+    data = []; data_ws = [];
+    for i = 1:2
+        for j = 1:1
+            data{i, j} = dataToPlot(:,i);
+            % individually demean for within-subject visualization
+            data_ws{i, j} = dataToPlot(:,i)-...
+                nanmean(dataToPlot(:,:),2)+...
+                repmat(nanmean(nanmean(dataToPlot(:,:),2),1),size(dataToPlot(:,:),1),1);
+            data_nooutlier{i, j} = data{i, j};
+            data_nooutlier{i, j}(idx_outlier{indGroup}) = [];
+            data_ws_nooutlier{i, j} = data_ws{i, j};
+            data_ws_nooutlier{i, j}(idx_outlier{indGroup}) = [];
+            % sort outliers to back in original data for improved plot overlap
+            data_ws{i, j} = [data_ws{i, j}(idx_standard{indGroup}); data_ws{i, j}(idx_outlier{indGroup})];
+        end
+    end
+
+    % IMPORTANT: plot individually centered estimates, stats on uncentered estimates!
+
+    subplot(1,2,indGroup);
+    set(gcf,'renderer','Painters')
+        cla;
+        cl = cBrew(indGroup,:);
+        [~, dist] = rm_raincloud_fixedSpacing(data_ws, [.8 .8 .8],1);
+        h_rc = rm_raincloud_fixedSpacing(data_ws_nooutlier, cl,1,[],[],[],dist);
+        view([90 -90]);
+        axis ij
+    box(gca,'off')
+    set(gca, 'YTickLabels', {'natural'; 'manmade'});
+    yticks = get(gca, 'ytick'); ylim([yticks(1)-(yticks(2)-yticks(1))./2, yticks(2)+(yticks(2)-yticks(1))./1.5]);
+
+    minmax = [min(min(cat(2,data_ws{:}))), max(max(cat(2,data_ws{:})))];
+    xlim(minmax+[-0.2*diff(minmax), 0.2*diff(minmax)])
+    ylabel('scene category'); xlabel({'Brainscore'; '[Individually centered]'})
+
+    % test linear effect
+    curData = [data_nooutlier{1, 1}, data_nooutlier{2, 1}];
+    X = [1 1; 1 2]; b=X\curData'; IndividualSlopes = b(2,:);
+    [~, p, ci, stats] = ttest(IndividualSlopes);
+    title(['M:', num2str(round(mean(IndividualSlopes),3)), '; p=', num2str(round(p,3))])
+end
+figureName = ['b01_rcp'];
+% saveas(h, fullfile(pn.figures, figureName), 'epsc');
+% saveas(h, fullfile(pn.figures, figureName), 'png');

+ 156 - 0
code/z_archive/b2a_taskPLS_novelty_frontal_erp_plot_trace_tmp.m

@@ -0,0 +1,156 @@
+
+currentFile = mfilename('fullpath');
+[pathstr,~,~] = fileparts(currentFile);
+cd(fullfile(pathstr,'..'))
+rootpath = pwd;
+
+pn.data_eeg = fullfile(rootpath, '..', 'eegmp_preproc', 'data', 'outputs', 'eeg');
+pn.data_erp = fullfile(rootpath, 'data', 'erp');
+pn.data_erf = fullfile(rootpath, 'data', 'erf');
+pn.tools = fullfile(rootpath, 'tools');
+    addpath(fullfile(rootpath, '..', 'eegmp_preproc', 'tools', 'fieldtrip')); ft_defaults
+    addpath(fullfile(pn.tools, 'BrewerMap'));
+    addpath(fullfile(pn.tools, 'shadedErrorBar'));
+    
+%% load erp
+
+for ind_id = 1:33
+    id = sprintf('sub-%03d', ind_id);
+    load(fullfile(pn.data_erp, [id,'_erp.mat']));
+    for ind_option = 1:numel(conds.old)
+        if ind_id == 1
+             erpgroup.old.(conds.old{ind_option}) = erp.old{ind_option};
+             erpgroup.old.(conds.old{ind_option}) = ...
+                 rmfield(erpgroup.old.(conds.old{ind_option}), {'avg', 'var', 'dof'});
+             erpgroup.old.(conds.old{ind_option}).dimord = 'sub_chan_time';
+        end
+        erpgroup.old.(conds.old{ind_option}).avg(ind_id,:,:) = erp.old{ind_option}.avg;
+    end
+end
+
+time = erpgroup.old.old.time;
+elec = erpgroup.old.old.elec;
+channels = erpgroup.old.old.label;
+
+%idx_chans = find(ismember(channels, {'O1', 'Oz', 'O2'}));
+%idx_chans = find(ismember(channels, {'PO7', 'PO8'}));
+%idx_chans = find(ismember(channels, {'Pz', 'CPz', 'P1'}));
+
+mergeddata = cat(4, erpgroup.old.old.avg, ...
+    erpgroup.old.new.avg);
+
+%% plot ERP topography
+
+% set custom colormap
+cBrew = brewermap(500,'RdBu');
+cBrew = flipud(cBrew);
+colormap(cBrew)
+
+h = figure('units','centimeters','position',[0 0 10 10]);
+set(gcf,'renderer','Painters')
+
+cfg = [];
+cfg.layout = 'biosemi64.lay';
+cfg.parameter = 'powspctrm';
+cfg.comment = 'no';
+cfg.colormap = cBrew;
+cfg.colorbar = 'EastOutside';
+
+plotData = [];
+plotData.label = elec.label; % {1 x N}
+plotData.dimord = 'chan';
+plotData.powspctrm = squeeze(nanmean(nanmean(nanmean(mergeddata(:,:,time>=0.3& time <=0.5,1:2),3),1),4))'; 
+
+cfg.zlim = [-14 14]*10^-4; 
+cfg.figure = h;
+ft_topoplotER(cfg,plotData);
+cb = colorbar('location', 'EastOutside'); set(get(cb,'ylabel'),'string','Amplitude');
+% figureName = ['xxx'];
+% saveas(h, fullfile(pn.figures, figureName), 'epsc');
+% saveas(h, fullfile(pn.figures, figureName), 'png');
+
+%% visualize frontal ERP
+
+idx_chans = [38];
+
+% avg across channels and conditions
+condAvg = squeeze(nanmean(nanmean(mergeddata(:,idx_chans,:,1:2),2),4));
+
+h = figure('units','centimeters','position',[0 0 10 8]);
+cla; hold on;
+% highlight relevant phase in background
+patches.timeVec = [0.3 0.5];
+patches.colorVec = [1 .95 .8];
+for indP = 1:size(patches.timeVec,2)-1
+    YLim = [-8 2]*10^-4;
+    p = patch([patches.timeVec(indP) patches.timeVec(indP+1) patches.timeVec(indP+1) patches.timeVec(indP)], ...
+                [YLim(1) YLim(1)  YLim(2), YLim(2)], patches.colorVec(indP,:));
+    p.EdgeColor = 'none';
+end
+% new value = old value ? subject average + grand average
+curData = squeeze(nanmean(mergeddata(:,idx_chans,:,1),2));
+curData = curData-condAvg+repmat(nanmean(condAvg,1),size(condAvg,1),1);
+standError = nanstd(curData,1)./sqrt(size(curData,1));
+l1 = shadedErrorBar(time,nanmean(curData,1),standError, 'lineprops', {'color', 'k','linewidth', 2}, 'patchSaturation', .1);
+curData = squeeze(nanmean(mergeddata(:,idx_chans,:,2),2));
+curData = curData-condAvg+repmat(nanmean(condAvg,1),size(condAvg,1),1);
+standError = nanstd(curData,1)./sqrt(size(curData,1));
+l2 = shadedErrorBar(time,nanmean(curData,1),standError, 'lineprops', {'color', 'r','linewidth', 2}, 'patchSaturation', .1);
+% ax = gca; ax.YDir = 'reverse';
+legend([l1.mainLine, l2.mainLine],{'old', 'new'}, ...
+    'location', 'southwest'); legend('boxoff')
+xlabel('Time (s) from stim onset')
+xlim([-.05 .6]); %ylim([-.03 .18])
+ylabel({'ERP';'(microVolts)'});
+xlabel({'Time (s)'});    
+set(findall(gcf,'-property','FontSize'),'FontSize',14)
+
+%% plot difference
+
+idx_chans = [38];
+
+h = figure('units','centimeters','position',[0 0 10 8]);
+cla; hold on;
+% highlight relevant phase in background
+patches.timeVec = [0.3 0.5];
+patches.colorVec = [1 .95 .8];
+for indP = 1:size(patches.timeVec,2)-1
+    YLim = [-10 5]*10^-5;
+    p = patch([patches.timeVec(indP) patches.timeVec(indP+1) patches.timeVec(indP+1) patches.timeVec(indP)], ...
+                [YLim(1) YLim(1)  YLim(2), YLim(2)], patches.colorVec(indP,:));
+    p.EdgeColor = 'none';
+end
+% new value = old value ? subject average + grand average
+curData = squeeze(mergeddata(:,idx_chans,:,2)-mergeddata(:,idx_chans,:,1));
+standError = nanstd(curData,1)./sqrt(size(curData,1));
+l1 = shadedErrorBar(time,nanmean(curData,1),standError, 'lineprops', {'color', 'k','linewidth', 2}, 'patchSaturation', .1);
+legend([l1.mainLine],{'new-old'}, ...
+    'location', 'southwest'); legend('boxoff')
+xlabel('Time (s) from stim onset')
+xlim([-.05 .6]); %ylim([-.03 .18])
+ylabel({'ERP';'(microVolts)'});
+xlabel({'Time (s)'});    
+set(findall(gcf,'-property','FontSize'),'FontSize',14)
+
+
+%% plot difference between conditions
+
+h = figure('units','centimeters','position',[0 0 10 10]);
+set(gcf,'renderer','Painters')
+
+cfg = [];
+cfg.layout = 'biosemi64.lay';
+cfg.parameter = 'powspctrm';
+cfg.comment = 'no';
+cfg.colormap = cBrew;
+cfg.colorbar = 'EastOutside';
+
+plotData = [];
+plotData.label = elec.label; % {1 x N}
+plotData.dimord = 'chan';
+oldminnew = mergeddata(:,:,:,1)-mergeddata(:,:,:,2);
+plotData.powspctrm = squeeze(nanmean(nanmean(oldminnew(:,:,time>=.3 & time <=.5),3),1))'; 
+
+cfg.figure = h;
+ft_topoplotER(cfg,plotData);
+cb = colorbar('location', 'EastOutside'); set(get(cb,'ylabel'),'string','Amplitude');

+ 303 - 0
code/z_archive/b_scenecat_n1.m

@@ -0,0 +1,303 @@
+
+currentFile = mfilename('fullpath');
+[pathstr,~,~] = fileparts(currentFile);
+cd(fullfile(pathstr,'..'))
+rootpath = pwd;
+
+pn.data_eeg = fullfile(rootpath, '..', 'eegmp_preproc', 'data', 'outputs', 'eeg');
+pn.data_erp = fullfile(rootpath, 'data', 'erp');
+pn.data_erf = fullfile(rootpath, 'data', 'erf');
+pn.tools = fullfile(rootpath, 'tools');
+    addpath(fullfile(rootpath, '..', 'eegmp_preproc', 'tools', 'fieldtrip')); ft_defaults
+    addpath(fullfile(pn.tools, 'BrewerMap'));
+    addpath(fullfile(pn.tools, 'shadedErrorBar'));
+    
+%% load event info
+
+load(fullfile(pn.data_eeg, ['sub-001_task-xxxx_eeg_art.mat']), 'events');
+
+parameter = {'scene_category'; 'old'; 'behavior'; 'subsequent_memory'};
+for ind_param = 1:numel(parameter)
+    conds.(parameter{ind_param}) = unique(events.(parameter{ind_param}));
+end
+
+%% load erp
+
+for ind_id = 1:33
+    id = sprintf('sub-%03d', ind_id);
+    load(fullfile(pn.data_erp, [id,'_erp.mat']));
+    for ind_option = 1:numel(conds.scene_category)
+        if ind_id == 1
+             erpgroup.scene_category.(conds.scene_category{ind_option}) = erp.scene_category{ind_option};
+             erpgroup.scene_category.(conds.scene_category{ind_option}) = ...
+                 rmfield(erpgroup.scene_category.(conds.scene_category{ind_option}), {'avg', 'var', 'dof'});
+             erpgroup.scene_category.(conds.scene_category{ind_option}).dimord = 'sub_chan_time';
+        end
+        erpgroup.scene_category.(conds.scene_category{ind_option}).avg(ind_id,:,:) = erp.scene_category{ind_option}.avg;
+    end
+end
+
+time = erpgroup.scene_category.manmade.time;
+elec = erpgroup.scene_category.manmade.elec;
+channels = erpgroup.scene_category.manmade.label;
+
+%idx_chans = find(ismember(channels, {'O1', 'Oz', 'O2'}));
+%idx_chans = find(ismember(channels, {'PO7', 'PO8'}));
+%idx_chans = find(ismember(channels, {'Pz', 'CPz', 'P1'}));
+
+mergeddata = cat(4, erpgroup.scene_category.manmade.avg, ...
+    erpgroup.scene_category.natural.avg);
+
+%% plot topography of visual N1
+
+% set custom colormap
+cBrew = brewermap(500,'RdBu');
+cBrew = flipud(cBrew);
+colormap(cBrew)
+
+h = figure('units','centimeters','position',[0 0 10 10]);
+set(gcf,'renderer','Painters')
+
+cfg = [];
+cfg.layout = 'EEG1010.lay';
+cfg.parameter = 'powspctrm';
+cfg.comment = 'no';
+cfg.colormap = cBrew;
+cfg.colorbar = 'EastOutside';
+
+plotData = [];
+plotData.label = elec.label(1:64); % {1 x N}
+plotData.dimord = 'chan';
+plotData.powspctrm = squeeze(nanmean(nanmean(nanmin(mergeddata(:,:,time>0.04 & time <0.12,1:2),[],3),1),4))'; 
+[~, sortidx] = sort(plotData.powspctrm, 'ascend');
+idx_chans = sortidx(1);
+idx_chans_visual = idx_chans;
+
+cfg.marker = 'off'; 
+cfg.highlight = 'yes';
+cfg.highlightchannel = plotData.label(idx_chans);
+cfg.highlightcolor = [1 0 0];
+cfg.highlightsymbol = '.';
+cfg.highlightsize = 18;
+cfg.zlim = [-10 10]*10^-4; 
+cfg.figure = h;
+ft_topoplotER(cfg,plotData);
+cb = colorbar('location', 'EastOutside'); set(get(cb,'ylabel'),'string','Amplitude');
+
+%% visualize N1 over negative maximum
+
+% avg across channels and conditions
+condAvg = squeeze(nanmean(nanmean(mergeddata(:,idx_chans,:,1:2),2),4));
+
+condAvg1 = squeeze(nanmean(nanmean(mergeddata(:,idx_chans,:,1),2),4));
+condAvg2 = squeeze(nanmean(nanmean(mergeddata(:,idx_chans,:,2),2),4));
+
+
+h = figure('units','centimeters','position',[0 0 10 8]);
+cla; hold on;
+% new value = old value ? subject average + grand average
+curData = squeeze(nanmean(mergeddata(:,idx_chans,:,1),2));
+curData = curData-condAvg+repmat(nanmean(condAvg,1),size(condAvg,1),1);
+standError = nanstd(curData,1)./sqrt(size(curData,1));
+l1 = shadedErrorBar(time,nanmean(curData,1),standError, 'lineprops', {'color', 'k','linewidth', 2}, 'patchSaturation', .1);
+curData = squeeze(nanmean(mergeddata(:,idx_chans,:,2),2));
+curData = curData-condAvg+repmat(nanmean(condAvg,1),size(condAvg,1),1);
+standError = nanstd(curData,1)./sqrt(size(curData,1));
+l2 = shadedErrorBar(time,nanmean(curData,1),standError, 'lineprops', {'color', 'r','linewidth', 2}, 'patchSaturation', .1);
+% ax = gca; ax.YDir = 'reverse';
+xlabel('Time (s) from stim onset')
+xlim([-.025 .16]); %ylim([-.03 .18])
+ylabel({'ERP';'(microVolts)'});
+xlabel({'Time (s)'});    
+set(findall(gcf,'-property','FontSize'),'FontSize',12)
+
+%% ERP components for subjects 1-17 and 18-33 are shifted in time!
+
+h = figure('units','centimeters','position',[0 0 10 8]);
+cla; hold on;
+% new value = old value ? subject average + grand average
+curData = squeeze(nanmean(mergeddata(1:17,idx_chans,:,1),2));
+standError = nanstd(curData,1)./sqrt(size(curData,1));
+l1 = shadedErrorBar(time,nanmean(curData,1),standError, 'lineprops', {'color', 'k','linewidth', 2}, 'patchSaturation', .1);
+curData = squeeze(nanmean(mergeddata(18:end,idx_chans,:,1),2));
+standError = nanstd(curData,1)./sqrt(size(curData,1));
+l2 = shadedErrorBar(time,nanmean(curData,1),standError, 'lineprops', {'color', 'r','linewidth', 2}, 'patchSaturation', .1);
+% ax = gca; ax.YDir = 'reverse';
+xlabel('Time (s) from stim onset')
+xlim([-.025 .16]); %ylim([-.03 .18])
+ylabel({'ERP';'(microVolts)'});
+xlabel({'Time (s)'});    
+set(findall(gcf,'-property','FontSize'),'FontSize',12)
+
+%% align individual subjects N1 to first negative peak
+
+% find individual minimum (avg. across conditions) between 40 and 120 ms
+
+time2search = find(time>0.04 & time <0.12);
+
+newtime = 0-100*(time(2)-time(1)):(time(2)-time(1)):0+100*(time(2)-time(1));
+
+for indID = 1:size(condAvg,1)
+    %[peaks, locs] = findpeaks(condAvg1(indID,:));
+    tmp = find(islocalmin(condAvg(indID,time2search), ...
+        'FlatSelection', 'center', ...
+        'MinSeparation', 25));
+    minVal1(indID) = condAvg1(indID,time2search(tmp(1)));
+    curmin = time2search(tmp(1));
+    alignedN1_1(indID,:) = condAvg1(indID,curmin-100:curmin+100);
+
+    minVal2(indID) = condAvg2(indID,time2search(tmp(1)));
+    curmin = time2search(tmp(1));
+    alignedN1_2(indID,:) = condAvg2(indID,curmin-100:curmin+100);
+    
+    alignedTopo(indID,:,:) = squeeze(nanmean(mergeddata(indID,:,curmin-100:curmin+100,1:2),4));
+end
+
+% alternatively: consider global minimum
+% for indID = 1:size(condAvg,1)
+%     [~, minLoc1(indID)] = min(condAvg(indID,time2search));
+%     curmin = time2search(minLoc1(indID));
+%     minVal1(indID) = condAvg1(indID,curmin);
+%     alignedN1_1(indID,:) = condAvg1(indID,curmin-100:curmin+100);
+%     [~, minLoc2(indID)] = min(condAvg(indID,time2search));
+%     curmin = time2search(minLoc2(indID));
+%     minVal1(indID) = condAvg2(indID,curmin);
+%     alignedN1_2(indID,:) = condAvg2(indID,curmin-100:curmin+100);
+% end
+
+mergeddata_aligned = cat(3, alignedN1_1, alignedN1_2);
+
+[h, p] = ttest(minVal1, minVal2)
+
+% avg across channels and conditions
+condAvg_al = squeeze(nanmean(mergeddata_aligned(:,:,1:2),3));
+
+% check that troughs are aligned
+% figure; imagesc(zscore(condAvg_al,[],2))
+% figure; imagesc(condAvg_al)
+
+h = figure('units','centimeters','position',[0 0 10 8]);
+cla; hold on;
+% new value = old value ? subject average + grand average
+curData = squeeze(mergeddata_aligned(:,:,1));
+curData = curData-condAvg_al+repmat(nanmean(condAvg_al,1),size(condAvg_al,1),1);
+standError = nanstd(curData,1)./sqrt(size(curData,1));
+l1 = shadedErrorBar(newtime*1000,nanmean(curData,1),standError, 'lineprops', {'color', 'k','linewidth', 2}, 'patchSaturation', .1);
+curData = squeeze(mergeddata_aligned(:,:,2));
+curData = curData-condAvg_al+repmat(nanmean(condAvg_al,1),size(condAvg_al,1),1);
+standError = nanstd(curData,1)./sqrt(size(curData,1));
+l2 = shadedErrorBar(newtime*1000,nanmean(curData,1),standError, 'lineprops', {'color', 'r','linewidth', 2}, 'patchSaturation', .1);
+% ax = gca; ax.YDir = 'reverse';
+legend({'manmade', 'natural'}, 'location', 'NorthWest'); legend('boxoff')
+xlabel('Time (s) from local minimum')
+xlim([-100 100]); %ylim([-.03 .18])
+ylabel({'ERP';'(microVolts)'});
+xlabel({'Time (ms) from local minimum'});    
+set(findall(gcf,'-property','FontSize'),'FontSize',12)
+
+%% plot topography around detected trough
+
+h = figure('units','centimeters','position',[0 0 10 10]);
+set(gcf,'renderer','Painters')
+
+cfg = [];
+cfg.layout = 'EEG1010.lay';
+cfg.parameter = 'powspctrm';
+cfg.comment = 'no';
+cfg.colormap = cBrew;
+cfg.colorbar = 'EastOutside';
+
+plotData = [];
+plotData.label = elec.label(1:64); % {1 x N}
+plotData.dimord = 'chan';
+plotData.powspctrm = squeeze(nanmean(nanmean(alignedTopo(:, :, newtime>-.01 & newtime < .01),3),1))'; 
+[~, sortidx] = sort(plotData.powspctrm, 'ascend');
+idx_chans = sortidx(1);
+idx_chans_visual = idx_chans;
+
+cfg.marker = 'off'; 
+cfg.highlight = 'yes';
+cfg.highlightchannel = plotData.label(idx_chans);
+cfg.highlightcolor = [1 0 0];
+cfg.highlightsymbol = '.';
+cfg.highlightsize = 18;
+cfg.zlim = [-5 5]*10^-4; 
+cfg.figure = h;
+ft_topoplotER(cfg,plotData);
+cb = colorbar('location', 'EastOutside'); set(get(cb,'ylabel'),'string','Amplitude');
+
+%% plot difference between conditions
+
+h = figure('units','centimeters','position',[0 0 10 10]);
+set(gcf,'renderer','Painters')
+
+cfg = [];
+cfg.layout = 'biosemi64.lay';
+cfg.parameter = 'powspctrm';
+cfg.comment = 'no';
+cfg.colormap = cBrew;
+cfg.colorbar = 'EastOutside';
+
+plotData = [];
+plotData.label = elec.label; % {1 x N}
+plotData.dimord = 'chan';
+plotData.powspctrm = squeeze(nanmean(nanmean(nanmean(mergeddata(:,:,time>0.08 & time <0.12,2),3),1),4))'...
+    -squeeze(nanmean(nanmean(nanmean(mergeddata(:,:,time>0.08 & time <0.12,1),3),1),4))'; 
+[~, sortidx] = sort(plotData.powspctrm, 'ascend');
+idx_chans = sortidx(1:6);
+
+cfg.marker = 'off'; 
+cfg.highlight = 'yes';
+cfg.highlightchannel = plotData.label(idx_chans);
+cfg.highlightcolor = [1 0 0];
+cfg.highlightsymbol = '.';
+cfg.highlightsize = 18;
+%cfg.zlim = [-5 5]*10^-4; 
+cfg.figure = h;
+ft_topoplotER(cfg,plotData);
+cb = colorbar('location', 'EastOutside'); set(get(cb,'ylabel'),'string','Amplitude');
+
+
+%% visualize for negative pls channels
+
+idx_chans = [28:30];
+condAvg = squeeze(nanmean(nanmean(mergeddata(:,idx_chans,:,1:2),2),4));
+
+h = figure('units','centimeters','position',[0 0 10 8]);
+cla; hold on;
+% new value = old value ? subject average + grand average
+curData = squeeze(nanmean(mergeddata(:,idx_chans,:,1),2));
+curData = curData-condAvg+repmat(nanmean(condAvg,1),size(condAvg,1),1);
+standError = nanstd(curData,1)./sqrt(size(curData,1));
+l1 = shadedErrorBar(time,nanmean(curData,1),standError, 'lineprops', {'color', 'k','linewidth', 2}, 'patchSaturation', .1);
+curData = squeeze(nanmean(mergeddata(:,idx_chans,:,2),2));
+curData = curData-condAvg+repmat(nanmean(condAvg,1),size(condAvg,1),1);
+standError = nanstd(curData,1)./sqrt(size(curData,1));
+l2 = shadedErrorBar(time,nanmean(curData,1),standError, 'lineprops', {'color', 'r','linewidth', 2}, 'patchSaturation', .1);
+xlabel('Time (s) from stim onset')
+xlim([-1 2]); %ylim([-.03 .18])
+ylabel({'ERP';'(microVolts)'});
+xlabel({'Time (s)'});    
+set(findall(gcf,'-property','FontSize'),'FontSize',12)
+
+%% visualize for positive pls channels
+
+idx_chans = [21:23, 58:62];
+condAvg = squeeze(nanmean(nanmean(mergeddata(:,idx_chans,:,1:2),2),4));
+
+h = figure('units','centimeters','position',[0 0 10 8]);
+cla; hold on;
+% new value = old value ? subject average + grand average
+curData = squeeze(nanmean(mergeddata(:,idx_chans,:,1),2));
+curData = curData-condAvg+repmat(nanmean(condAvg,1),size(condAvg,1),1);
+standError = nanstd(curData,1)./sqrt(size(curData,1));
+l1 = shadedErrorBar(time,nanmean(curData,1),standError, 'lineprops', {'color', 'k','linewidth', 2}, 'patchSaturation', .1);
+curData = squeeze(nanmean(mergeddata(:,idx_chans,:,2),2));
+curData = curData-condAvg+repmat(nanmean(condAvg,1),size(condAvg,1),1);
+standError = nanstd(curData,1)./sqrt(size(curData,1));
+l2 = shadedErrorBar(time,nanmean(curData,1),standError, 'lineprops', {'color', 'r','linewidth', 2}, 'patchSaturation', .1);
+xlabel('Time (s) from stim onset')
+xlim([-1 2]); %ylim([-.03 .18])
+ylabel({'ERP';'(microVolts)'});
+xlabel({'Time (s)'});    
+set(findall(gcf,'-property','FontSize'),'FontSize',12)

+ 106 - 0
code/z_archive/e1_taskPLS_memory_erp copy.m

@@ -0,0 +1,106 @@
+% Set up EEG PLS for a task PLS using spectral power
+
+clear all; cla; clc;
+
+currentFile = mfilename('fullpath');
+[pathstr,~,~] = fileparts(currentFile);
+cd(fullfile(pathstr,'..'))
+rootpath = pwd;
+
+pn.data_eeg = fullfile(rootpath, '..', 'eegmp_preproc', 'data', 'outputs', 'eeg');
+pn.data_erp = fullfile(rootpath, 'data', 'erp');
+pn.data_erf = fullfile(rootpath, 'data', 'erf');
+pn.data = fullfile(rootpath, 'data', 'stats'); mkdir(pn.data);
+pn.tools = fullfile(rootpath, 'tools');
+    addpath(fullfile(rootpath, '..', 'eegmp_preproc', 'tools', 'fieldtrip')); ft_defaults
+    addpath(genpath(fullfile(pn.tools, '[MEG]PLS', 'MEGPLS_PIPELINE_v2.02b')))
+    addpath(fullfile(pn.tools, 'BrewerMap'));
+    addpath(fullfile(pn.tools, 'shadedErrorBar'));
+
+%% add seed for reproducibility
+
+rng(0, 'twister');
+    
+%% load event info
+
+load(fullfile(pn.data_eeg, ['sub-001_task-xxxx_eeg_art.mat']), 'events');
+
+parameter = {'scene_category'; 'old'; 'behavior'; 'subsequent_memory'};
+for ind_param = 1:numel(parameter)
+    conds.(parameter{ind_param}) = unique(events.(parameter{ind_param}));
+end
+
+%% load erp_bl
+
+for ind_id = 1:33
+    id = sprintf('sub-%03d', ind_id); disp(id)
+    load(fullfile(pn.data_erp, [id,'_erp_bl.mat']));
+    for ind_option = 2:3
+        if ind_id == 1
+             erpgroup.subsequent_memory.(conds.subsequent_memory{ind_option}) = erp_bl.subsequent_memory{ind_option};
+             erpgroup.subsequent_memory.(conds.subsequent_memory{ind_option}) = ...
+                 rmfield(erpgroup.subsequent_memory.(conds.subsequent_memory{ind_option}), {'avg', 'var', 'dof'});
+             erpgroup.subsequent_memory.(conds.subsequent_memory{ind_option}).dimord = 'sub_chan_time';
+        end
+        erpgroup.subsequent_memory.(conds.subsequent_memory{ind_option}).avg(ind_id,:,:) = erp_bl.subsequent_memory{ind_option}.avg;
+    end
+end
+
+time = erpgroup.subsequent_memory.subsequent_remembered.time;
+elec = erpgroup.subsequent_memory.subsequent_remembered.elec;
+channels = erpgroup.subsequent_memory.subsequent_remembered.label;
+
+mergeddata = cat(4, erpgroup.subsequent_memory.subsequent_forgotten.avg, ...
+    erpgroup.subsequent_memory.subsequent_remembered.avg);
+
+num_chans = numel(channels);
+num_freqs = 1;
+num_time = numel(time);
+
+num_subj_lst = [33];
+num_cond = 2;
+num_grp = 1;
+
+datamat_lst = cell(num_grp); lv_evt_list = [];
+indCount_cont = 1;
+indCount = 1;
+indGroup = 1;
+for indCond = 1:num_cond
+    for indID = 1:num_subj_lst(indGroup)
+        datamat_lst{indGroup}(indCount,:) = reshape(squeeze(mergeddata(indID,:,:,indCond)), [], 1);
+        lv_evt_list(indCount_cont) = indCond;
+        indCount = indCount+1;
+        indCount_cont = indCount_cont+1;
+    end
+end
+datamat_lst{indGroup}(isnan(datamat_lst{indGroup})) = 0;
+
+%% set PLS options and run PLS
+
+option = [];
+option.method = 1; % [1] | 2 | 3 | 4 | 5 | 6
+option.num_perm = 1000; %( single non-negative integer )
+option.num_split = 0; %( single non-negative integer )
+option.num_boot = 1000; % ( single non-negative integer )
+option.cormode = 0; % [0] | 2 | 4 | 6
+option.meancentering_type = 0;% [0] | 1 | 2 | 3
+option.boot_type = 'strat'; %['strat'] | 'nonstrat'
+
+result = pls_analysis(datamat_lst, num_subj_lst, num_cond, option);
+
+%% rearrange into fieldtrip structure
+
+lvdat = reshape(result.boot_result.compare_u(:,1), num_chans, num_freqs, num_time);
+%udat = reshape(result.u, num_chans, num_freqs, num_time);
+
+stat = [];
+stat.prob = lvdat;
+stat.dimord = 'chan_freq_time';
+stat.clusters = [];
+stat.clusters.prob = result.perm_result.sprob; % check for significance of LV
+stat.mask = lvdat > 3 | lvdat < -3;
+stat.cfg = option;
+stat.time = time;
+
+save(fullfile(pn.data, 'e01_taskpls_erp.mat'),...
+    'stat', 'result', 'lvdat', 'lv_evt_list', 'num_chans', 'num_freqs', 'num_time')

+ 59 - 0
code/z_eegmp_old_new_ERP.m

@@ -0,0 +1,59 @@
+function z_eegmp_old_new_ERP(rootpath, id)
+
+%% paths
+if ismac
+    currentFile = mfilename('fullpath');
+    [pathstr,~,~] = fileparts(currentFile);
+    cd(fullfile(pathstr,'..'))
+    rootpath = pwd;
+    id = 'sub-011';
+end
+
+pn.data_eeg = fullfile(rootpath, '..', 'eegmp_preproc', 'data', 'outputs', 'eeg');
+pn.data_erp = fullfile(rootpath, 'data', 'test'); mkdir(pn.data_erp);
+pn.tools = fullfile(rootpath, '..', 'eegmp_preproc', 'tools');
+    addpath(fullfile(pn.tools, 'fieldtrip')); ft_defaults
+
+%% load data_eeg
+
+% load preprocessed eeg data_eeg
+load(fullfile(pn.data_eeg, [id,'_task-xxxx_eeg_art.mat']), 'data_eeg', 'events');
+
+%% further preprocessing
+
+% apply notch filter
+
+cfg = [];
+cfg.dftfilter = 'yes';
+data_eeg = ft_preprocessing(cfg, data_eeg);
+
+%% CSD transform
+    
+% csd_cfg = [];
+% csd_cfg.method = 'spline';
+% data_eeg = ft_scalpcurrentdensity(csd_cfg, data_eeg);
+
+%% single-trial baseline-correction for ERPs
+
+time = data_eeg.time{1};
+
+data_eeg_bl = data_eeg;
+
+for indTrial = 1:numel(data_eeg_bl.trial)
+    curbl = squeeze(nanmean(data_eeg_bl.trial{indTrial}(:,time>-.2 & time<0),2));
+    data_eeg_bl.trial{indTrial} = data_eeg_bl.trial{indTrial}-repmat(curbl,1,numel(time));
+end
+
+%% split tfr and time series data by condition, average across trials
+
+cfg = [];
+cfg.trials = ismember(events.old, 'old');
+erp_bl.old = ft_timelockanalysis(cfg, data_eeg_bl);
+
+cfg = [];
+cfg.trials = ismember(events.old, 'new');
+erp_bl.new = ft_timelockanalysis(cfg, data_eeg_bl);
+
+%% save data
+
+save(fullfile(pn.data_erp, [id, '_erp_bl.mat']), 'erp_bl');

+ 27 - 0
code/z_eegmp_old_new_ERP_START.sh

@@ -0,0 +1,27 @@
+#!/bin/bash
+
+#!/bin/bash
+
+fun_name="z_eegmp_old_new_ERP"
+job_name="eegmp_test"
+
+rootpath="$(pwd)/.."
+rootpath=$(builtin cd $rootpath; pwd)
+
+mkdir ${rootpath}/log
+
+for subj in $(seq 1 33); do
+	cursub=$(printf "sub-%03d\n" ${subj})
+	echo ${cursub}
+	# if not been performed yet
+	#if [ ! -f ${rootpath}/data/erf/sub-$(printf "%03d" ${subj})*_erf.mat ]; then
+		sbatch \
+  			--job-name ${job_name}_${cursub} \
+  			--cpus-per-task 4 \
+  			--mem 6gb \
+  			--time 00:30:00 \
+  			--output ${rootpath}/log/${job_name}_${cursub}.out \
+  			--workdir . \
+  			--wrap=". /etc/profile ; module load matlab/R2016b; matlab -nodisplay -r \"${fun_name}('${rootpath}','${cursub}')\""
+  	#fi
+done

+ 130 - 0
code/z_eegmp_old_new_ERP_trace.m

@@ -0,0 +1,130 @@
+
+currentFile = mfilename('fullpath');
+[pathstr,~,~] = fileparts(currentFile);
+cd(fullfile(pathstr,'..'))
+rootpath = pwd;
+
+pn.data_eeg = fullfile(rootpath, '..', 'eegmp_preproc', 'data', 'outputs', 'eeg');
+pn.data_erp = fullfile(rootpath, 'data', 'test');
+pn.data_erf = fullfile(rootpath, 'data', 'erf');
+pn.tools = fullfile(rootpath, 'tools');
+    addpath(fullfile(rootpath, '..', 'eegmp_preproc', 'tools', 'fieldtrip')); ft_defaults
+    addpath(fullfile(pn.tools, 'BrewerMap'));
+    addpath(fullfile(pn.tools, 'shadedErrorBar'));
+    
+% set custom colormap
+cBrew = brewermap(500,'RdBu');
+cBrew = flipud(cBrew);
+colormap(cBrew)
+
+%% load erp
+
+for ind_id = 1:33
+    id = sprintf('sub-%03d', ind_id);
+    load(fullfile(pn.data_erp, [id,'_erp_bl.mat']));
+    if ind_id == 1
+         erpgroup.old.old = erp_bl.old;
+         erpgroup.old.old = ...
+             rmfield(erpgroup.old.old, {'avg', 'var', 'dof'});
+         erpgroup.old.old.dimord = 'sub_chan_time';
+
+         erpgroup.old.new = erp_bl.new;
+         erpgroup.old.new = ...
+             rmfield(erpgroup.old.new, {'avg', 'var', 'dof'});
+         erpgroup.old.new.dimord = 'sub_chan_time';
+    end
+    erpgroup.old.old.avg(ind_id,:,:) = erp_bl.old.avg;
+    erpgroup.old.new.avg(ind_id,:,:) = erp_bl.new.avg;
+end
+
+time = erpgroup.old.old.time;
+elec = erpgroup.old.old.elec;
+channels = erpgroup.old.old.label;
+
+mergeddata = cat(4, erpgroup.old.old.avg, ...
+    erpgroup.old.new.avg);
+
+%% visualize frontal ERP
+
+idx_chans = [38];
+
+% avg across channels and conditions
+condAvg = squeeze(nanmean(nanmean(mergeddata(:,idx_chans,:,1:2),2),4));
+
+h = figure('units','centimeters','position',[0 0 10 8]);
+cla; hold on;
+% highlight relevant phase in background
+patches.timeVec = [0.3 0.5];
+patches.colorVec = [1 .95 .8];
+for indP = 1:size(patches.timeVec,2)-1
+    YLim = [-8 2]*10^-4;
+    p = patch([patches.timeVec(indP) patches.timeVec(indP+1) patches.timeVec(indP+1) patches.timeVec(indP)], ...
+                [YLim(1) YLim(1)  YLim(2), YLim(2)], patches.colorVec(indP,:));
+    p.EdgeColor = 'none';
+end
+% new value = old value ? subject average + grand average
+curData = squeeze(nanmean(mergeddata(:,idx_chans,:,1),2));
+curData = curData-condAvg+repmat(nanmean(condAvg,1),size(condAvg,1),1);
+standError = nanstd(curData,1)./sqrt(size(curData,1));
+l1 = shadedErrorBar(time,nanmean(curData,1),standError, 'lineprops', {'color', 'k','linewidth', 2}, 'patchSaturation', .1);
+curData = squeeze(nanmean(mergeddata(:,idx_chans,:,2),2));
+curData = curData-condAvg+repmat(nanmean(condAvg,1),size(condAvg,1),1);
+standError = nanstd(curData,1)./sqrt(size(curData,1));
+l2 = shadedErrorBar(time,nanmean(curData,1),standError, 'lineprops', {'color', 'r','linewidth', 2}, 'patchSaturation', .1);
+% ax = gca; ax.YDir = 'reverse';
+legend([l1.mainLine, l2.mainLine],{'old', 'new'}, ...
+    'location', 'southwest'); legend('boxoff')
+xlabel('Time (s) from stim onset')
+xlim([-.05 .7]); %ylim([-.03 .18])
+ylabel({'ERP';'(microVolts)'});
+xlabel({'Time (s)'});    
+set(findall(gcf,'-property','FontSize'),'FontSize',14)
+
+%% plot difference
+
+idx_chans = [38];
+
+h = figure('units','centimeters','position',[0 0 10 8]);
+cla; hold on;
+% highlight relevant phase in background
+patches.timeVec = [0.3 0.5];
+patches.colorVec = [1 .95 .8];
+for indP = 1:size(patches.timeVec,2)-1
+    YLim = [-10 5]*10^-5;
+    p = patch([patches.timeVec(indP) patches.timeVec(indP+1) patches.timeVec(indP+1) patches.timeVec(indP)], ...
+                [YLim(1) YLim(1)  YLim(2), YLim(2)], patches.colorVec(indP,:));
+    p.EdgeColor = 'none';
+end
+% new value = old value ? subject average + grand average
+curData = squeeze(mergeddata(:,idx_chans,:,2)-mergeddata(:,idx_chans,:,1));
+standError = nanstd(curData,1)./sqrt(size(curData,1));
+l1 = shadedErrorBar(time,nanmean(curData,1),standError, 'lineprops', {'color', 'k','linewidth', 2}, 'patchSaturation', .1);
+legend([l1.mainLine],{'new-old'}, ...
+    'location', 'southwest'); legend('boxoff')
+xlabel('Time (s) from stim onset')
+xlim([-.05 .7]); %ylim([-.03 .18])
+ylabel({'ERP';'(microVolts)'});
+xlabel({'Time (s)'});    
+set(findall(gcf,'-property','FontSize'),'FontSize',14)
+
+%% plot difference between conditions
+
+h = figure('units','centimeters','position',[0 0 10 10]);
+set(gcf,'renderer','Painters')
+
+cfg = [];
+cfg.layout = 'biosemi64.lay';
+cfg.parameter = 'powspctrm';
+cfg.comment = 'no';
+cfg.colormap = cBrew;
+cfg.colorbar = 'EastOutside';
+
+plotData = [];
+plotData.label = elec.label(1:64); % {1 x N}
+plotData.dimord = 'chan';
+oldminnew = mergeddata(:,:,:,1)-mergeddata(:,:,:,2);
+plotData.powspctrm = squeeze(nanmean(nanmean(oldminnew(:,1:64,time>=.3 & time <=.5),3),1))'; 
+
+cfg.figure = h;
+ft_topoplotER(cfg,plotData);
+cb = colorbar('location', 'EastOutside'); set(get(cb,'ylabel'),'string','Amplitude');

+ 1 - 1
data/erf/sub-001_erf.mat

@@ -1 +1 @@
-../../.git/annex/objects/1z/xG/MD5E-s25965437--5930ca9b2d4bba87ec030bea561ea46a.mat/MD5E-s25965437--5930ca9b2d4bba87ec030bea561ea46a.mat
+../../.git/annex/objects/9v/m5/MD5E-s13425680--9ab233ccf9fafd745b7be02a7efc87b4.mat/MD5E-s13425680--9ab233ccf9fafd745b7be02a7efc87b4.mat

+ 1 - 1
data/erf/sub-002_erf.mat

@@ -1 +1 @@
-../../.git/annex/objects/v0/09/MD5E-s23708152--97938175f25225af5016aa4a0edbac59.mat/MD5E-s23708152--97938175f25225af5016aa4a0edbac59.mat
+../../.git/annex/objects/fv/V0/MD5E-s12195583--bf90fc03a5ef157e8bc07c85bbc17b84.mat/MD5E-s12195583--bf90fc03a5ef157e8bc07c85bbc17b84.mat

+ 1 - 1
data/erf/sub-003_erf.mat

@@ -1 +1 @@
-../../.git/annex/objects/Gq/JG/MD5E-s23752159--22a4646b4ea5136b8f99158abd7c7a22.mat/MD5E-s23752159--22a4646b4ea5136b8f99158abd7c7a22.mat
+../../.git/annex/objects/pk/j0/MD5E-s12303942--31aa8c399f69b44316e60610dca72f07.mat/MD5E-s12303942--31aa8c399f69b44316e60610dca72f07.mat

+ 1 - 1
data/erf/sub-004_erf.mat

@@ -1 +1 @@
-../../.git/annex/objects/7q/0W/MD5E-s25836544--6071c904dc707d0fe0d7e9d6e0fce72c.mat/MD5E-s25836544--6071c904dc707d0fe0d7e9d6e0fce72c.mat
+../../.git/annex/objects/f2/6j/MD5E-s13560014--28ffc072105a596e8bf9cb905e2bb079.mat/MD5E-s13560014--28ffc072105a596e8bf9cb905e2bb079.mat

+ 1 - 1
data/erf/sub-005_erf.mat

@@ -1 +1 @@
-../../.git/annex/objects/7v/q7/MD5E-s25892424--974e7bc670920d309dfd8c1f2d01d1ee.mat/MD5E-s25892424--974e7bc670920d309dfd8c1f2d01d1ee.mat
+../../.git/annex/objects/g8/1q/MD5E-s13615394--2eaeeb8efed8a1f8d4e93ec738651609.mat/MD5E-s13615394--2eaeeb8efed8a1f8d4e93ec738651609.mat

+ 1 - 1
data/erf/sub-006_erf.mat

@@ -1 +1 @@
-../../.git/annex/objects/wk/Fq/MD5E-s23653512--017580e6a613613d305a6f87ce7bd8b4.mat/MD5E-s23653512--017580e6a613613d305a6f87ce7bd8b4.mat
+../../.git/annex/objects/xQ/jV/MD5E-s12319310--6f3ec0598f54cef2e3a13d68b45b1456.mat/MD5E-s12319310--6f3ec0598f54cef2e3a13d68b45b1456.mat

+ 1 - 1
data/erf/sub-007_erf.mat

@@ -1 +1 @@
-../../.git/annex/objects/VQ/Qx/MD5E-s25900205--cf08168c0af24728507fca3dafa236be.mat/MD5E-s25900205--cf08168c0af24728507fca3dafa236be.mat
+../../.git/annex/objects/x7/w9/MD5E-s13602714--3fa8392a732b51ab3a2fc30e7d1c0389.mat/MD5E-s13602714--3fa8392a732b51ab3a2fc30e7d1c0389.mat

+ 1 - 1
data/erf/sub-008_erf.mat

@@ -1 +1 @@
-../../.git/annex/objects/KQ/6z/MD5E-s23658963--c29628ee341d487608d859b9a6f29219.mat/MD5E-s23658963--c29628ee341d487608d859b9a6f29219.mat
+../../.git/annex/objects/75/qp/MD5E-s12039212--ca6be68912e16ba98c12aec3f238c13d.mat/MD5E-s12039212--ca6be68912e16ba98c12aec3f238c13d.mat

+ 1 - 1
data/erf/sub-009_erf.mat

@@ -1 +1 @@
-../../.git/annex/objects/kz/Kp/MD5E-s25874873--14cc24a013f5926da4d43b635cb4b51f.mat/MD5E-s25874873--14cc24a013f5926da4d43b635cb4b51f.mat
+../../.git/annex/objects/j3/VK/MD5E-s13557566--5e7333ac6733e1a4b4fec0b3b8de079b.mat/MD5E-s13557566--5e7333ac6733e1a4b4fec0b3b8de079b.mat

+ 1 - 1
data/erf/sub-010_erf.mat

@@ -1 +1 @@
-../../.git/annex/objects/pj/p7/MD5E-s25957213--27f5523c20264e1cc89b20d7b5d69b7f.mat/MD5E-s25957213--27f5523c20264e1cc89b20d7b5d69b7f.mat
+../../.git/annex/objects/GP/Qg/MD5E-s13453887--cbdac1f75fa4b7122292f2e3973a2a07.mat/MD5E-s13453887--cbdac1f75fa4b7122292f2e3973a2a07.mat

+ 1 - 1
data/erf/sub-011_erf.mat

@@ -1 +1 @@
-../../.git/annex/objects/Pp/ZV/MD5E-s23763301--a04575f217114c9e41c4cbbe023be617.mat/MD5E-s23763301--a04575f217114c9e41c4cbbe023be617.mat
+../../.git/annex/objects/2J/Vk/MD5E-s12285899--47eb01ec570711031dfc7d60d6652da3.mat/MD5E-s12285899--47eb01ec570711031dfc7d60d6652da3.mat

+ 1 - 1
data/erf/sub-012_erf.mat

@@ -1 +1 @@
-../../.git/annex/objects/Km/KG/MD5E-s23745801--a63b678996434a57805a68fff361368c.mat/MD5E-s23745801--a63b678996434a57805a68fff361368c.mat
+../../.git/annex/objects/Kj/MK/MD5E-s12449226--ccd68b97c56bcdd573607c8d38ca253a.mat/MD5E-s12449226--ccd68b97c56bcdd573607c8d38ca253a.mat

+ 1 - 1
data/erf/sub-013_erf.mat

@@ -1 +1 @@
-../../.git/annex/objects/W9/1v/MD5E-s25868372--510b24ef57fd4c57d5eb93c13a11d164.mat/MD5E-s25868372--510b24ef57fd4c57d5eb93c13a11d164.mat
+../../.git/annex/objects/z4/5j/MD5E-s13176737--fc9fd1f4c68e0dcccf66806ac5e745c9.mat/MD5E-s13176737--fc9fd1f4c68e0dcccf66806ac5e745c9.mat

+ 1 - 1
data/erf/sub-014_erf.mat

@@ -1 +1 @@
-../../.git/annex/objects/Km/5m/MD5E-s23782386--8073df9fb9a4e1d72950563860210a18.mat/MD5E-s23782386--8073df9fb9a4e1d72950563860210a18.mat
+../../.git/annex/objects/VP/6m/MD5E-s12314332--0913d449ccf0e28096e414ded39d8084.mat/MD5E-s12314332--0913d449ccf0e28096e414ded39d8084.mat

+ 1 - 1
data/erf/sub-015_erf.mat

@@ -1 +1 @@
-../../.git/annex/objects/m1/F7/MD5E-s23733319--cbb328ed0e710872db2497f77d8ca70d.mat/MD5E-s23733319--cbb328ed0e710872db2497f77d8ca70d.mat
+../../.git/annex/objects/4P/GW/MD5E-s12181737--4d5c6fb87a09baaf93782470a8fb21f1.mat/MD5E-s12181737--4d5c6fb87a09baaf93782470a8fb21f1.mat

+ 1 - 1
data/erf/sub-016_erf.mat

@@ -1 +1 @@
-../../.git/annex/objects/6p/8F/MD5E-s25851775--4bdee37830e0fdb5c945150840573deb.mat/MD5E-s25851775--4bdee37830e0fdb5c945150840573deb.mat
+../../.git/annex/objects/Zm/4f/MD5E-s13345051--84a9a07f997c0b6f42b5a45d4572d86c.mat/MD5E-s13345051--84a9a07f997c0b6f42b5a45d4572d86c.mat

+ 1 - 1
data/erf/sub-017_erf.mat

@@ -1 +1 @@
-../../.git/annex/objects/z5/6j/MD5E-s23783046--43769779c35b3725ccd5d01e5aa88d4b.mat/MD5E-s23783046--43769779c35b3725ccd5d01e5aa88d4b.mat
+../../.git/annex/objects/XG/VK/MD5E-s12164012--5342b03e9dabd65cc45ab9ebbd8961bc.mat/MD5E-s12164012--5342b03e9dabd65cc45ab9ebbd8961bc.mat

+ 1 - 1
data/erf/sub-018_erf.mat

@@ -1 +1 @@
-../../.git/annex/objects/9g/Zg/MD5E-s25882380--74a64dc7537c187c1cd967a9aebacea6.mat/MD5E-s25882380--74a64dc7537c187c1cd967a9aebacea6.mat
+../../.git/annex/objects/0P/Vv/MD5E-s13158335--691ba25a314b487f7c73c0c669cfc5cc.mat/MD5E-s13158335--691ba25a314b487f7c73c0c669cfc5cc.mat

+ 1 - 1
data/erf/sub-019_erf.mat

@@ -1 +1 @@
-../../.git/annex/objects/Kx/8k/MD5E-s25911350--8ec427769c63d0d5135874125c5750e0.mat/MD5E-s25911350--8ec427769c63d0d5135874125c5750e0.mat
+../../.git/annex/objects/33/4P/MD5E-s13060296--6fce57f78dab25425ef274584acb81fa.mat/MD5E-s13060296--6fce57f78dab25425ef274584acb81fa.mat

+ 1 - 1
data/erf/sub-020_erf.mat

@@ -1 +1 @@
-../../.git/annex/objects/qJ/gQ/MD5E-s23841676--23921dd7be7eeb25fd6317de8cb47836.mat/MD5E-s23841676--23921dd7be7eeb25fd6317de8cb47836.mat
+../../.git/annex/objects/8z/01/MD5E-s12202298--7c91167390d91f7e94d11a7fbd4ea618.mat/MD5E-s12202298--7c91167390d91f7e94d11a7fbd4ea618.mat

+ 1 - 1
data/erf/sub-021_erf.mat

@@ -1 +1 @@
-../../.git/annex/objects/V0/6Q/MD5E-s25914567--7d5fdc6d52b699d72c8736251893b9c8.mat/MD5E-s25914567--7d5fdc6d52b699d72c8736251893b9c8.mat
+../../.git/annex/objects/w9/Gk/MD5E-s13539202--5b4f4e054a3488e97a7cacb1642a6c91.mat/MD5E-s13539202--5b4f4e054a3488e97a7cacb1642a6c91.mat

+ 1 - 1
data/erf/sub-022_erf.mat

@@ -1 +1 @@
-../../.git/annex/objects/jx/qk/MD5E-s23630140--1a4f157fac1921a119787471952809e3.mat/MD5E-s23630140--1a4f157fac1921a119787471952809e3.mat
+../../.git/annex/objects/6Q/Kk/MD5E-s12321314--4c306420337e248b9ca1012039961008.mat/MD5E-s12321314--4c306420337e248b9ca1012039961008.mat

+ 1 - 1
data/erf/sub-023_erf.mat

@@ -1 +1 @@
-../../.git/annex/objects/V2/gX/MD5E-s25909644--26605a542ffaa1d8f001cb621d97b29e.mat/MD5E-s25909644--26605a542ffaa1d8f001cb621d97b29e.mat
+../../.git/annex/objects/K5/kQ/MD5E-s13316397--a7dab1adbb41efb995fd16bbeaed9439.mat/MD5E-s13316397--a7dab1adbb41efb995fd16bbeaed9439.mat

+ 1 - 1
data/erf/sub-024_erf.mat

@@ -1 +1 @@
-../../.git/annex/objects/Wk/J5/MD5E-s23740098--4cc20d5531e643b3b30f5f99d84ab367.mat/MD5E-s23740098--4cc20d5531e643b3b30f5f99d84ab367.mat
+../../.git/annex/objects/Kj/GG/MD5E-s12201069--8fea017c33d53c5356118085e6700c5e.mat/MD5E-s12201069--8fea017c33d53c5356118085e6700c5e.mat

+ 1 - 1
data/erf/sub-025_erf.mat

@@ -1 +1 @@
-../../.git/annex/objects/4w/j3/MD5E-s25945628--5b6d01b6d84425c8242b1fe135ebbd6c.mat/MD5E-s25945628--5b6d01b6d84425c8242b1fe135ebbd6c.mat
+../../.git/annex/objects/KG/V5/MD5E-s13569875--445218c438ec1e88d3ff71391cae54ff.mat/MD5E-s13569875--445218c438ec1e88d3ff71391cae54ff.mat

+ 1 - 1
data/erf/sub-026_erf.mat

@@ -1 +1 @@
-../../.git/annex/objects/z1/gM/MD5E-s25938229--a643b58baccdbbcd92652525e31833f2.mat/MD5E-s25938229--a643b58baccdbbcd92652525e31833f2.mat
+../../.git/annex/objects/VX/Z5/MD5E-s13042187--20d89b8d81d9ff273ea15aea6f045d25.mat/MD5E-s13042187--20d89b8d81d9ff273ea15aea6f045d25.mat

+ 1 - 1
data/erf/sub-027_erf.mat

@@ -1 +1 @@
-../../.git/annex/objects/Zm/q0/MD5E-s25970202--37364331e16212d9a130618b248480c7.mat/MD5E-s25970202--37364331e16212d9a130618b248480c7.mat
+../../.git/annex/objects/qq/WW/MD5E-s13535870--9c062a0770c5efe826162da84b6fdc42.mat/MD5E-s13535870--9c062a0770c5efe826162da84b6fdc42.mat

+ 1 - 1
data/erf/sub-028_erf.mat

@@ -1 +1 @@
-../../.git/annex/objects/75/28/MD5E-s25940419--03e8e976e9cb12e5cff9939346ea63f3.mat/MD5E-s25940419--03e8e976e9cb12e5cff9939346ea63f3.mat
+../../.git/annex/objects/4k/z2/MD5E-s13209742--1e1a4f3579d3b69893e85fd9715db3af.mat/MD5E-s13209742--1e1a4f3579d3b69893e85fd9715db3af.mat

+ 1 - 1
data/erf/sub-029_erf.mat

@@ -1 +1 @@
-../../.git/annex/objects/gJ/6q/MD5E-s25915599--da02d306c00a711950089e6043693272.mat/MD5E-s25915599--da02d306c00a711950089e6043693272.mat
+../../.git/annex/objects/Kv/pX/MD5E-s13464929--214dc7297f9aac94efa540ef373fa046.mat/MD5E-s13464929--214dc7297f9aac94efa540ef373fa046.mat

+ 1 - 1
data/erf/sub-030_erf.mat

@@ -1 +1 @@
-../../.git/annex/objects/9V/f6/MD5E-s25882935--9147441e2364f2d138bf1f59a3ac6fcf.mat/MD5E-s25882935--9147441e2364f2d138bf1f59a3ac6fcf.mat
+../../.git/annex/objects/1Q/v7/MD5E-s13411216--baf832e497889fc13b0cbbf8d0af06d7.mat/MD5E-s13411216--baf832e497889fc13b0cbbf8d0af06d7.mat

+ 1 - 1
data/erf/sub-031_erf.mat

@@ -1 +1 @@
-../../.git/annex/objects/PJ/k8/MD5E-s25891755--b9ace4f0216568d0038a0f548f51ec46.mat/MD5E-s25891755--b9ace4f0216568d0038a0f548f51ec46.mat
+../../.git/annex/objects/kg/Ww/MD5E-s13306917--43a1dba8df9b63c18dedfcd23feaa39f.mat/MD5E-s13306917--43a1dba8df9b63c18dedfcd23feaa39f.mat

+ 1 - 1
data/erf/sub-032_erf.mat

@@ -1 +1 @@
-../../.git/annex/objects/z2/0g/MD5E-s23603875--90dcd5018c3923b77c6548b203779a5c.mat/MD5E-s23603875--90dcd5018c3923b77c6548b203779a5c.mat
+../../.git/annex/objects/G5/x2/MD5E-s12206302--62999127dba5f403367d513f87da8a63.mat/MD5E-s12206302--62999127dba5f403367d513f87da8a63.mat

+ 1 - 1
data/erf/sub-033_erf.mat

@@ -1 +1 @@
-../../.git/annex/objects/k4/qx/MD5E-s23679316--c089c30a1967868b1c2ee99671839f2a.mat/MD5E-s23679316--c089c30a1967868b1c2ee99671839f2a.mat
+../../.git/annex/objects/mj/28/MD5E-s12219283--246f5ef5bf4b34842ddaaa03a9ef4d52.mat/MD5E-s12219283--246f5ef5bf4b34842ddaaa03a9ef4d52.mat

+ 1 - 1
data/erp/sub-001_erp.mat

@@ -1 +1 @@
-../../.git/annex/objects/G7/73/MD5E-s18856858--80fb4f179b02a13cd2ef29c8c141084d.mat/MD5E-s18856858--80fb4f179b02a13cd2ef29c8c141084d.mat
+../../.git/annex/objects/7V/JV/MD5E-s18717486--b6b752afd7cc0d9c8c0e398ba1aa7adf.mat/MD5E-s18717486--b6b752afd7cc0d9c8c0e398ba1aa7adf.mat

+ 1 - 1
data/erp/sub-001_erp_bl.mat

@@ -1 +1 @@
-../../.git/annex/objects/x0/Zw/MD5E-s18850313--522cfdd3a3c125e93877f6e4e0b11135.mat/MD5E-s18850313--522cfdd3a3c125e93877f6e4e0b11135.mat
+../../.git/annex/objects/m5/QK/MD5E-s18720247--dcacea13577c315a1b93a8496eedcdf5.mat/MD5E-s18720247--dcacea13577c315a1b93a8496eedcdf5.mat

+ 1 - 1
data/erp/sub-002_erp.mat

@@ -1 +1 @@
-../../.git/annex/objects/94/3p/MD5E-s17943972--79b0ecb5727ffdb663e6a40ade3a6903.mat/MD5E-s17943972--79b0ecb5727ffdb663e6a40ade3a6903.mat
+../../.git/annex/objects/qX/wz/MD5E-s17601338--6b5c5e3d46fbbc8194cd39c01a728a53.mat/MD5E-s17601338--6b5c5e3d46fbbc8194cd39c01a728a53.mat

+ 1 - 1
data/erp/sub-002_erp_bl.mat

@@ -1 +1 @@
-../../.git/annex/objects/f6/mz/MD5E-s17937451--03d55e1b8dcba6e20a8c677e05c6e531.mat/MD5E-s17937451--03d55e1b8dcba6e20a8c677e05c6e531.mat
+../../.git/annex/objects/JP/Xm/MD5E-s17619336--27e0e216b095492467449660659d90aa.mat/MD5E-s17619336--27e0e216b095492467449660659d90aa.mat

+ 1 - 1
data/erp/sub-003_erp.mat

@@ -1 +1 @@
-../../.git/annex/objects/6q/mW/MD5E-s17977030--cc5f3a948f0d82149e7edc87070b2ea2.mat/MD5E-s17977030--cc5f3a948f0d82149e7edc87070b2ea2.mat
+../../.git/annex/objects/3k/kK/MD5E-s17799082--e6a833730a25ab6122cbfab1b67e3f78.mat/MD5E-s17799082--e6a833730a25ab6122cbfab1b67e3f78.mat

+ 1 - 1
data/erp/sub-003_erp_bl.mat

@@ -1 +1 @@
-../../.git/annex/objects/k2/f7/MD5E-s17975992--363d517c2cb11a16c3df5dc4e6a19962.mat/MD5E-s17975992--363d517c2cb11a16c3df5dc4e6a19962.mat
+../../.git/annex/objects/xk/4g/MD5E-s17819261--e37a0e8e54742b8bf7693ac1c4289043.mat/MD5E-s17819261--e37a0e8e54742b8bf7693ac1c4289043.mat

+ 1 - 1
data/erp/sub-004_erp.mat

@@ -1 +1 @@
-../../.git/annex/objects/3k/kp/MD5E-s18867310--91bfca595b6431450365bd5c52924890.mat/MD5E-s18867310--91bfca595b6431450365bd5c52924890.mat
+../../.git/annex/objects/4F/PF/MD5E-s18857334--3353a05454029650d817f58451914e9b.mat/MD5E-s18857334--3353a05454029650d817f58451914e9b.mat

+ 1 - 1
data/erp/sub-004_erp_bl.mat

@@ -1 +1 @@
-../../.git/annex/objects/9j/6z/MD5E-s18869346--43214e51f11909b4305880c88fa4af71.mat/MD5E-s18869346--43214e51f11909b4305880c88fa4af71.mat
+../../.git/annex/objects/QQ/4k/MD5E-s18835816--60b803cca6ee31cfbd3cca8f14ad3ca3.mat/MD5E-s18835816--60b803cca6ee31cfbd3cca8f14ad3ca3.mat

+ 1 - 1
data/erp/sub-005_erp.mat

@@ -1 +1 @@
-../../.git/annex/objects/83/z4/MD5E-s18859050--a75b9e9d57f74c0318da54ffa2b126d9.mat/MD5E-s18859050--a75b9e9d57f74c0318da54ffa2b126d9.mat
+../../.git/annex/objects/Pq/54/MD5E-s18883791--72fb4b4ad3a426167969c293de1e54d1.mat/MD5E-s18883791--72fb4b4ad3a426167969c293de1e54d1.mat

+ 1 - 1
data/erp/sub-005_erp_bl.mat

@@ -1 +1 @@
-../../.git/annex/objects/wM/fM/MD5E-s18843674--b589004cdaadee3c2814d947f34d6556.mat/MD5E-s18843674--b589004cdaadee3c2814d947f34d6556.mat
+../../.git/annex/objects/wx/VQ/MD5E-s18901907--d425de4cc903eea09809ba5972680b0a.mat/MD5E-s18901907--d425de4cc903eea09809ba5972680b0a.mat

+ 1 - 1
data/erp/sub-006_erp.mat

@@ -1 +1 @@
-../../.git/annex/objects/Xg/0w/MD5E-s17941060--5d682071fb82bfe8bbc330d96596d59b.mat/MD5E-s17941060--5d682071fb82bfe8bbc330d96596d59b.mat
+../../.git/annex/objects/9k/wg/MD5E-s17810953--38c0af19a6013bc3caa7d99cb2a32e11.mat/MD5E-s17810953--38c0af19a6013bc3caa7d99cb2a32e11.mat

+ 1 - 1
data/erp/sub-006_erp_bl.mat

@@ -1 +1 @@
-../../.git/annex/objects/0z/vq/MD5E-s17925782--3b779935183213530816ddb44ee51ee3.mat/MD5E-s17925782--3b779935183213530816ddb44ee51ee3.mat
+../../.git/annex/objects/Wj/gX/MD5E-s17829237--b5200d124beb77d4df7375d5aea4c119.mat/MD5E-s17829237--b5200d124beb77d4df7375d5aea4c119.mat

+ 1 - 1
data/erp/sub-007_erp.mat

@@ -1 +1 @@
-../../.git/annex/objects/Gf/wJ/MD5E-s19567079--d8432ac2abe9930f25a7f2a48ecff6c7.mat/MD5E-s19567079--d8432ac2abe9930f25a7f2a48ecff6c7.mat
+../../.git/annex/objects/xK/JM/MD5E-s19654546--0a9a48fdbbc544d290111b3967fd4388.mat/MD5E-s19654546--0a9a48fdbbc544d290111b3967fd4388.mat

+ 1 - 1
data/erp/sub-007_erp_bl.mat

@@ -1 +1 @@
-../../.git/annex/objects/Pw/G4/MD5E-s19571480--6647bbcdbe8d1e77c2f222fa9a21441c.mat/MD5E-s19571480--6647bbcdbe8d1e77c2f222fa9a21441c.mat
+../../.git/annex/objects/WK/qG/MD5E-s19659919--54a2c997bea7b24dff3ee8ed008d09ca.mat/MD5E-s19659919--54a2c997bea7b24dff3ee8ed008d09ca.mat

+ 1 - 1
data/erp/sub-008_erp.mat

@@ -1 +1 @@
-../../.git/annex/objects/2V/xx/MD5E-s17940101--768732fd1aea53c733c7815b5ca61759.mat/MD5E-s17940101--768732fd1aea53c733c7815b5ca61759.mat
+../../.git/annex/objects/4k/f0/MD5E-s17379509--ed95ed9151cd44d1202ad0c29324193f.mat/MD5E-s17379509--ed95ed9151cd44d1202ad0c29324193f.mat

+ 1 - 1
data/erp/sub-008_erp_bl.mat

@@ -1 +1 @@
-../../.git/annex/objects/gV/vq/MD5E-s17932576--ee364bf7cb3bbaecf03ff9c8fba55f6a.mat/MD5E-s17932576--ee364bf7cb3bbaecf03ff9c8fba55f6a.mat
+../../.git/annex/objects/60/fJ/MD5E-s17392096--64ea3f176c281264d56e43095ea9f90d.mat/MD5E-s17392096--64ea3f176c281264d56e43095ea9f90d.mat

+ 1 - 1
data/erp/sub-009_erp.mat

@@ -1 +1 @@
-../../.git/annex/objects/5X/M4/MD5E-s19586421--a9735a35f2a9411e37e0c873e79e1f5b.mat/MD5E-s19586421--a9735a35f2a9411e37e0c873e79e1f5b.mat
+../../.git/annex/objects/Z2/vx/MD5E-s19625054--99676430521388a5f1a38b5ad1f21928.mat/MD5E-s19625054--99676430521388a5f1a38b5ad1f21928.mat

+ 1 - 1
data/erp/sub-009_erp_bl.mat

@@ -1 +1 @@
-../../.git/annex/objects/Qm/Kw/MD5E-s19570785--f1ee80bacf09621e29d75e9afa0e94a6.mat/MD5E-s19570785--f1ee80bacf09621e29d75e9afa0e94a6.mat
+../../.git/annex/objects/gj/Z2/MD5E-s19638193--4de606996ddc406c34ae488715fca10b.mat/MD5E-s19638193--4de606996ddc406c34ae488715fca10b.mat

+ 1 - 1
data/erp/sub-010_erp.mat

@@ -1 +1 @@
-../../.git/annex/objects/mg/xV/MD5E-s18858038--f7b3e466a9fd5426e6e31d31908b70fc.mat/MD5E-s18858038--f7b3e466a9fd5426e6e31d31908b70fc.mat
+../../.git/annex/objects/QG/9X/MD5E-s18688778--03113451f53f227c6ba3c1625820f82a.mat/MD5E-s18688778--03113451f53f227c6ba3c1625820f82a.mat

+ 1 - 1
data/erp/sub-010_erp_bl.mat

@@ -1 +1 @@
-../../.git/annex/objects/MJ/ZQ/MD5E-s18856822--f0abe75e1dbdd7a532aa84c34e9ab0b2.mat/MD5E-s18856822--f0abe75e1dbdd7a532aa84c34e9ab0b2.mat
+../../.git/annex/objects/82/X0/MD5E-s18675674--3f37b0674a9213564760c60feb873359.mat/MD5E-s18675674--3f37b0674a9213564760c60feb873359.mat

+ 1 - 1
data/erp/sub-011_erp.mat

@@ -1 +1 @@
-../../.git/annex/objects/xQ/z1/MD5E-s17944899--5bac574571be9f40036cdb247883bbc1.mat/MD5E-s17944899--5bac574571be9f40036cdb247883bbc1.mat
+../../.git/annex/objects/75/0f/MD5E-s17854680--18fced4e0398cacc5ba70ab4651786e5.mat/MD5E-s17854680--18fced4e0398cacc5ba70ab4651786e5.mat

+ 1 - 1
data/erp/sub-011_erp_bl.mat

@@ -1 +1 @@
-../../.git/annex/objects/wq/PZ/MD5E-s17942264--6e004af92befcdb2e8b6f1f3a37543d7.mat/MD5E-s17942264--6e004af92befcdb2e8b6f1f3a37543d7.mat
+../../.git/annex/objects/KK/Kk/MD5E-s17848475--36ee3247389171440339f552624c988a.mat/MD5E-s17848475--36ee3247389171440339f552624c988a.mat

+ 1 - 1
data/erp/sub-012_erp.mat

@@ -1 +1 @@
-../../.git/annex/objects/vV/7j/MD5E-s17972043--a10c461923ba6221568dc7182e234cd6.mat/MD5E-s17972043--a10c461923ba6221568dc7182e234cd6.mat
+../../.git/annex/objects/jf/XV/MD5E-s17986248--8b778570a4a3820b79771f8e2fcf50cd.mat/MD5E-s17986248--8b778570a4a3820b79771f8e2fcf50cd.mat

+ 1 - 1
data/erp/sub-012_erp_bl.mat

@@ -1 +1 @@
-../../.git/annex/objects/QG/P2/MD5E-s17962934--2e76e841c9ce9f41b302e0023c476e48.mat/MD5E-s17962934--2e76e841c9ce9f41b302e0023c476e48.mat
+../../.git/annex/objects/fv/G9/MD5E-s17990003--6d0e865f0d68263583ed7190067b16e8.mat/MD5E-s17990003--6d0e865f0d68263583ed7190067b16e8.mat

+ 1 - 1
data/erp/sub-013_erp.mat

@@ -1 +1 @@
-../../.git/annex/objects/p6/80/MD5E-s19580400--c9ca493f0ea6a2d6f62c3629f4676d6f.mat/MD5E-s19580400--c9ca493f0ea6a2d6f62c3629f4676d6f.mat
+../../.git/annex/objects/Vp/z4/MD5E-s19226030--8aabe1006c8037337927fbd0ccf1af69.mat/MD5E-s19226030--8aabe1006c8037337927fbd0ccf1af69.mat

+ 1 - 1
data/erp/sub-013_erp_bl.mat

@@ -1 +1 @@
-../../.git/annex/objects/wv/gx/MD5E-s19584074--d0082012a01e5bb9810beda03436bf10.mat/MD5E-s19584074--d0082012a01e5bb9810beda03436bf10.mat
+../../.git/annex/objects/xf/Pw/MD5E-s19209960--d4410162a338edd2d2b4ae367ae3c58c.mat/MD5E-s19209960--d4410162a338edd2d2b4ae367ae3c58c.mat

+ 0 - 0
data/erp/sub-014_erp.mat


Some files were not shown because too many files changed in this diff