track_msd <- function(x,n=5,framerate=0.1,pxsize=100,truncate=F,dim=2){ if (dim==2){ #for 2D data x$X <- (x$X*pxsize)/1000 #convert pixelsize to um x$Y <- (x$Y*pxsize)/1000 } else if (dim==3){ #for 3D data x$X <- (x$X*pxsize[1])/1000 #convert pixelsize to um x$Y <- (x$Y*pxsize[2])/1000 x$Z <- (x$Z*pxsize[3])/1000 } #calculate MSD for n time intervals coef <- ddply(x,.variables = "track",.fun= function(x) { result <- vector(length = n) #put first frame of track at zero x$frame <- x$frame-x$frame[1]+1 if(nrow(x)>n+1){ #test effect of truncating tracks to first number of steps, skipped by default if(truncate){ x <- x[1:6,] } #loop over different time intervals sapply(1:n,function(j){ #loop over all steps of tracks sum <- unlist(sapply(1:nrow(x),simplify = F,function(k){ if (is.element(x[k,1]+j,x[,1])){ #check if point is present in track, this deals with gaps which_point <- which(x[,1]==x[k,1]+j) if (dim==2){ sum <- ((x[k,2]-x[which_point,2])^2+(x[k,3]-x[which_point,3])^2) #determine squared displacement between points } else if (dim==3){ sum <- ((x[k,2]-x[which_point,2])^2+(x[k,3]-x[which_point,3])^2+(x[k,5]-x[which_point,5])^2) } return(sum) }})) result[j] <<- mean(sum) #calculate MSD for j time interval }) return(result) #return MSD for different time intervals as vector } }) return(coef) } TRACK_MSD <- function(x,n=5,framerate=0.1,pxsize=100,truncate=F,dim=2){ UseMethod("TRACK_MSD") } TRACK_MSD.default <- function(x,n=5,framerate=0.1,pxsize=100,truncate=F,dim=2){ stop("MSD requires data frame") } TRACK_MSD.data.frame <- function(x,n=5,framerate=0.1,pxsize=100,truncate=F,dim=2){ track_msd(x,n,framerate,pxsize,truncate,dim) } TRACK_MSD.list <- function(x,n=5,framerate=0.1,pxsize=100,truncate=F,dim=2){ llply(x,function(x){ out <- TRACK_MSD(x,n,framerate,pxsize,truncate,dim) out$cellID <- x$cellID[1] return(out) }) }