figure_neurotrace.asv 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479
  1. function figure_neurotrace(fld)
  2. fprintf('\n======================================================\n');
  3. fprintf('-- Creating Figure neurotrace --\n');
  4. fprintf('======================================================\n');
  5. %% settings
  6. green = [23, 105, 13]./255;
  7. red = [201, 0, 34]./255;
  8. cols = [green; 0.3 0.3 0.3; red; 1.00,0.84,0.00];
  9. snrthres = 2.5;
  10. smoothfact = 15; mindays = 3;
  11. falpha = 1; % set to 1 for converting to illustrator
  12. do_cleantraces = true; % if true we throw out artefact traces
  13. % citerion: avg emplitude in first 100ms after stimulus onset should be
  14. % at least 3 times the standard deviation in the preceding 100 ms
  15. do_latency = true;
  16. %% load RTs
  17. if exist(fullfile(fld.basedir, 'results','figure_behavior','RTs.mat'),'file')
  18. load(fullfile(fld.basedir, 'results','figure_behavior','RTs.mat'),'RTs');
  19. else
  20. error('RTs missing, run figure_behavior.m first');
  21. end
  22. %% plots
  23. % load traces
  24. monkeys = {'M1','M2'};
  25. wm = [];
  26. %% plot
  27. f1 = figure;
  28. set(f1,'Position',[500 500 1600 800])
  29. % individual animals
  30. for mi = 1:2
  31. monkey = monkeys{mi};
  32. savedir = fullfile(fld.basedir,'results','figure_neurotrace');
  33. load(fullfile(savedir, [monkey '_averages_snr' num2str(snrthres) '_mindays' num2str(mindays) '.mat']),...
  34. 'traces','tracesLUT','grandtraces','grandtracesLUT','env_t');
  35. traces_ALL{mi} = traces; %#ok<*AGROW,*NASGU>
  36. tracesLUT_ALL{mi} = tracesLUT;
  37. grandtraces_ALL{mi} = grandtraces;
  38. grandtracesLUT_ALL{mi} = grandtracesLUT;
  39. env_t_ALL{mi} = env_t;
  40. figure(f1); subplot(2,3,mi+1); hold on;
  41. mns = []; sems = []; trcs = cell(0);
  42. for cond = 1:3
  43. if do_cleantraces
  44. incl = grandtracesLUT(:,2)==cond;
  45. get_traces = grandtraces(incl,:);
  46. sel_LUT = grandtracesLUT(incl,:);
  47. incl_ALL{mi,cond} = incl;
  48. prewin = env_t > -0.1 & env_t < 0;
  49. postwin = env_t > 0 & env_t < 0.1;
  50. sd_pre = std(get_traces(:,prewin),0,2);
  51. m_post = mean(get_traces(:,postwin),2);
  52. snr_sel = m_post > 3*sd_pre;
  53. incl = incl(snr_sel');
  54. get_traces = get_traces(snr_sel',:);
  55. newLUT = sel_LUT(snr_sel',:);
  56. % now average sites over sessions
  57. get_traces_ = get_traces; % backup
  58. get_traces = [];
  59. for rs = unique(newLUT(:,1))'
  60. if sum(newLUT(:,1)==rs)>1
  61. get_traces = [get_traces;...
  62. mean(get_traces_(newLUT(:,1)==rs,:))];
  63. else
  64. get_traces = [get_traces; get_traces_(newLUT(:,1)==rs,:)];
  65. end
  66. end
  67. recsites{mi,cond}=unique(newLUT(:,1));
  68. else
  69. incl = tracesLUT(:,2)==cond;
  70. get_traces = traces(incl,:);
  71. sel_LUT = tracesLUT(incl,:);
  72. incl_ALL{mi,cond} = incl;
  73. newLUT = sel_LUT;
  74. recsites{mi,cond}=unique(newLUT(:,1));
  75. end
  76. % calculate the mean across channels
  77. s_traces = [];
  78. for t = 1:size(get_traces,1)
  79. s_traces(t,:) = smooth(get_traces(t,:),smoothfact);
  80. end
  81. s_traces_ALL{mi,cond} = s_traces;
  82. mn = mean(s_traces);
  83. mns(cond,:) = mn; % for calculating the difference between conditions
  84. trcs{cond} = s_traces; % for calculating the modulation onset
  85. sem = std(s_traces)./sqrt(sum(incl));
  86. sems(cond,:) = sem;
  87. t2 = [env_t*1e3, fliplr(env_t*1e3)];
  88. inBetween = [mn+sem, fliplr(mn-sem)];
  89. fill(t2, inBetween, 'g','LineStyle','none','FaceColor',cols(cond,:),...
  90. 'FaceAlpha',falpha); hold all
  91. plot(env_t*1e3,mn,'Color',cols(cond,:));
  92. RT=RTs{mi}(cond);
  93. plot([RT RT],[0 1],'--','Color',cols(cond,:),'LineWidth',2)
  94. xlim([0 0.25*1e3]); ylim([0 1]);
  95. end
  96. title(monkeys{mi}); xlabel('time(ms)'); ylabel('MUA');
  97. % only include sites with all conditions
  98. if size(recsites{mi,1},1) <= size(recsites{mi,2},1) && ...
  99. size(recsites{mi,1},1) <= size(recsites{mi,3},1)
  100. rsidx = [1 2 3];
  101. elseif size(recsites{mi,2},1) < size(recsites{mi,1},1) && ...
  102. size(recsites{mi,2},1) < size(recsites{mi,3},1)
  103. rsidx = [2 1 3];
  104. elseif size(recsites{mi,3},1) < size(recsites{mi,1},1) && ...
  105. size(recsites{mi,3},1) < size(recsites{mi,2},1)
  106. rsidx = [3 1 2];
  107. end
  108. rsinc{mi,rsidx(1)} = ismember(recsites{mi,rsidx(1)},recsites{mi,rsidx(1)});
  109. rsinc{mi,rsidx(2)} = ismember(recsites{mi,rsidx(2)},recsites{mi,rsidx(1)});
  110. rsinc{mi,rsidx(3)} = ismember(recsites{mi,rsidx(3)},recsites{mi,rsidx(1)});
  111. inRF = {'target','','distractor'};
  112. for cond = [1 3 4]
  113. figure(f1)
  114. subplot(2,3,mi+4);
  115. if cond < 4
  116. df = trcs{cond}(rsinc{mi,cond},:) - ...
  117. trcs{2}(rsinc{mi,2},:); % difference for each channel separately
  118. mn = mean(df);
  119. csem = std(trcs{cond}(rsinc{mi,cond},:) - ...
  120. trcs{2}(rsinc{mi,2},:))./...
  121. sqrt(size(trcs{cond}(rsinc{mi,cond},:),1));
  122. else
  123. df = trcs{1}(rsinc{mi,1},:) - ...
  124. trcs{3}(rsinc{mi,3},:);
  125. mn = mean(df);
  126. csem = std(trcs{1}(rsinc{mi,1},:) - ...
  127. trcs{3}(rsinc{mi,3},:))./...
  128. sqrt(size(trcs{1}(rsinc{mi,1},:),1));
  129. end
  130. inBetween = [mn+csem, fliplr(mn-csem)];
  131. fill(t2, inBetween, 'g','LineStyle','none','FaceColor',cols(cond,:),...
  132. 'FaceAlpha',falpha); hold all
  133. plot(env_t*1e3,mn,'Color',cols(cond,:));
  134. xlim([0 0.25*1e3]); ylim([-0.15 0.25]);
  135. % let's calculate the latency of modulation per channel
  136. if do_latency
  137. do_latfig=0;
  138. if mi==1
  139. until = find(env_t<0.25,1,'last');
  140. else
  141. until = find(env_t<0.21,1,'last');
  142. end
  143. lat = []; coeff = []; rs = []; converge = [];
  144. for i = 1:size(df,1) % loop channels
  145. cur_resp = df(i,1:until)';
  146. if cond==3
  147. % the latency function cannot fit downward modulation
  148. cur_resp = cur_resp*-1;
  149. end
  150. [lat(i),~] = latencyfit_jp(cur_resp,env_t(1:until)'*1000,do_latfig);
  151. end
  152. % latency on average
  153. cur_resp = mn(1:until)';
  154. if cond==3
  155. % the latency function cannot fit downward modulation
  156. cur_resp = cur_resp*-1;
  157. end
  158. lt = latencyfit_jp(smooth(cur_resp,20),env_t(1:until)'*1000,do_latfig);
  159. if cond < 4
  160. rng('default') % for reproducibility
  161. nsamp = 100;
  162. btstrp_LT = bootstrp(nsamp,@latencyfit_jp,smooth(cur_resp,20),env_t(1:until)'*1000,0);
  163. fprintf([monkey ' ' inRF{cond} ' - Bootstrapped latency [' num2str(nsamp) ' samples] =====\n'])
  164. fprintf(['mean: ' num2str(mean(btstrp_LT,'omitnan')) ', std:' num2str(std(btstrp_LT,'omitnan')) '\n'])
  165. BLT{mi,cond}=btstrp_LT;
  166. end
  167. if ~isnan(lt) % if lt = nan, latencyfit_jp gives no figure, so we shouldn't make a title either
  168. if cond < 4
  169. title([monkey ', fit on average response, ' inRF{cond} ' in RF']);
  170. else
  171. title([monkey ', fit on average response modulation']);
  172. end
  173. end
  174. if cond < 4
  175. disp([monkey ', latency of modulation onset when ' inRF{cond} ' is in RF: ' ...
  176. num2str(round(mean(lat,'omitnan'))) 'ms (' num2str(round(lt)) ...
  177. 'ms as estimated on the average response)']);
  178. else
  179. disp([monkey ', latency of targ-distr modulation: ' ...
  180. num2str(round(mean(lat,'omitnan'))) 'ms (' num2str(round(lt)) ...
  181. 'ms as estimated on the average response)']);
  182. end
  183. %disp(['individual channel estimates: ' num2str(lat)]);
  184. ModLatency{mi,cond} = lt;
  185. figure(f1);
  186. plot([lt lt],[-0.2 0.25],'--','Color',cols(cond,:),'LineWidth',2)
  187. if isnan(lt)
  188. plot([round(mean(lat,'omitnan')) round(mean(lat,'omitnan'))],[-0.2 0.25],...
  189. ':','Color',cols(cond,:),'LineWidth',2)
  190. end
  191. end
  192. end
  193. figure(f1)
  194. plot([0 .25*1e3],[0 0],'k');
  195. title(monkeys{mi}); xlabel('time(ms)'); ylabel('Modulation(MUA)');
  196. % save the extra cleaned traces
  197. save(fullfile(savedir,'Traces_SNR_trialbased.mat'),...
  198. 's_traces_ALL','recsites','rsinc');
  199. %% statistics
  200. window_means = [];
  201. win_idx = find(env_t>0.15 & env_t<0.20);
  202. for cond = 1:3
  203. if do_cleantraces
  204. incl = grandtracesLUT(:,2)==cond;
  205. get_traces = grandtraces(incl,win_idx); %#ok<*FNDSB>
  206. else
  207. incl = tracesLUT(:,2)==cond;
  208. get_traces = traces(incl,win_idx);
  209. end
  210. incl = tracesLUT(:,2)==cond;
  211. % calculate the average in a window
  212. s_traces = [];
  213. for t = 1:size(get_traces,1)
  214. s_traces(t,:) = smooth(get_traces(t,:),smoothfact);
  215. end
  216. window_means(:,cond) = mean(s_traces,2);
  217. end
  218. anova1(window_means);
  219. wm = [wm; window_means];
  220. wm2{mi} = window_means;
  221. end
  222. figure(f1); subplot(2,3,1); hold on;
  223. % pooled animals
  224. for cond = 1:3
  225. traces = [s_traces_ALL{1,cond};s_traces_ALL{2,cond}];
  226. % calculate the mean across channels
  227. % get_traces = traces(incl,:);
  228. get_traces = traces;
  229. s_traces = [];
  230. for t = 1:size(get_traces,1)
  231. s_traces(t,:) = smooth(get_traces(t,:),smoothfact);
  232. end
  233. mn = mean(s_traces);
  234. mns(cond,:) = mn; % for calculating the difference between conditions
  235. trcs{cond} = s_traces; % for calculating the modulation onset
  236. sem = std(s_traces)./sqrt(sum(size(s_traces,1)));
  237. sems(cond,:) = sem;
  238. t2 = [env_t*1e3, fliplr(env_t*1e3)];
  239. inBetween = [mn+sem, fliplr(mn-sem)];
  240. fill(t2, inBetween, 'g','LineStyle','none','FaceColor',cols(cond,:),...
  241. 'FaceAlpha',falpha); hold all
  242. RT=RTs{3}(cond);
  243. plot([RT RT],[0 1],'--','Color',cols(cond,:),'LineWidth',2)
  244. plot(env_t*1e3,mn,'Color',cols(cond,:));
  245. xlim([0 0.25*1e3]); ylim([0 1]);
  246. end
  247. title('BOTH animals pooled'); xlabel('time(ms)'); ylabel('MUA');
  248. inRF = {'target','','distractor'};
  249. for cond=1:3
  250. rsinc{3,cond} = [rsinc{1,cond};rsinc{2,cond}];
  251. end
  252. for cond = [1 3 4]
  253. figure(f1)
  254. subplot(2,3,4);
  255. if cond < 4
  256. df = trcs{cond}(rsinc{3,cond},:) - ...
  257. trcs{2}(rsinc{3,2},:); % difference for each channel separately
  258. mn = mean(df);
  259. csem = std(trcs{cond}(rsinc{3,cond},:) - ...
  260. trcs{2}(rsinc{3,2},:))./...
  261. sqrt(size(trcs{cond}(rsinc{3,cond},:),1));
  262. else
  263. df = trcs{1}(rsinc{3,1},:) - ...
  264. trcs{3}(rsinc{3,3},:);
  265. mn = mean(df);
  266. csem = std(trcs{1}(rsinc{3,1},:) - ...
  267. trcs{3}(rsinc{3,3},:))./...
  268. sqrt(size(trcs{1}(rsinc{3,1},:),1));
  269. end
  270. inBetween = [mn+csem, fliplr(mn-csem)];
  271. fill(t2, inBetween, 'g','LineStyle','none','FaceColor',cols(cond,:),...
  272. 'FaceAlpha',falpha); hold all
  273. plot(env_t*1e3,mn,'Color',cols(cond,:));
  274. xlim([0 0.25*1e3]); ylim([-0.15 0.25]);
  275. % let's calculate the latency of modulation per channel
  276. if do_latency
  277. do_latfig=0;
  278. if mi==1
  279. until = find(env_t<0.25,1,'last');
  280. else
  281. until = find(env_t<0.21,1,'last');
  282. end
  283. lat = []; coeff = []; rs = []; converge = [];
  284. for i = 1:size(df,1) % loop channels
  285. cur_resp = df(i,1:until)';
  286. if cond==3
  287. % the latency function cannot fit downward modulation
  288. cur_resp = cur_resp*-1;
  289. end
  290. [lat(i),~] = latencyfit_jp(cur_resp,env_t(1:until)'*1000,do_latfig);
  291. end
  292. %collect latencty
  293. clat{cond} = lat;
  294. % latency on average
  295. do_latfig=1;
  296. cur_resp = mn(1:until)';
  297. if cond==3
  298. % the latency function cannot fit downward modulation
  299. cur_resp = cur_resp*-1;
  300. end
  301. lt = latencyfit_jp(smooth(cur_resp,20),env_t(1:until)'*1000,do_latfig);
  302. if cond < 4
  303. rng('default') % for reproducibility
  304. nsamp = 100;
  305. btstrp_LT = bootstrp(nsamp,@latencyfit_jp,smooth(cur_resp,20),env_t(1:until)'*1000,0);
  306. fprintf([inRF{cond} ' - Bootstrapped latency [' num2str(nsamp) ' samples] =====\n'])
  307. fprintf(['mean: ' num2str(mean(btstrp_LT,'omitnan')) ', std:' num2str(std(btstrp_LT,'omitnan')) '\n'])
  308. BLT{3,cond}=btstrp_LT;
  309. end
  310. if ~isnan(lt) % if lt = nan, latencyfit_jp gives no figure, so we shouldn't make a title either
  311. if cond < 4
  312. title(['BOTH monkeys, fit on average response, ' inRF{cond} ' in RF']);
  313. else
  314. title('BOTH monkeys, fit on average response modulation');
  315. end
  316. end
  317. if cond < 4
  318. disp(['BOTH monkeys, latency of modulation onset when ' inRF{cond} ' is in RF: ' ...
  319. num2str(round(mean(lat,'omitnan'))) 'ms (' num2str(round(lt)) ...
  320. 'ms as estimated on the average response)']);
  321. else
  322. disp(['BOTH monkeys, latency of targ-distr modulation: ' ...
  323. num2str(round(mean(lat,'omitnan'))) 'ms (' num2str(round(lt)) ...
  324. 'ms as estimated on the average response)']);
  325. end
  326. %disp(['individual channel estimates: ' num2str(lat)]);
  327. figure(f1)
  328. plot([lt lt],[-0.2 0.25],'--','Color',cols(cond,:),'LineWidth',2)
  329. if isnan(lt)
  330. plot([round(mean(lat,'omitnan')) round(mean(lat,'omitnan'))],[-0.2 0.25],...
  331. ':','Color',cols(cond,:),'LineWidth',2)
  332. end
  333. end
  334. end
  335. figure(f1)
  336. plot([0 .25*1e3],[0 0],'k');
  337. title('ALL animals pooled'); xlabel('time(ms)'); ylabel('Modulation (MUA)');
  338. %% do a bootstrapped latency analysis to get some stats
  339. rng('default') % for reproducibility
  340. nsamp = 1000;
  341. btstrp_LAT = bootstrp(nsamp,@nanmean,[clat{1}' clat{3}']);
  342. [h,p,ci,stats]=ttest(btstrp_LAT(:,1)-btstrp_LAT(:,2));
  343. fprintf('== BTSTRP comparison of latencies ===\n');
  344. fprintf(['Mean difference in latency (T-SD): ' ...
  345. num2str(mean(btstrp_LAT(:,1)-btstrp_LAT(:,2))) ', SEM: ' ...
  346. num2str(std(btstrp_LAT(:,1)-btstrp_LAT(:,2))./sqrt(size(btstrp_LAT,1))) ...
  347. 'ms\n']);
  348. fprintf([num2str(sum((btstrp_LAT(:,1)-btstrp_LAT(:,2))<0)) '/' num2str(nsamp) ...
  349. ' T before SD, p = ' num2str(sum((btstrp_LAT(:,1)-btstrp_LAT(:,2))>0)/nsamp) ...
  350. ' that H0[T not before SD] is rejected \n']);
  351. fprintf(['ttest t(' num2str(stats.df) ') = ' num2str(stats.tstat) ...
  352. ', p = ' num2str(p) '\n']);
  353. %% use the bootstrapped latency estimates for stats
  354. fprintf('== Comparison of bootstrapped T-SD latencies ===\n');
  355. for mi=1:3
  356. [h,p,ci,stats]=ttest(BLT{mi,1}-BLT{mi,3});
  357. nn = sum(~isnan());
  358. if mi<3
  359. fprintf(['-- Monkey ' num2str(mi) ' --\n']);
  360. else
  361. fprintf('-- BOTH Monkeys --\n');
  362. end
  363. fprintf(['Mean difference in latency (T-SD): ' ...
  364. num2str(mean(BLT{mi,1}-BLT{mi,3},'omitnan')) ', SEM: ' ...
  365. num2str(std(BLT{mi,1}-BLT{mi,3},'omitnan')./sqrt(sum(~isnan(BLT{mi,1})))) ...
  366. 'ms\n']);
  367. fprintf([num2str(sum((BLT{mi,1}-BLT{mi,3})<0)) '/' num2str(100) ...
  368. ' T before SD, p = ' num2str(sum((BLT{mi,1}-BLT{mi,3})>0)/100) ...
  369. ' that H0[T not before SD] is rejected \n']);
  370. fprintf(['ttest t(' num2str(stats.df) ') = ' num2str(stats.tstat) ...
  371. ', p = ' num2str(p) '\n']);
  372. end
  373. %% statistics
  374. % do a simple paired t-test for each monkey
  375. fprintf('=============================\n');
  376. fprintf(' Paired T-test \n');
  377. fprintf('=============================\n');
  378. clear h p stats
  379. for mi = 1:2
  380. mns = wm2{mi};
  381. p = []; vp=[]; ci=1;
  382. for cond = [1 3]
  383. [vh,vp(end+1)]=vartest2(mns(:,cond),mns(:,2));
  384. [h,p(end+1),~,stats{mi,ci}] = ttest(mns(:,cond), mns(:,2));
  385. ci=ci+1;
  386. end
  387. [vh,vp(end+1)]=vartest2(mns(:,1),mns(:,3));
  388. [h,p(end+1),~,stats{mi,3}] = ttest(mns(:,1), mns(:,3));
  389. disp([monkeys{mi} ', target response increased: p=' num2str(p(1)) ...
  390. ' t = ' num2str(stats{mi,1}.tstat) ', df = ' num2str(stats{mi,1}.df) ...
  391. ' (unequal var p = ' num2str(vp(1)) ')']);
  392. disp([monkeys{mi} ', distractor response decreased: p=' num2str(p(2)) ...
  393. ' t = ' num2str(stats{mi,2}.tstat) ', df = ' num2str(stats{mi,2}.df) ...
  394. ' (unequal var p = ' num2str(vp(2)) ')']);
  395. disp([monkeys{mi} ', targ vs distractor: p=' num2str(p(3)) ...
  396. ' t = ' num2str(stats{mi,3}.tstat) ', df = ' num2str(stats{mi,3}.df) ...
  397. ' (unequal var p = ' num2str(vp(3)) ')']);
  398. end
  399. %Both together
  400. mns = [wm2{1}; wm2{2}];
  401. p = [];vp=[]; ci=1;
  402. for cond = [1 3]
  403. [vh,vp(end+1)]=vartest2(mns(:,cond),mns(:,2));
  404. [h,p(end+1),~,stats{3,ci}] = ttest(mns(:,cond), mns(:,2));
  405. ci=ci+1;
  406. end
  407. [vh,vp(end+1)]=vartest2(mns(:,1),mns(:,3));
  408. [h,p(end+1),~,stats{3,3}] = ttest(mns(:,1), mns(:,3));
  409. disp(['BOTH, target response increased: p=' num2str(p(1)) ...
  410. ' t = ' num2str(stats{3,1}.tstat) ', df = ' num2str(stats{3,1}.df) ...
  411. ' (unequal var p = ' num2str(vp(1)) ')']);
  412. disp(['BOTH, distractor response decreased: p=' num2str(p(2)) ...
  413. ' t = ' num2str(stats{3,2}.tstat) ', df = ' num2str(stats{3,2}.df) ...
  414. ' (unequal var p = ' num2str(vp(2)) ')']);
  415. disp(['BOTH, targ vs distractor: p=' num2str(p(3)) ...
  416. ' t = ' num2str(stats{3,3}.tstat) ', df = ' num2str(stats{3,3}.df) ...
  417. ' (unequal var p = ' num2str(vp(3)) ')']);
  418. %% save figure
  419. figure(f1)
  420. saveas(gcf,fullfile(savedir,'figure_neurotrace.svg'));