processDFF_Adaptive.m 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508
  1. clear
  2. %% IMPORTANT NOTES
  3. % Voltage conversion equation: Force = m * ([Voltage] - b)
  4. % These constants will change if you use a different pull module or
  5. % recalibrate it (use Check_Pull_Calibration_Values script to recalculate)
  6. % paper position for saving .pdfs
  7. % x = -0.8, y = 1.0, width = 11.0, height = 7.1875
  8. %% Set Variables
  9. fr = 29.6; %Framerate
  10. frames = 10000; %Number of Frames in the Session
  11. m = 25.045; %Contants from Pull Calibration Script:
  12. b = 1.628; %Force = m * ([Voltage] - b)
  13. % m = 21.973, b = 0.049 (Newer values, but recalibrate for future experiments)
  14. %% Extract and Classify Pulls from Mototrak and Thorsync Files
  15. %Extract adaptive threshold from the selected MotoTrak file
  16. [file,path] = uigetfile('*MotoTrak', 'Select Mototrak file');
  17. cd(path);
  18. D = dir(file);
  19. [~,~,ext] = fileparts(file);
  20. data = MotoTrakFileRead(file);
  21. threshold = [data.trial.parameters];
  22. lower_thresh = threshold(:,2:2:end);
  23. volt_thresh = (lower_thresh / 25.045) + 1.628;
  24. %Load ThorSync file and find times the trials start
  25. foldername = uigetdir('Choose folder to save results');
  26. [filename, pathname] = uigetfile('*.h5', 'Pick a Sync Episode file');
  27. if isequal(filename,0) || isequal(pathname,0)
  28. disp('User pressed cancel')
  29. return
  30. else
  31. disp(['User selected ', fullfile(pathname, filename)])
  32. end
  33. fnam = [pathname,filename];
  34. dataOut = ThorsyncLoadSimple(fnam);
  35. time = dataOut.time;
  36. trial = dataOut.FrameIn;
  37. time(trial(1,:) == 0) = [];
  38. Frame_In = uniquetol(time', 0.0001) - 0.05; %subtract 0.05s to account for the delay between MotoTrak and ThorSync
  39. %Find frames where the animal is pulling and classify them based on adaptive threshold
  40. end_frames = frames - 1;
  41. lower = (15/m) + b;
  42. upper = (18/m) + b;
  43. three = (3/m) + b;
  44. nine = (9/m) + b;
  45. %segment voltage data into cell by trial
  46. Pull_trial = cell(1, length(Frame_In));
  47. trial_time = cell(1, length(Frame_In));
  48. segment = floor(Frame_In * 100000);
  49. for i = 1:length(Frame_In) - 1
  50. Pull_trial{1,i} = dataOut.Pull(segment(i):segment(i+1));
  51. trial_time{1,i} = dataOut.time(segment(i):segment(i+1));
  52. for j = length(Frame_In)
  53. Pull_trial{1,j} = dataOut.Pull(segment(j):end);
  54. trial_time{1,j} = dataOut.time(segment(j):end);
  55. end
  56. end
  57. %find peaks in each block greater than 3 grams
  58. Peaks = cell(1, length(Frame_In));
  59. locations = cell(1, length(Frame_In));
  60. width = cell(1, length(Frame_In));
  61. for i = 1:length(Frame_In)
  62. [pks, locs, widths] = findpeaks(Pull_trial{1,i}, trial_time{1,i}, 'MinPeakHeight', three, 'MinPeakDistance', 0.1 , 'MaxPeakWidth', 1);
  63. Peaks{1,i} = pks;
  64. locations{1,i} = locs;
  65. width{1,i} = widths;
  66. end
  67. peakTimes = cell2mat(locations);
  68. pks = cell2mat(Peaks);
  69. peakFrames = cell2mat(locations) * fr;
  70. peakFrames(peakFrames > end_frames) = [];
  71. NumPeaks = length(peakFrames);
  72. trial_start = 1:1:NumPeaks;
  73. trial_end = 1:1:NumPeaks;
  74. widthFrames = cell2mat(width) * fr;
  75. avg_pull_frame = mean(widthFrames);
  76. avg_pull_frame = round(avg_pull_frame, 0);
  77. intFrames = round(peakFrames);
  78. intTimes = round((peakFrames/fr) * 100000);
  79. avg_pull_time = round((avg_pull_frame/fr) * 100000);
  80. for i = 1:NumPeaks
  81. trial_start(1,i) = peakFrames(1,i) - widthFrames(1,i);
  82. trial_end(1,i) = peakFrames(1,i) + widthFrames(1,i);
  83. end
  84. R_trial_start = floor(trial_start);
  85. R_trial_end = ceil(trial_end);
  86. %Find start and end times of pulls based on the width of the peak
  87. pullFrames = reshape([R_trial_start(:) R_trial_end(:)]', [1, 2* NumPeaks]);
  88. if pullFrames(1,1) < 3 %excludes first trial if there are an insufficient number of pull Frames for it
  89. pullFrames(:,1) = [];
  90. pullFrames(:,1) = [];
  91. end
  92. pullForce = m * (pks - b);
  93. save(fullfile(foldername,'pullForce'),'pullForce','-v7.3');
  94. %excludes pulls that are cut off when ThorSync recording stops
  95. pullFrames(pullFrames > end_frames) = [];
  96. if mod(length(pullFrames), 2) > 0
  97. pullFrames(end) = [];
  98. end
  99. [row, col] = find(pks > three & pks < nine);
  100. threetonine = peakTimes(:,col);
  101. threetonineFrames = threetonine * fr;
  102. [row, col] = find(pks > nine & pks < lower);
  103. ninetofifteen = peakTimes(:,col);
  104. ninetofifteenFrames = ninetofifteen * fr;
  105. [row, col] = find(pks > lower & pks < upper);
  106. fifteentoeighteen = peakTimes(:,col);
  107. fifteentoeighteenFrames = fifteentoeighteen * fr;
  108. [row, col] = find(pks > upper);
  109. eighteenplus = peakTimes(:,col);
  110. eighteenplusFrames = eighteenplus * fr;
  111. %% Classify Successful and Unsuccessful Peaks based on Adaptive Threshold
  112. sPeaks = cell(1,length(Frame_In));
  113. uPeaks = cell(1,length(Frame_In));
  114. slocs = cell(1,length(Frame_In));
  115. ulocs = cell(1,length(Frame_In));
  116. swidths = cell(1,length(Frame_In));
  117. uwidths = cell(1,length(Frame_In));
  118. if length(Frame_In) < length(volt_thresh)
  119. q = length(Frame_In);
  120. else
  121. q = length(volt_thresh);
  122. end
  123. %if script throws index exceeds matrix error here replace length(Frame_In)
  124. %with the length of volt_thresh, make sure to change it back
  125. for i = 1:q
  126. [col] = find(Peaks{1,i} > volt_thresh(i));
  127. sPeaks{1,i} = Peaks{1,i}(col);
  128. slocs{1,i} = locations{1,i}(col);
  129. swidths{1,i} = width{1,i}(col);
  130. [col] = find(Peaks{1,i} < volt_thresh(i));
  131. uPeaks{1,i} = Peaks{1,i}(col);
  132. ulocs{1,i} = locations{1,i}(col);
  133. uwidths{1,i} = width{1,i}(col);
  134. end
  135. %find pull frames for each peak based on width and location
  136. successPeaks = cell2mat(slocs) * fr;
  137. successWidth = cell2mat(swidths) * fr;
  138. unsuccessPeaks = cell2mat(ulocs) * fr;
  139. unsuccessWidth = cell2mat(uwidths) * fr;
  140. trial_start = 1:1:length(successPeaks);
  141. trial_end = 1:1:length(successPeaks);
  142. for i = 1:length(successPeaks)
  143. trial_start(1,i) = successPeaks(1,i) - successWidth(1,i);
  144. trial_end(1,i) = successPeaks(1,i) + successWidth(1,i);
  145. end
  146. R_trial_start = floor(trial_start);
  147. R_trial_end = ceil(trial_end);
  148. successFrames = reshape([R_trial_start(:) R_trial_end(:)]', [1, 2* length(successPeaks)]);
  149. if successFrames > 0
  150. if successFrames(1,1) < 3 %excludes first trial if there are an insufficient number of pull Frames for it
  151. successFrames(:,1) = [];
  152. successFrames(:,1) = [];
  153. end
  154. %excludes pulls that are cut off when ThorSync recording stops
  155. successFrames(successFrames > frames) = [];
  156. if mod(length(successFrames), 2) > 0
  157. successFrames(end) = [];
  158. end
  159. end
  160. trial_start = 1:1:length(unsuccessPeaks);
  161. trial_end = 1:1:length(unsuccessPeaks);
  162. for i = 1:length(unsuccessPeaks)
  163. trial_start(1,i) = unsuccessPeaks(1,i) - unsuccessWidth(1,i);
  164. trial_end(1,i) = unsuccessPeaks(1,i) + unsuccessWidth(1,i);
  165. end
  166. R_trial_start = floor(trial_start);
  167. R_trial_end = ceil(trial_end);
  168. unsuccessFrames = reshape([R_trial_start(:) R_trial_end(:)]', [1, 2* length(unsuccessPeaks)]);
  169. if unsuccessFrames(1,1) < 3 %excludes first trial if there are an insufficient number of pull Frames for it
  170. unsuccessFrames(:,1) = [];
  171. unsuccessFrames(:,1) = [];
  172. end
  173. %excludes pulls that are cut off when ThorSync recording stops
  174. unsuccessFrames(unsuccessFrames > frames) = [];
  175. if mod(length(unsuccessFrames), 2) > 0
  176. unsuccessFrames(end) = [];
  177. end
  178. for i = 1:NumPeaks
  179. mean_start(1,i) = intFrames(1,i) - avg_pull_frame;
  180. mean_end(1,i) = intFrames(1,i) + avg_pull_frame;
  181. time_start(1,i) = intTimes(1,i) - avg_pull_time;
  182. time_end(1,i) = intTimes(1,i) + avg_pull_time;
  183. end
  184. meanFrames = reshape([mean_start(:) mean_end(:)]', [1, 2*NumPeaks]);
  185. meanTimes = reshape([time_start(:) time_end(:)]', [1, 2*NumPeaks]);
  186. if meanFrames(1,1) < 3
  187. meanFrames(:,1) = [];
  188. meanFrames(:,1) = [];
  189. end
  190. meanFrames(meanFrames > end_frames) = [];
  191. if mod(length(meanFrames), 2) > 0
  192. meanFrames(end) = [];
  193. end
  194. if meanTimes(1,1) < (3/fr * 100000)
  195. meanTimes(:,1) = [];
  196. meanTimes(:,1) = [];
  197. end
  198. meanTimes(meanTimes > (end_frames/fr * 100000)) = [];
  199. if mod(length(meanTimes), 2) > 0
  200. meanTimes(end) = [];
  201. end
  202. window = 5; %# of seconds in each trial
  203. Frame_In = round(Frame_In * 100000);
  204. Frame_Out = Frame_In + (window * 100000);
  205. Frame_times = reshape([Frame_In(:) Frame_Out(:)]', [1, 2*length(Frame_In)]);
  206. Frame_times(Frame_times > ((end_frames/fr)*100000)) = [];
  207. if mod(length(Frame_times), 2) > 0
  208. Frame_times(end) = [];
  209. end
  210. %% Initialize variables for Correlations and Classification
  211. dir = '';
  212. autoClassifyNeurons = true;
  213. pTA = 2; % frames before and after pull that should be included in the average
  214. [newNeurons,fluorescenceData,classifications,binaryPullTimes,pulls,options] = processDFFInitVars(dir,pullFrames,fr,autoClassifyNeurons,pTA);
  215. % Unpack Data from function call
  216. numFrames = options.numFrames;
  217. numNeurons = options.numNeurons;
  218. xpoints = options.xpoints;
  219. framerate = options.framerate;
  220. %
  221. Fdf = fluorescenceData.Fdf;
  222. Cd = fluorescenceData.Cd;
  223. Sp = fluorescenceData.Sp;
  224. if pks > 0
  225. binarySuccessTimes = zeros(1,numFrames);
  226. for i = 1:2:length(successFrames)
  227. binarySuccessTimes(successFrames(i) - pTA:successFrames(i+1) + pTA) = 1;
  228. end
  229. end
  230. binarySuccessTimes(binarySuccessTimes > frames) = [];
  231. binaryUnsuccessTimes = zeros(1,numFrames);
  232. for i = 1:2:length(unsuccessFrames)
  233. binaryUnsuccessTimes(unsuccessFrames(i) - pTA:unsuccessFrames(i+1) + pTA) = 1;
  234. end
  235. binaryUnsuccessTimes(binaryUnsuccessTimes > frames) = [];
  236. Cd_N = [];
  237. for i = 1:numNeurons
  238. Cd_N(i,:) = (Cd(i,:) - min(Cd(i,:))) / (max(Cd(i,:)) - min(Cd(i,:)));
  239. end
  240. fulldff = Cd_N';
  241. fullCd = Cd;
  242. activeCd = Cd_N(classifications.active,:);
  243. quiescentCd = Cd_N(classifications.quiescent,:);
  244. indiscCd = Cd_N(classifications.indisc,:);
  245. cells = cat(1, classifications.active, classifications.quiescent, classifications.indisc);
  246. cells = sortrows(cells, 'ascend');
  247. Cd_N = Cd_N(cells,:);
  248. Cd = Cd(cells,:);
  249. numNeurons = size(Cd_N,1);
  250. %activity_Cd = Cd_N + 1;
  251. behavior = cell(1, length(meanFrames) / 2);
  252. activity = cell(numNeurons, length(meanFrames) / 2);
  253. for i = 1:numNeurons
  254. for j = 1:2:length(meanFrames)%j = 1:2:length(meanFrames)
  255. behavior{1,j} = dataOut.Pull(1, meanTimes(j) : meanTimes(j+1));
  256. activity{i,j} = Cd_N(i, pullFrames(j) : pullFrames(j+1));
  257. end
  258. end
  259. activity(cellfun('isempty',activity)) = [];
  260. activity = reshape(activity, [numNeurons, length(meanFrames)/2]);
  261. activity_cat = cell2mat(activity);
  262. behavior(cellfun('isempty',behavior)) = [];
  263. %[coeff,score,latent,tsquared,explained,mu] = pca(activity_cat);
  264. %Preliminary pca analysis for activity
  265. for i = 1:numNeurons
  266. for j = 1:size(behavior,2) - 1
  267. temp = corrcoef(behavior{1,j}, behavior{1,j+1});
  268. pull_corr{1,j} = temp(1,2);
  269. end
  270. end
  271. for i = 1:numNeurons - 1
  272. temp2 = corrcoef(activity_cat(i,:), activity_cat(i+1,:));
  273. activity_corr(i,:) = temp2(1,2);
  274. end
  275. avg_pull_corr = mean(abs(cell2mat(pull_corr)));
  276. avg_act_corr = mean(activity_corr);
  277. Correlations = struct('pull_corr',avg_pull_corr, 'activity_corr', avg_act_corr);
  278. %% Preliminary Analysis of Peaks during Pulls vs Queiscent Periods
  279. flourFrames = cell(1,numNeurons);
  280. behaviorPeaks = zeros(1,numNeurons);
  281. nonBehaviorPeaks = zeros(1,numNeurons);
  282. SbehaviorPeaks = zeros(1,numNeurons);
  283. UbehaviorPeaks = zeros(1,numNeurons);
  284. allPeaks = zeros(1,numNeurons);
  285. for i = 1:numNeurons
  286. ROI = Cd_N(i,:)';
  287. [pks, locs, widths] = findpeaks(ROI, xpoints/framerate, 'MinPeakHeight', 0.1, 'MinPeakDistance', 0.35);
  288. temp = locs * fr;
  289. temp = locs * fr;
  290. temp2 = locs * fr;
  291. flourFrames{1,i} = round(temp,0);
  292. for k = 1:length(locs)
  293. if binaryPullTimes(1,flourFrames{1,i}(1,k)) > 0
  294. temp(1,k) = 1;
  295. else
  296. temp(1,k) = 0;
  297. end
  298. end
  299. for k = 1:length(locs)
  300. if binarySuccessTimes(1,flourFrames{1,i}(1,k)) > 0
  301. temp(1,k) = 1;
  302. end
  303. end
  304. for k = 1:length(locs)
  305. if binaryUnsuccessTimes(1,flourFrames{1,i}(1,k)) > 0
  306. temp2(1,k) = 1;
  307. end
  308. end
  309. behaviorPeaks(1,i) = length(temp(temp == 1));
  310. nonBehaviorPeaks(1,i) = length(temp(temp == 0));
  311. SbehaviorPeaks(1,i) = length(temp(temp == 1));
  312. UbehaviorPeaks(1,i) = length(temp2(temp2 == 1));
  313. allPeaks(1,i) = length(temp);
  314. end
  315. peakPercent = behaviorPeaks ./ allPeaks;
  316. peakPercent(allPeaks < 5) = [];
  317. [plotPercent,index] = sortrows(peakPercent', 'descend');
  318. x = 1:length(peakPercent);
  319. % figure
  320. % scatter(x, plotPercent)
  321. behavior_ca = struct('behaviorPeaks', behaviorPeaks, 'nonBehaviorPeaks', nonBehaviorPeaks, 'SbehaviorPeaks', SbehaviorPeaks, 'UbehaviorPeaks', UbehaviorPeaks, 'allPeaks', allPeaks);
  322. % Choose which data we want to use for everything.
  323. dff = Cd_N';
  324. %Cd_N = normalized, Cd = not normalized
  325. figure;
  326. K = heatmap(Cd_N);
  327. K.GridVisible = 'off';
  328. K.Colormap = hot;
  329. %% Save files for segmentation
  330. save(fullfile(foldername,'Cd_N'),'Cd_N','-v7.3');
  331. save(fullfile(foldername,'classifications'),'classifications','-v7.3');
  332. save(fullfile(foldername,'activeCd'),'activeCd','-v7.3');
  333. save(fullfile(foldername,'quiescentCd'),'quiescentCd','-v7.3');
  334. save(fullfile(foldername,'indiscCd'),'indiscCd','-v7.3');
  335. save(fullfile(foldername,'peakFrames'),'peakFrames','-v7.3');
  336. save(fullfile(foldername,'successPeaks'),'successPeaks','-v7.3');
  337. save(fullfile(foldername,'unsuccessFrames'),'unsuccessPeaks','-v7.3');
  338. save(fullfile(foldername,'threetonineFrames'),'threetonineFrames','-v7.3');
  339. save(fullfile(foldername,'ninetofifteenFrames'),'ninetofifteenFrames','-v7.3');
  340. save(fullfile(foldername,'fifteentoeighteenFrames'),'fifteentoeighteenFrames','-v7.3');
  341. save(fullfile(foldername,'eighteenplusFrames'),'eighteenplusFrames','-v7.3');
  342. save(fullfile(foldername,'behavior_ca'),'behavior_ca','-v7.3');
  343. save(fullfile(foldername,'Correlations'),'Correlations','-v7.3');
  344. %% Start by looking at all neurons plotted on same plot and stacked
  345. % Colors
  346. co = ...
  347. [0 0.4470 0.7410;
  348. 0.8500 0.3250 0.0980;
  349. 0.9290 0.6940 0.1250;
  350. 0.4940 0.1840 0.5560;
  351. 0.4660 0.6740 0.1880;
  352. 0.3010 0.7450 0.9330;
  353. 0.6350 0.0780 0.1840];
  354. %% Plot shows all neuron plots stacked.
  355. figure;
  356. plot(xpoints/framerate, bsxfun(@plus,dff,0:numNeurons-1))
  357. hold on
  358. p = patch(xpoints/framerate, binaryUnsuccessTimes * numNeurons, 'k');
  359. set(p, 'FaceAlpha', 0.2)
  360. set(p, 'EdgeAlpha', 0)
  361. if successpeaks > 0
  362. m = patch(xpoints/framerate, binarySuccessTimes * numNeurons, 'r');
  363. set(m, 'FaceAlpha', 0.4)
  364. set(m, 'EdgeAlpha', 0)
  365. end
  366. nvs = gca;
  367. nvs.XTick = 0:50:max(xpoints/framerate);
  368. nvs.YTick = 0:10:numNeurons;
  369. if framerate ~= 1
  370. xlabel('Time (seconds)');
  371. else
  372. xlabel('Frame');
  373. end
  374. ylabel('Neuron ID');
  375. title('All Neurons Stacked');
  376. set(gca,'fontsize',24)
  377. set(gca,'LooseInset',get(gca,'TightInset'));
  378. saveas(gcf,strcat(foldername,'/dff','.fig'));
  379. %% Population, Active, Quiescent, Indiscriminant Averages
  380. active = classifications.active;
  381. quiesc = classifications.quiescent;
  382. indisc = classifications.indisc;
  383. figure;
  384. plot(xpoints/framerate, mean(fulldff,2)+3, 'col', co(1,:)) % Population Average
  385. hold on;
  386. plot(xpoints/framerate, mean(fulldff(:,active),2)+2, 'col', co(2,:)) % Active Average
  387. plot(xpoints/framerate, mean(fulldff(:,quiesc),2)+1, 'col', co(3,:)) % Quiescent Average
  388. plot(xpoints/framerate, mean(fulldff(:,indisc),2), 'col', co(4,:)) % Indiscriminant Active Average
  389. lgd = legend(['Population Average (n=' num2str(length(newNeurons)) ')'], ...
  390. ['Active Average (n=' num2str(length(active)) ')'], ...
  391. ['Quiescent Average (n=' num2str(length(quiesc)) ')'], ...
  392. ['Indiscriminant Average (n=' num2str(length(indisc)) ')'], ...
  393. 'Location', 'eastoutside');
  394. % plot(xpoints/framerate, mean(dffActive,2)+2,'color', [0,0,0]+0.8)
  395. % plot(xpoints/framerate, mean(dffActive,2)+2, 'col', co(2,:)) % Active Average
  396. lgd.FontSize = 24;
  397. p = patch(xpoints/framerate, binaryPullTimes * 4, 'b');
  398. set(p, 'FaceAlpha', 0.4)
  399. set(p, 'EdgeAlpha', 0) % Pull Bars
  400. set(gca,'YTick',[])
  401. xlabel('Time (seconds)');
  402. set(gca,'fontsize',24)
  403. set(gca,'LooseInset',get(gca,'TightInset'));