neuralAnalyses.m 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  1. % Computes behavioral analyses on the dACC dataset.
  2. % function developed by Demetrio Ferro. (C) CC BY-NC-SA 4.0
  3. clear all; close all; clc;
  4. savefolder='./Figures/';
  5. dACC =load('../Data/dACC_all.mat');
  6. % NOTE: CELLS 1-55 subject1, 56-129 subject2
  7. dACC_subject(1:55)=1; dACC_subject(56:length(dACC.data))=2;
  8. Ntrs_dACC=arrayfun(@(cc) dACC.data{cc}.numTrials, 1:length(dACC.data));
  9. Nccs_dACC=length(dACC.data);
  10. %% Loading main data from vars data structures
  11. Vtl_dACC=reshapeACCstruct2varsmat(dACC,5);
  12. Vbl_dACC=reshapeACCstruct2varsmat(dACC,6);
  13. Vtr_dACC=reshapeACCstruct2varsmat(dACC,7);
  14. Vbr_dACC=reshapeACCstruct2varsmat(dACC,8);
  15. Ptl_dACC=reshapeACCstruct2varsmat(dACC,12)./100;
  16. Ptr_dACC=reshapeACCstruct2varsmat(dACC,13)./100;
  17. Ord_dACC=reshapeACCstruct2varsmat(dACC,15);
  18. start_trial_dACC=reshapeACCstruct2varsmat(dACC,1);
  19. start_outcm_dACC=reshapeACCstruct2varsmat(dACC,18)-start_trial_dACC;
  20. startchoice_dACC=reshapeACCstruct2varsmat(dACC,19)-start_trial_dACC;
  21. valid_trs_dACC=double(startchoice_dACC<10 & start_outcm_dACC<10);
  22. startchoice_dACC(valid_trs_dACC==0)=nan;
  23. start_outcm_dACC(valid_trs_dACC==0)=nan;
  24. %% Computing EV and Risk
  25. EVl_dACC = Ptl_dACC.*Vtl_dACC + (1-Ptl_dACC).*Vbl_dACC;
  26. EVr_dACC = Ptr_dACC.*Vtr_dACC + (1-Ptr_dACC).*Vbr_dACC;
  27. EVf_dACC=nan(size(Ord_dACC));
  28. EVs_dACC=nan(size(Ord_dACC));
  29. EVf_dACC(Ord_dACC==1)=EVl_dACC(Ord_dACC==1);
  30. EVf_dACC(Ord_dACC==2)=EVr_dACC(Ord_dACC==2);
  31. EVs_dACC(Ord_dACC==1)=EVr_dACC(Ord_dACC==1);
  32. EVs_dACC(Ord_dACC==2)=EVl_dACC(Ord_dACC==2);
  33. %% Computing psth and for valid i-1 trials
  34. % tb_m1_p3 is -1s, +3s around first offer onset (not choice/outcome event-locked)
  35. % tb_tlock is -1s, +3s around first offer + time-locked choice, + time-locked outcome
  36. timeAxis=(-5e3+20:20:10e3)/1e3; % in seconds
  37. Ntps=length(timeAxis);
  38. psth_dACC0=nan(Nccs_dACC,max(Ntrs_dACC),Ntps);
  39. psth_dACC_offers=nan(Nccs_dACC,max(Ntrs_dACC),Ntps);
  40. psth_dACC_chs=nan(Nccs_dACC,max(Ntrs_dACC),Ntps);
  41. psth_dACC_ocs=nan(Nccs_dACC,max(Ntrs_dACC),Ntps);
  42. tr_st_bin=find(timeAxis<0,1,'last');
  43. for cc=1:Nccs_dACC
  44. psth_dACC0(cc,1:size(dACC.data{cc}.psth,1),:)=dACC.data{cc}.psth;
  45. for tr=1:Ntrs_dACC(cc)
  46. if valid_trs_dACC(cc,tr) %&& ~isnan(start_trial_dACC(cc,tr))
  47. ichs_cc_tr=find(timeAxis<=startchoice_dACC(cc,tr),1,'last');
  48. iche_cc_tr=find(timeAxis>=start_outcm_dACC(cc,tr),1,'first');
  49. psth_dACC_offers(cc,tr,1:(ichs_cc_tr-tr_st_bin+1000/20))=psth_dACC0(cc,tr,[(-(1000/20)+1:0)+tr_st_bin, tr_st_bin+1:ichs_cc_tr]);
  50. %psth_dACC_chs(cc,tr,1:(iche_cc_tr-ichs_cc_tr))=psth_dACC0(cc,tr,ichs_cc_tr+1:iche_cc_tr);
  51. iocs_cc_tr=find(timeAxis<=start_outcm_dACC(cc,tr),1,'last');
  52. psth_dACC_chs(cc,tr,1:(iocs_cc_tr-ichs_cc_tr))=psth_dACC0(cc,tr,ichs_cc_tr+1:iocs_cc_tr);
  53. psth_dACC_ocs(cc,tr,1:(Ntps-iocs_cc_tr+1))=psth_dACC0(cc,tr,iocs_cc_tr:end);
  54. end
  55. end
  56. end
  57. psth_dACC1=cat(3,rmnans(psth_dACC_offers,3),rmnans(psth_dACC_chs,3),rmnans(psth_dACC_ocs,3));
  58. offs_dACC_Ntps=size(rmnans(psth_dACC_offers,3),3);
  59. chcs_dACC_Ntps=size(rmnans(psth_dACC_chs,3),3);
  60. otcs_dACC_Ntps=size(rmnans(psth_dACC_ocs,3),3);
  61. psth_dACC_ntrav=(sum(~isnan(reshape(psth_dACC1,[Nccs_dACC*max(Ntrs_dACC) size(psth_dACC1,3)])))./sum(valid_trs_dACC(:)));
  62. Ntps_psth_dACC_offs_used=sum(psth_dACC_ntrav(1:offs_dACC_Ntps)>.9);
  63. Ntps_psth_dACC_chcs_used=sum(psth_dACC_ntrav(offs_dACC_Ntps+(1:chcs_dACC_Ntps))>.9);
  64. Ntps_psth_dACC_otcs_used=sum(psth_dACC_ntrav(offs_dACC_Ntps+chcs_dACC_Ntps+(1:otcs_dACC_Ntps))>.9);
  65. psth_dACC=cat(3,psth_dACC_offers(:,:,1:Ntps_psth_dACC_offs_used),psth_dACC_chs(:,:,1:Ntps_psth_dACC_chcs_used),psth_dACC_ocs(:,:,1:Ntps_psth_dACC_otcs_used));
  66. timeAxis_psth_tl=[-1000:20:0 20:20:(Ntps_psth_dACC_offs_used+Ntps_psth_dACC_chcs_used+Ntps_psth_dACC_otcs_used-50-1)*20 ]/1000;
  67. timeAxis_psth_li=cumsum([0 Ntps_psth_dACC_offs_used-50-1 Ntps_psth_dACC_chcs_used Ntps_psth_dACC_otcs_used])*20/1000;
  68. psth_dACC_rn=renormtoprestim(psth_dACC,psth_dACC(:,:,1:(1000/20)),3);
  69. % Safety-check: plot histogram of trials available along time axis
  70. %plot((sum(~isnan(reshape(psth_dACC,[Nccs_dACC*max(Ntrs_dACC) size(psth_dACC,3)]))./sum(valid_trs_dACC(:))));
  71. clearvars psth_dACC1 psth_sgACC1
  72. %% REGRESSING EVs JOINTLY, EVENT-LOCKED
  73. Nshf=100; %This will impact comptational time, consider setting >=100
  74. Dsfactor=1;
  75. EVfs_dACC=cat(3,EVf_dACC,EVs_dACC);
  76. clearvars pvstruct*
  77. if 1% joint regression for EV1 and EV2
  78. [~, ~, ~, ~, pv12sig, pv12sig_sh]=fitlmspksvars(psth_dACC_rn,EVfs_dACC,Nshf,Dsfactor);
  79. pvsig_struct.pvdACCsig=pv12sig;
  80. pvsig_struct.pvdACCsig_sh=pv12sig_sh;
  81. pvsig_struct.Ntrs=sum(all(isnan(EVfs_dACC),3),2);
  82. save('./pvsigEV_all_struct_v1.mat','pvsig_struct');
  83. else
  84. load pvsigEV_all_struct_v1.mat
  85. end
  86. hff=figure('Units','Normalized','Position',[0 0 .5 .33]);
  87. plot(timeAxis_psth_tl,squeeze(mean(pvsig_struct.pvdACCsig(:,:,2)))*100,'r'); hold on;
  88. plot(timeAxis_psth_tl,squeeze(mean(pvsig_struct.pvdACCsig(:,:,3)))*100,'b');
  89. plot(timeAxis_psth_tl,prctile(squeeze(mean(pvsig_struct.pvdACCsig_sh(:,:,2,:)))*100,95,2),'r:');
  90. plot(timeAxis_psth_tl,prctile(squeeze(mean(pvsig_struct.pvdACCsig_sh(:,:,3,:)))*100,95,2),'b:');
  91. ylim([0 40]); xlim(timeAxis_psth_tl([1 end])); yl=get(gca,'YLim');
  92. plot(repmat([0 .6 .75 1.35 1.5 1.62 1.74 8.34],2,1),repmat([0 40]',1,8),'k:');
  93. text(0.05,yl(end)*.85,'offer1','rotation',90); text(0.65,yl(end)*.85,'delay1','rotation',90);
  94. text(0.80,yl(end)*.85,'offer2','rotation',90); text(1.40,yl(end)*.85,'delay2','rotation',90); text(8.40,yl(end)*.85,'outcome','rotation',90);
  95. title('Encoding of offer EV_1, EV_2, all trials'); legend({'EV_1','EV_2'},'box','off','Location','NorthEastOutside');
  96. xlabel('time (s)'); ylabel('% significant cells');
  97. hff.Theme='light';
  98. saveas(hff,[savefolder '/Fig2_EVfs_all_dACC_eventlocked.png']);
  99. saveas(hff,[savefolder '/Fig2_EVfs_all_dACC_eventlocked.svg']);
  100. % ---------------------------------SUPPORT----FUNCTIONS----------------------------
  101. %% Removes nans along specified dimension
  102. function [rx,ri]=rmnans(x,dim)
  103. % rx are the non-nan elements
  104. % ri are the non-nan indices
  105. if nargin<2
  106. dim=1;
  107. end
  108. if isvector(x)
  109. rx=x;
  110. ri=1:length(x);
  111. ri(isnan(x))=[];
  112. rx(isnan(x))=[];
  113. elseif ismatrix(x)
  114. rx=x;
  115. if dim==1
  116. ri=1:size(x,1);
  117. ri(all(isnan(x),2))=[];
  118. rx(all(isnan(x),2),:)=[];
  119. elseif dim==2
  120. ri=1:size(x,2);
  121. ri(all(isnan(x),1))=[];
  122. rx(:,all(isnan(x),1))=[];
  123. end
  124. elseif length(size(x))==3
  125. ri=1:size(x,dim);
  126. ri=ri(~all(isnan(x),setdiff(1:3,dim)));
  127. if dim==1
  128. rx=x(ri,:,:);
  129. elseif dim==2
  130. rx=x(:,ri,:);
  131. elseif dim==3
  132. rx=x(:,:,ri);
  133. end
  134. else
  135. error('more than 3D is not supported');
  136. end
  137. end
  138. %% Baseline-normalization for psth
  139. % function developed by Demetrio Ferro. (C) CC BY-NC-SA 4.0
  140. function Xnorm = renormtoprestim(X,Xprestim,dim)
  141. % !important time has in X and Xprestim to lie along dim dimension
  142. Ndims=numel(size(X));
  143. Ndim=size(X,dim);
  144. %if dim==3 -> [1 1 Ndim]
  145. %if dim==2 -> [1 Ndim 1]
  146. NX=size(X);
  147. NP=size(Xprestim);
  148. elsedims=setdiff(1:Ndims,dim);
  149. if ~all(NX(elsedims)==NP(elsedims))
  150. error('X and Xprestim need to match size in all dimensions except dim.');
  151. end
  152. repvec=ones(1,Ndims);
  153. repvec(dim)=Ndim;
  154. Xnorm=(X-repmat(nanmean(Xprestim,dim),repvec)); % De-mean
  155. end
  156. %% Compute Linear model fits
  157. % function developed by Demetrio Ferro. (C) CC BY-NC-SA 4.0
  158. function [pvalues, betas, pvalues_shf, betas_shf, pvalues_sig, pvalues_sig_shf, r2values, r2values_shf]=fitlmspksvars(Xspks,Yvars,Nshf,Dsfactor,pvsig_th)
  159. if nargin<5
  160. if nargin<4
  161. if nargin<3
  162. Nshf=0;
  163. end
  164. Dsfactor=3;
  165. end
  166. pvsig_th=.05;
  167. end
  168. % X is [cells, trials, time ] the neural signal
  169. % Y is [cells, trials~, nvars] the trial variable
  170. [Nccx, Ntrx, Ntp] = size(Xspks);
  171. [Nccy, Ntry, Nvars] = size(Yvars); %for Nvars=1 only computes beta0 and beta1
  172. assert(Nccx==Nccy, 'The two first variables have to match size along first dimension.');
  173. assert(Ntrx==Ntry, 'The two first variables have to match size along second dimension.');
  174. Ntp=Ntp/Dsfactor;
  175. betas=nan(Nccx,Ntp,Nvars+1);
  176. pvalues=nan(Nccx,Ntp,Nvars+1);
  177. r2values=nan(Nccx,Ntp);
  178. pvalues_shf=nan(Nccx,Ntp,Nvars+1,Nshf);
  179. betas_shf=nan(Nccx,Ntp,Nvars+1,Nshf);
  180. r2values_shf=nan(Nccx,Ntp,Nshf);
  181. warning('off','all')
  182. for cc=1:Nccx
  183. Xccmm=movmean(squeeze(Xspks(cc,:,:))',[0 10],"omitnan")'; % works well only for DSfactor==1
  184. Ycc=squeeze(Yvars(cc,:,:));
  185. if Nvars>1
  186. nans2rem=all(isnan(Ycc),2);
  187. Ycc=Ycc(~nans2rem,:);
  188. Nycc=size(Ycc,1);
  189. else
  190. nans2rem=isnan(Ycc);
  191. Ycc=Ycc(~nans2rem);
  192. Nycc=length(Ycc);
  193. end
  194. Xccmm=Xccmm(~nans2rem,:);
  195. Nxcm=size(Xccmm);
  196. parfor tt=1:Nxcm(2)%Ntp
  197. lastwarn('');
  198. gfitccttmdl=fitlm(Ycc,Xccmm(:,tt));
  199. % faster withouth function call
  200. if isempty(lastwarn())
  201. pvalues(cc,tt,:)=gfitccttmdl.Coefficients.pValue;
  202. betas(cc,tt,:)=gfitccttmdl.Coefficients.Estimate;
  203. r2values(cc,tt)=gfitccttmdl.Rsquared.Ordinary;
  204. end
  205. if Nshf>0
  206. shpvs=nan(Nvars+1,Nshf);
  207. shbvs=nan(Nvars+1,Nshf);
  208. shrvs=nan(1,Nshf);
  209. currx=Xccmm(:,tt);
  210. for sh=1:Nshf
  211. lastwarn('');
  212. if Nvars>1
  213. shmdl=fitlm(Ycc(randperm(Nycc),:),currx(randperm(Nxcm(1))));
  214. else
  215. shmdl=fitlm(Ycc(randperm(Nycc)),currx(randperm(Nxcm(1))));
  216. end
  217. if isempty(lastwarn())
  218. shpvs(:,sh)=shmdl.Coefficients.pValue;
  219. shbvs(:,sh)=shmdl.Coefficients.Estimate;
  220. shrvs(sh)=shmdl.Rsquared.Ordinary;
  221. end
  222. end
  223. pvalues_shf(cc,tt,:,:)=shpvs;
  224. betas_shf(cc,tt,:,:)=shbvs;
  225. r2values_shf(cc,tt,:)=shrvs;
  226. end
  227. %gfitccttmdl=[];
  228. end
  229. disp([sprintf('%s',datetime('now','Format','HH:mm')) ' - done: ' num2str(cc) '/' num2str(Nccx) ', ' sprintf('%2.2f',cc/Nccx.*100) '%']);
  230. end
  231. %Safety checks: plot(sum(squeeze(pvalues(:,:,2))<0.05,1))
  232. pvalues_sig=uint8(nanlt(pvalues,pvsig_th)); %uint8 reduces storage overhead
  233. pvalues_sig_shf=uint8(nanlt(pvalues_shf,pvsig_th));
  234. warning('on','all')
  235. end
  236. %% Compare elements in A to be lower than B but keeping NaNs in place
  237. % function developed by Demetrio Ferro. (C) CC BY-NC-SA 4.0
  238. function AltB=nanlt(A,B)
  239. if(isscalar(B) && isnan(B))
  240. error('nan is not allowed as input 2');
  241. end
  242. if isscalar(B)
  243. nanmask=zeros(size(A));
  244. nanmask(isnan(A))=nan;
  245. elseif all(size(A)==size(B))
  246. nanmask=zeros(size(A));
  247. nanmask(isnan(A))=nan;
  248. else
  249. error('check inputs size, input 2 scalar is allowed.');
  250. end
  251. AltB=sum(cat(length(size(A))+1,double(A<B),nanmask),length(size(A))+1);
  252. end
  253. %% Get task variables
  254. function ACCmat=struct2varsmat(ACCstruct, vars_index, start_offset,end_offset)
  255. % The function takes as first input ACCstruct loaded from "../Data/dACC_all.mat" and provides task variables,
  256. % respectively indicized by the second input vars_index, in trial range start_offset:end_offset
  257. % function developed by Demetrio Ferro. (C) CC BY-NC-SA 4.0
  258. if nargin<4
  259. if nargin<3
  260. start_offset=0;
  261. end
  262. end_offset=0;
  263. end
  264. Nccs=length(ACCstruct.data);
  265. Ntrs=arrayfun(@(cc) ACCstruct.data{cc}.numTrials, 1:Nccs);
  266. ACCmat=nan(Nccs,max(Ntrs));
  267. for cc=1:Nccs
  268. Ntrcc=size(ACCstruct.data{cc}.vars,1);
  269. ACCmat(cc,:)=cat(1,ACCstruct.data{cc}.vars(:,vars_index),nan(max(Ntrs)-Ntrcc,1));
  270. ACCmat(cc,1:start_offset)=nan;
  271. ACCmat(cc,Ntrcc-end_offset+1:Ntrcc)=nan;
  272. end
  273. end