https://github.com/gcharvin/autotrack
Tip revision: afe094c4c7f8fe8646b095b54df62ceea3b605e9 authored by Gilles Charvin on 10 November 2020, 08:59:37 UTC
Merge branch 'master' of https://github.com/gcharvin/autotrack
Merge branch 'master' of https://github.com/gcharvin/autotrack
Tip revision: afe094c
at_cellCycle.m
function at_cellCycle(cellindex,display,nosave)
%cellindex : index of the cells to consider
% display=0 : no display
% display=1 : display histogram
% display=2 : display specific temporal trace
% output matrix stats that contains
% Cll position, Cell ID, cell division number, cycle start, cycle end,
% tdiv, tg1, ts, tg2, tanaphase, % timings
% array htb2 fluo,
%
% vbirth, vg1, vs, vg2, vana % cell size
% tbud % interpolated timing at which budding occurs
%array cell area
%stats=[zeros(1,10) zeros(1,100) zeros(1,100)];
stats=[];
% plot sample traj using traj.
% plot mean traj using traj
global segmentation timeLapse at_displayHandles
minTraceDur=60/(timeLapse.interval/60); % 1 peak every 60 minutes at the most
cc=0;
if numel(cellindex)==0
cellindex=1:1:numel(segmentation.tnucleus);
end
for i=1:length(cellindex)
id=cellindex(i);
% detect divisions based on decay of area x mean fluo % or gaussian fit
[arrx ix]= sort([segmentation.tnucleus(id).Obj.image]); % time data for the cell
if length(arrx)<minTraceDur % cell is present for a too short time; bypass
continue
end
% fluo=fluo(ix); % sort fluo data with increasing time
% fluo=fluo-600; % remove zero fo camera
dat=[segmentation.tcells1(id).Obj.Mean];
arrx=[segmentation.tcells1(id).Obj.image];
pix=find(arrx>=segmentation.tcells1(id).birthFrame,1,'first');
fluo=[dat.fluo];
area=[dat.area];
fluo=fluo.*area; fluo=fluo(pix:end);
arrx=arrx(pix:end);
nonzeropix=find(fluo);
if numel(nonzeropix)==0 % no nucleus within cell
continue
end
%fluo=[segmentation.tnucleus(id).Obj.Mean]; % Gaussian fit of nucleus intensity
%fluo=fluo(ix).*area;
%arrx=arrx(1:end-1);
%fluo=fluo(1:end-1);
figure, plot(arrx,fluo);
fluo= smooth(fluo,3); % filter out noise
dfluo=-diff(fluo);
dfluo=[0 ; dfluo]; % add trailing zero to detect early events
% figure, plot(arrx,dfluo); hold on;
stand=std(dfluo);
peak=fpeak(1:1:length(dfluo),dfluo,minTraceDur,[0 length(dfluo) 1.5*stand Inf]); % better function than matlab's fpeak
if display
figure, plot(dfluo); hold on; plot(peak(:,1)', peak(:,2)', 'Color', 'g'); plot(1:length(dfluo),2*stand*ones(1,length(dfluo)),'Color','k');
end
locmax=peak(:,1)';
if numel(locmax)==0 % no division detected ; skip nucleus....
continue
end
% make mother versus daughter distinction
cellcycle=getCellCyleBounds(locmax,id,minTraceDur)
return;
if display
h=figure; plot(arrx,fluo,'Color','b','lineWidth',2); hold on
title(['Cell:' num2str(id)])
%locmax2=locmax+arrx(1)-1;
%line([locmax2' locmax2']',[1330*ones(size(locmax2')) 2000*ones(size(locmax2'))]','Color','m');
end
firstFrame=arrx(1)-1; %segmentation.tnucleus(id).detectionFrame;
tstr=[];
tstr.start=[];
tstr.G1=[];
tstr.S=[];
tstr.G2=[];
tstr.A=[];
tstr.VstartM=[];
tstr.VG1M=[];
tstr.VSM=[];
tstr.VG2M=[];
tstr.AM=[];
tstr.VstartD=[];
tstr.VG1D=[];
tstr.VSD=[];
tstr.VG2D=[];
tstr.AD=[];
areaM=[segmentation.tcells1(id).Obj.area];
dauM=segmentation.tnucleus(id).daughterList;
divtimeM=segmentation.tnucleus(id).divisionTimes;
firstM=segmentation.tnucleus(id).detectionFrame;
icM=[segmentation.tcells1(id).Obj.image];
for i=1:size(cellcycle,1)
if cellcycle(i,3)==0 % Daughter; no defining birth peak
mother=0;
mine=max(1,cellcycle(i,1)-2);
maxe=min(length(fluo),cellcycle(i,2)+4);
areaC=zeros(1,length(mine:maxe));
areaD=zeros(1,length(mine:maxe));
%
nucleusMframes=mine+firstM-1:maxe+firstM-1; % index of tcells
%
[ic ia ib]=intersect(nucleusMframes,icM);
%
areaC(ia)= areaM(ib);
% bud area
% [firstM divtimeM]
% mine+firstM-1
% maxe+firstM-1
pM=find(divtimeM>mine+firstM-1 & divtimeM<maxe+firstM-1,1,'last');
if numel(pM)~=0
bud=dauM(pM);
areaB=[segmentation.tcells1(bud).Obj.area];
imB=[segmentation.tcells1(bud).Obj.image];
fitint=min(length(areaB),4);
if fitint>=2
p = polyfit(imB(1:fitint),areaB(1:fitint),1);
xf=icM(1):1:imB(1)-1;
f = polyval(p,xf);
pixf=find(f>0,1,'first');
imB=[xf(pixf:end) imB];
areaB=[f(pixf:end) areaB];
tbud=xf(pixf)-(firstM-1);
else
tbud=imB(1)-(firstM-1);
end
[ic ia ib]=intersect(nucleusMframes,imB);
areaD(ia) = areaB(ib);
else
tbud=0;
end
rangz=mine:maxe;
nknots=5;
lo = -inf(1,nknots);
up = +inf(1,nknots);
lo(1) = 0; up(1) = 0;
lo(2) = 0;
lo(3) = 0; up(3) = 0;
up(4) = 0;
lo(5) = 0; up(5) = 0;
shape = struct('p',1,'lo',lo,'up',up);
[yfit pp chi2]=splineFitCellCycle(fluo(rangz),nknots,shape);
%t=pp.breaks
if numel(pp.breaks)<5
continue
end
end
if cellcycle(i,3)==1 || cellcycle(i,3)==-1
mine=max(1,cellcycle(i,1)-2);
maxe=min(length(fluo),cellcycle(i,2)+4);
%
areaC=zeros(1,length(mine:maxe));
areaD=zeros(1,length(mine:maxe));
%
nucleusMframes=mine+firstM-1:maxe+firstM-1; % index of tcells
%
[ic ia ib]=intersect(nucleusMframes,icM);
%
areaC(ia)= areaM(ib);
% bud area
pM=find(divtimeM>mine+firstM-1 & divtimeM<maxe+firstM-1,1,'last');
if numel(pM)~=0
bud=dauM(pM);
areaB=[segmentation.tcells1(bud).Obj.area];
imB=[segmentation.tcells1(bud).Obj.image];
fitint=min(length(areaB),4);
if fitint>=2
p = polyfit(imB(1:fitint),areaB(1:fitint),1);
xf=icM(1):1:imB(1)-1;
f = polyval(p,xf);
pixf=find(f>0,1,'first');
imB=[xf(pixf:end) imB];
areaB=[f(pixf:end) areaB];
tbud=xf(pixf)-(firstM-1);
else
tbud=imB(1)-(firstM-1);
end
[ic ia ib]=intersect(nucleusMframes,imB);
areaD(ia) = areaB(ib);
else
tbud=0;
end
if cellcycle(i,3)==1
mother=1;
else
mother=-1;
end
rangz=mine:maxe;
nknots=6;
lo = -inf(1,nknots);
up = +inf(1,nknots);
%lo(1) = 0; up(1) = 0;
%lo(2) = 0;
%lo(3) = 0; up(3) = 0;
%up(4) = 0;
%lo(5) = 0; up(5) = 0;
up(1) = 0;
lo(2) = 0; up(2)=0;
lo(3) = 0;
lo(4) =0 ; up(4) = 0;
up(5) = 0;
lo(6) =0 ; up(6) = 0;
shape = struct('p',1,'lo',lo,'up',up);
[yfit pp chi2]=splineFitCellCycle(fluo(rangz),nknots,shape);
t=pp.breaks;
% pp
if numel(pp.breaks)<6
continue
end
end
%'ok1'
if numel(stats)==0
stats=[zeros(1,14) zeros(1,100) zeros(1,100) zeros(1,16) zeros(1,100) zeros(1,100) zeros(1,100)];
a=1;
else
a=size(stats,1)+1;
end
if numel(tbud)==0
tbud=-1000;
end
[stats tstr]=addToStats(stats,a,id,i,mother,pp,fluo(rangz),rangz,yfit,firstFrame,chi2,tstr,areaD,areaC,area(rangz),tbud);
if display==2
if mother==0 col=[1 0 0];
else col=[0 1 0];
end
% 'ok'
figure(h);
plot(rangz+arrx(1)-1,yfit,'Color',col,'lineWidth',2,'lineStyle','--');
% size(area(rangz)),size(areaD),size(areaC)
% figure; subplot(2,1,1); plot(rangz,fluo(rangz));
% subplot(2,1,2); plot(rangz,areaC,'Color','b'); hold on ; plot(rangz,areaD,'Color','r'); plot(rangz,areaC+areaD,'Color','g');
end
%return;
end
segmentation.tnucleus(id).mothers=tstr;
if display==1
figure(h); set(gcf,'Position',[200 200 1200 600]);
xlabel('Time (frames)','FontSize',24);
ylabel('HTB2-GFP fluo content (A.U.)','FontSize',24);
set(gca,'FontSize',24);
end
cc=cc+1;
fprintf(['Extract cell cycle phases - Cell ID ' num2str(id) '\n']);
end
if nargin==2
disp('done \n');
at_export(stats);
end
if nargin==3
if ischar(nosave)
if strcmp(nosave,'overwrite')
at_export(stats,'overwrite');
end
else
at_export(stats,nosave);
end
end
function [stats , tstr]=addToStats(stats,a,id,i,mother,pp,fluo,rangz,yfit,firstFrame,chi2,tstr,areaB,areaC,area,tbud)
global segmentation timeLapse
% output matrix stats that contains
% Cll position, Cell ID, cell division number, cycle start, cycle end, tdiv, tg1, ts,
% tg2, tanaphase, array htb2 fluo, array cell area
checksum=mean(double(timeLapse.startedDate));
% check if outlier
outlier=0;
%
cc=1;
stats(a,cc)=checksum; cc=cc+1;
stats(a,cc)= segmentation.position; cc=cc+1;
stats(a,cc)= id; cc=cc+1;
stats(a,cc)= i; cc=cc+1;
stats(a,cc)= mother; cc=cc+1;
stats(a,cc)= outlier; cc=cc+1;
stats(a,cc)=firstFrame; cc=cc+1;
includeAna2Cytokinesis=0; % in case the timing between anaphase and cytokinesis should be taken into account
% timing information based on HTB2 marker
if mother==1 || mother==-1
stats(a,cc)= rangz(1); cc=cc+1; %+includeAna2Cytokinesis; fit start
stats(a,cc)= rangz(1)+pp.breaks(2)+includeAna2Cytokinesis; cc=cc+1; %+includeAna2Cytokinesis; cell cycle start
stats(a,cc)= pp.breaks(6)-pp.breaks(2); cc=cc+1; % tdiv
stats(a,cc)= pp.breaks(3)-pp.breaks(2)-includeAna2Cytokinesis; cc=cc+1; % tg1
stats(a,cc)= pp.breaks(4)-pp.breaks(3); cc=cc+1; %ts
stats(a,cc)= pp.breaks(5)-pp.breaks(4); cc=cc+1; % tg2/m
stats(a,cc)= pp.breaks(6)-pp.breaks(5)+includeAna2Cytokinesis; cc=cc+1; % tanaphase + tcytokinesis : thr should be added for both M and D
ori=pp.breaks(2)+includeAna2Cytokinesis;
tstr.start=[tstr.start rangz(1)+pp.breaks(2)+includeAna2Cytokinesis];
tstr.G1=[tstr.G1 pp.breaks(3)-ori];
tstr.S=[tstr.S pp.breaks(4)-ori];
tstr.G2=[tstr.G2 pp.breaks(5)-ori];
tstr.A=[tstr.A pp.breaks(6)+includeAna2Cytokinesis-ori];
end
if mother==0
stats(a,cc)= rangz(1); cc=cc+1; %+includeAna2Cytokinesis; % start of fluo curve ; cell cycle start
stats(a,cc)= rangz(1)+includeAna2Cytokinesis; cc=cc+1; %+includeAna2Cytokinesis; % end of fluo curve ; cell cycle end
stats(a,cc)= pp.breaks(5)+includeAna2Cytokinesis; cc=cc+1; % tdiv
stats(a,cc)= pp.breaks(2); cc=cc+1; % tg1
stats(a,cc)= pp.breaks(3)-pp.breaks(2); cc=cc+1; %ts
stats(a,cc)= pp.breaks(4)-pp.breaks(3); cc=cc+1; % tg2/m
stats(a,cc)= pp.breaks(5)-pp.breaks(4)+includeAna2Cytokinesis; cc=cc+1; % tanaphase + tcytokinesis : thr should be added for both M and D
ori=includeAna2Cytokinesis;
tstr.start=[tstr.start rangz(1)+includeAna2Cytokinesis];
tstr.G1=[tstr.G1 pp.breaks(2)-ori];
tstr.S=[tstr.S pp.breaks(3)-ori];
tstr.G2=[tstr.G2 pp.breaks(4)-ori];
tstr.A=[tstr.A pp.breaks(5)+includeAna2Cytokinesis-ori];
end
%b=stats(a,7:14)
ma=min(length(fluo),100);
% timing information based on HTB2 marker : HTB2 signal
stats(a,cc:cc+ma-1)=fluo(1:ma)/max(fluo); cc=cc+100;
stats(a,cc:cc+ma-1)=yfit(1:ma)/max(fluo); cc=cc+100;
% size information base on cell and nucleus area
%
stats(a,cc)=tbud-tstr.start(end); cc=cc+1; % timing at which bud emerges
stats(a,cc)=areaC(round(tstr.start(end))-(rangz(1)-1)); cc=cc+1; %vol division
stats(a,cc)=areaC(round(tstr.G1(end)+tstr.start(end))-(rangz(1)-1)); cc=cc+1; % vol G1
stats(a,cc)=areaC(round(tstr.S(end)+tstr.start(end))-(rangz(1)-1)); cc=cc+1; % vol S
stats(a,cc)=areaC(round(tstr.G2(end)+tstr.start(end))-(rangz(1)-1)); cc=cc+1; % vol G2
stats(a,cc)=areaC(round(tstr.A(end)+tstr.start(end))-(rangz(1)-1)); cc=cc+1; % vol A
stats(a,cc)=areaB(round(tstr.start(end))-(rangz(1)-1)); cc=cc+1; %vol division
stats(a,cc)=areaB(round(tstr.G1(end)+tstr.start(end))-(rangz(1)-1)); cc=cc+1; % vol G1
stats(a,cc)=areaB(round(tstr.S(end)+tstr.start(end))-(rangz(1)-1)); cc=cc+1; % vol S
stats(a,cc)=areaB(round(tstr.G2(end)+tstr.start(end))-(rangz(1)-1)); cc=cc+1; % vol G2
stats(a,cc)=areaB(round(tstr.A(end)+tstr.start(end))-(rangz(1)-1)); cc=cc+1; % vol A
stats(a,cc)=area(round(tstr.start(end))-(rangz(1)-1)); cc=cc+1; %vol division
stats(a,cc)=area(round(tstr.G1(end)+tstr.start(end))-(rangz(1)-1)); cc=cc+1; % vol G1
stats(a,cc)=area(round(tstr.S(end)+tstr.start(end))-(rangz(1)-1)); cc=cc+1; % vol S
stats(a,cc)=area(round(tstr.G2(end)+tstr.start(end))-(rangz(1)-1)); cc=cc+1; % vol G2
stats(a,cc)=area(round(tstr.A(end)+tstr.start(end))-(rangz(1)-1)); cc=cc+1; % vol A
stats(a,cc:cc+ma-1)=areaC(1:ma); cc=cc+100; % cell size
stats(a,cc:cc+ma-1)=areaB(1:ma); cc=cc+100; % bud size
stats(a,cc:cc+ma-1)=area(1:ma); cc=cc+1; % nucleus size
chi2=chi2/ (max(fluo))^2;
out=checkOutlier(stats,a,chi2,mother);
%if out
%disp(['Cell ' num2str(id) ' - div:' num2str(i) ' was detected as an outlier']);
%fprintf('\n');
%end
%out=0;
stats(a,6)=out;
function out=checkOutlier(stats,a,chi2,mother)
global timeLapse
out=0;
if mother==0 || mother==-1;
coef=1.5;
else
coef=1;
end
%a
if stats(a,10)< timeLapse.autotrack.timing.tdiv(1) || stats(a,10) > timeLapse.autotrack.timing.tdiv(2) out=1; %'ok1',b=stats(a,10)
end
if stats(a,11)< coef*timeLapse.autotrack.timing.tg1(1) || stats(a,11) > coef*timeLapse.autotrack.timing.tg1(2) out=1; %'ok2',b=stats(a,11)
end
if stats(a,12)< timeLapse.autotrack.timing.ts(1) || stats(a,12) > timeLapse.autotrack.timing.ts(2) out=1; %'ok3',b=stats(a,12)
end
if stats(a,13)< timeLapse.autotrack.timing.tg2(1) || stats(a,13) > timeLapse.autotrack.timing.tg2(2) out=1; %'ok4',b=stats(a,13)
end
if stats(a,14)< timeLapse.autotrack.timing.tana(1) || stats(a,14) > timeLapse.autotrack.timing.tana(2) out=1; %'ok5',b=stats(a,14)
end
if chi2> timeLapse.autotrack.timing.chi out=1; %chi2
end
function cellcycle=getCellCyleBounds(locmax,id,minTraceDur)
global segmentation
cellcycle=[]; % array with 3 column : start, end and 0 if daughter, 1 if mother
tcells=segmentation.tcells1(id);
firstSeg=find(segmentation.cells1Segmented,1,'first');
if numel(locmax)==0 % no division detected ; skip nucleus....
return;
end
cc=1; count=0;
if tcells.detectionFrame>firstSeg % cell is born after first frame : first peaka is D division
%if locmax(1)>minTraceDur % first peak correspond to D division
cellcycle(cc,1)=1;
cellcycle(cc,2)=locmax(1);
cellcycle(cc,3)=0; %D
cc=cc+1;
% end
%if locmax(1)<5 % first peak correspond to D birth % bad case to be analyzed
% count=1;
% if numel(locmax)>=2
% cellcycle(cc,1)=locmax(1);
% cellcycle(cc,2)=locmax(2);
% cellcycle(cc,3)=-1; % weird D
% cc=cc+1;
% end
%end
else % cell was present on first frame
if tcells.Obj(1).Mean.fluo==0 % cell has no nucleus on first frame, should be considered as a bud, first peak is D birth
%if numel(locmax)>=2
cellcycle(cc,1)=1; %locmax(1);
cellcycle(cc,2)=locmax(1);
cellcycle(cc,3)=0; % weird D
cc=cc+1;
% count=1;
end
end
for i=2+count:length(locmax)
% if locmax(i-1)<5 % division occurs right after start of movie. don't know if cell is a mother or a daughter --> skip
% continue
% end
cellcycle(cc,1)=locmax(i-1);
cellcycle(cc,2)=locmax(i);
cellcycle(cc,3)=1; % M
cc=cc+1;
end
function [yfit, pp, chi2]=splineFitCellCycle(fluo,nknots,shape)
x = 1:1:length(fluo); x=x-1;
y=fluo;
fixknots = [];
k = 2;
%clear shape
% function increasing
%lo = 0;
%up = +inf;
%shape(1) = struct('p', 1, 'lo', lo, 'up', up);
% Function forced to have follownh values
% s(0)=1, s(3/2)=1, s(2)=2
% s'(0)=1 s'(3)=1
%pntcon(1) = struct('p', 0, 'x', [0 1.5 3], 'v', [0 1 2]);
%pntcon(2) = struct('p', 1, 'x', [0 3], 'v', 1);
% options = struct('animation', 1, ...
% 'figure', 1, ...
% 'waitbar', 1, ...
% 'display', 1, ...
% 'd', 1, 'lambda', 0e-3, 'regmethod', 'c', ...
% 'qpengine', '', ...
% 'sigma', [], ...
% 'shape', shape, ...
% 'pntcon', pntcon);
options = struct('shape', shape,'animation', 0,'maxiter',100);
warning off all
pp = BSFK(x, y, k, nknots, fixknots,options);
warning on all
yfit=ppval(pp,x);
y2=yfit';
chi2=sum( (y2-y).^2 ) / length(y);