Created
December 24, 2015 07:50
-
-
Save digideskio/57fea3f91fe032d519b0 to your computer and use it in GitHub Desktop.
strike behavioral analysis, force analysis
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| ## strike.probe.r | |
| ## a software for the analysis of strike data obtained from mantis shrimp | |
| ## https://gist.github.com/4180275 | |
| library(R.matlab) | |
| library(lattice) | |
| library(timsac) | |
| library(ggplot2) | |
| working.dir <- "~/Dropbox/Analysis2/R_programming/strike_probe" | |
| ## functions for high sampling rate (500k Hz) strike force data | |
| ## class: strike | |
| read.strike <- function(strike.dir=NA, animal.id=NA, species=NA, force.scale=NA){ | |
| ## read strike data into "strikes" in the current workspace | |
| ## ex) read.strike(strike.dir=N.oerstedii.4.dirs[2], animal.id="Y4", | |
| ## species="N.oerstedii", force.scale=15.03 (N/V)) | |
| previous.working.dir <- getwd() | |
| if (is.na(strike.dir)){ | |
| cat("Enter the directory path containing force data. \n") | |
| strike.dir <- scan( what="" ) | |
| } | |
| setwd(strike.dir) | |
| files <- list.files() | |
| files <- files[order(as.numeric(gsub('.mat', '', gsub('strike', '', files))))] | |
| if (is.na(animal.id)){ | |
| cat("Enter animal id and push return key. \n") | |
| animal.id <- scan( what="" ) | |
| } | |
| if (is.na(species)){ | |
| cat("Enter animal species and push return key. \n") | |
| species <- scan( what="" ) | |
| } | |
| if (is.na(force.scale)){ | |
| cat("Enter Newton/Voltage and push return key. \n") | |
| force.scale <- as.numeric(scan( what="" )) | |
| } | |
| strikes <- list() | |
| n = 1 | |
| for (each.file in files) { | |
| cat(".") | |
| one.strike <- readMat(each.file) | |
| is.rewarded <- one.strike[[1]][[1]][1,1] | |
| strike.time <- one.strike[[1]][[2]][1,1] | |
| voltage <- one.strike[[1]][[3]][,1] | |
| offset <- one.strike[[1]][[4]][1,1] | |
| voltage <- voltage + offset | |
| force <- ( voltage + offset ) * force.scale | |
| if ( n == 1 ) { | |
| duration <- one.strike[[1]][[5]][1,1] | |
| strike.threshold <- one.strike[[1]][[6]][1,1] | |
| reward.threshold <- one.strike[[1]][[7]][1,1] | |
| time <- seq(0, by = 1/500, length.out = length(force)) | |
| strikes <- list(header = list( | |
| animal.id = animal.id, | |
| species = species, | |
| strike.dir = strike.dir, | |
| force.scale = force.scale, | |
| duration = duration, | |
| strike.threshold = strike.threshold, | |
| reward.threshold = reward.threshold, | |
| time = time )) | |
| } | |
| strikes <- c( strikes, list(each.strike = list( | |
| is.rewarded = is.rewarded, | |
| strike.time = strike.time, | |
| voltage = voltage, | |
| force = force ))) | |
| n = n + 1 | |
| } | |
| cat("\n") | |
| setwd(previous.working.dir) | |
| class(strikes) <- "strikes" | |
| return(strikes) | |
| } | |
| select.strikes <- function(strikes){ | |
| num <- length(strikes) | |
| act <- c() | |
| time <- strikes[[1]]$time | |
| for (i in 2:num) { | |
| x <- strikes[[i]] | |
| # browser() | |
| plot(time, x$force, type="l") | |
| midline <- diff(range(time))/2 | |
| text(max(time), min(x$force), | |
| labels="click here, \n if this is an actual strike", pos=2) | |
| abline(v=midline, col="red") | |
| is.act <- locator(1)$x | |
| if(is.act > midline) { | |
| cat("strike", paste(i-1), '\n') | |
| act <- c(act, i) | |
| } else { | |
| cat("\n") | |
| } | |
| } | |
| new.strikes <- list() | |
| new.strikes$header <- strikes$header | |
| for (i in act) { | |
| new.strikes <- c(new.strikes, each.strike=list(strikes[[i]])) | |
| } | |
| class(new.strikes) <- "strikes" | |
| return(new.strikes) | |
| } | |
| print.strikes <- function(strikes){ | |
| strike.num <- length(strikes) - 1 | |
| cat(paste(strike.num, 'strikes data. The header information is shown below.\n')) | |
| cat(' ', 'animal id: ') | |
| cat(strikes$header$animal.id, '\n') | |
| cat(' ', 'species: ') | |
| cat(strikes$header$species, '\n') | |
| cat(' ', 'directory of the data: ') | |
| cat(strikes$header$strike.dir, '\n') | |
| cat(' ', 'force scale: ') | |
| cat(strikes$header$force.scale, '\n') | |
| cat(' ', 'duration: ') | |
| cat(strikes$header$duration, '\n') | |
| cat(' ', 'strike threshold: ') | |
| cat(strikes$header$strike.threshold, '\n') | |
| cat(' ', 'reward.threshold: ') | |
| cat(strikes$header$reward.threshold, '\n') | |
| } | |
| export.as.text <- function(strikes){ | |
| strike.n <- length(strikes) - 1 | |
| force.df <- data.frame() | |
| mkdirs("exported_strikes") | |
| setwd("./exported_strikes") | |
| for ( i in 1:strike.n ){ | |
| strike.ind <- i + 1 | |
| voltage <- strikes[[strike.ind]]$voltage | |
| offset <- mean(strikes[[strike.ind]]$voltage[1:(length(voltage)/4)]) | |
| voltage <- voltage - offset | |
| duration <- strikes$header$duration | |
| voltage.df <- data.frame(time = seq(duration/length(voltage), | |
| duration, duration/length(voltage)), | |
| voltage=voltage, voltage=voltage, voltage=voltage) | |
| write.table(voltage.df, file=paste("strike", i, ".txt", sep=""), | |
| col.names=FALSE, | |
| row.names=FALSE) | |
| } | |
| setwd("../") | |
| } | |
| plot.strikes <- function(my.strikes, which.strikes=NA, | |
| cummulative=FALSE) { | |
| time <- my.strikes$header$time | |
| if (is.na(which.strikes)) { | |
| which.strikes <- 1:(length(my.strikes)-1) + 1 | |
| } | |
| strike.num <- length(my.strikes) - 1 | |
| d <- data.frame() | |
| time.stamps.rewarded <- c() | |
| rewarded.strike.ind <- c() | |
| for (i in which.strikes) { | |
| d <- rbind(d, data.frame( | |
| strike.n = i, | |
| force = my.strikes[[i]]$force, | |
| time = time)) | |
| if (my.strikes[[i]]$is.rewarded) { | |
| time.stamps.rewarded <- c(time.stamps.rewarded, my.strikes[[i]]$strike.time) | |
| rewarded.strike.ind <- c(rewarded.strike.ind, i - 1) # because of header | |
| } | |
| } | |
| ## col.seq <- rep("black", strike.num) | |
| ## col.seq[rewarded.strike.ind] <- rep("red", length(rewarded.strike.ind)) | |
| if (cummulative==TRUE) { | |
| plot(time.stamps.rewarded, 1:length(time.stamps.rewarded), type="s", | |
| xlim=c(0, 2000), ylim=c(0, 50), | |
| xlab="Time (sec)", ylab="Cummulative # of actions") | |
| } else { | |
| xyplot(force~time|strike.n, | |
| d, col="black", type="l", | |
| xlab="Time (ms)", ylab = "Force (N)", strip=FALSE) | |
| } | |
| } | |
| ## make data frame of animal 04 | |
| make.df04 <- function(){ | |
| strikes <- read.strike(strike.dir=readline(prompt="enter dir: "), | |
| animal.id="animal04", species="unknown", force.scale=15.03) | |
| new.strikes <- select.strikes(strikes) | |
| d <- summary(new.strikes) | |
| session <- as.numeric(readline(prompt="enter session number: ")) | |
| condition <- readline(prompt="enter condition (rewarded or nonrewarded?): ") | |
| is.rewarded <- rep(0, length(new.strikes)-1) | |
| is.rewarded[d$rewarded.strike.ind] <- 1 | |
| df04 <<- rbind(df04, | |
| data.frame(session=session, condition=condition, | |
| event=1:length(d$peaks), | |
| time=sort(c(d$rewarded.time, d$non.rewarded.time)), | |
| is.rewarded=is.rewarded, | |
| peak=d$peaks)) | |
| } | |
| summary.strikes <- function(my.strikes) { | |
| num.strikes <- length(my.strikes) - 1 | |
| which.strikes <- 1:num.strikes + 1 | |
| time.stamps.rewarded <- c() | |
| time.stamps.nonrewarded <- c() | |
| rewarded.strike.ind <- c() | |
| for (i in which.strikes) { | |
| if (my.strikes[[i]]$is.rewarded) { | |
| time.stamps.rewarded <- c(time.stamps.rewarded, my.strikes[[i]]$strike.time) | |
| rewarded.strike.ind <- c(rewarded.strike.ind, i - 1) # because of header | |
| } else { | |
| time.stamps.nonrewarded <- c(time.stamps.nonrewarded, | |
| my.strikes[[i]]$strike.time) | |
| } | |
| } | |
| time.stamps <- sort(c(time.stamps.rewarded, time.stamps.nonrewarded)) | |
| num.rewarded.strikes <- length(time.stamps.rewarded) | |
| peaks <- c() | |
| for (i in which.strikes) { | |
| peaks <- c(peaks, max(my.strikes[[i]]$force)) | |
| } | |
| summary.d <- list( | |
| animal.id=my.strikes$header$animal.id, | |
| strike.dir=my.strikes$header$strike.dir, | |
| rewarded.strike.ind=rewarded.strike.ind, | |
| rewarded.time=time.stamps.rewarded, | |
| non.rewarded.time=time.stamps.nonrewarded, | |
| peaks=peaks) | |
| return(summary.d) | |
| } | |
| aggregate.action.counts <- function(dirs=N.oerstedii.4.dirs, | |
| animal.id="Y4", species="N.oerstedii", | |
| force.scale=15.03){ | |
| df <- data.frame() | |
| session <- 1 | |
| for (i in dirs) { | |
| cat('reading: ', paste(i), '\n') | |
| strikes <- read.strike(strike.dir=i, animal.id=animal.id, | |
| species=species, force.scale=force.scale) | |
| df <- rbind(df, | |
| data.frame(session=session, | |
| rewarded.time=summary(strikes)$rewarded.time, | |
| action.counts=1:length(summary(strikes)$rewarded.time))) | |
| session <- session + 1 | |
| } | |
| return(df) | |
| } | |
| ## functions for physiological data (text data exported from chart) | |
| ## class: phys | |
| read.phys <- function(phys.dir=NA, file.name="strike"){ | |
| wd <- getwd() | |
| setwd(phys.dir) | |
| files <- list.files() | |
| files <- files[order(as.numeric(gsub('.txt', '', gsub(file.name, '', files))))] | |
| phys <- list() | |
| for (i in files) { | |
| one.phys <- read.table(i) | |
| phys <- c( phys, list(one.phys = list(strike.id=i, phys=one.phys))) | |
| cat(i, "\n") | |
| } | |
| setwd(wd) | |
| class(phys) <- "phys" | |
| return(phys) | |
| } | |
| print.phys <- function(phys){ | |
| cat(length(phys), 'physiological data.', '\n') | |
| } | |
| plot.phys <- function(phys, ch=4){ | |
| strike.num <- length(phys) | |
| ys <- data.frame() | |
| for (i in 1:strike.num) { | |
| y <- phys[[i]]$phys[,ch] | |
| time <- phys[[i]]$phys$V1 - min(phys[[i]]$phys$V1) | |
| ys <- rbind(ys, data.frame(strike.id=i, time=time, y=y)) | |
| } | |
| xyplot(y~time | strike.id, ys, strip=FALSE, type="l") | |
| } | |
| strike2df <- function(strike){ | |
| event.n <- length(strike) - 1 | |
| time <- strike[[1]]$time | |
| phys.df <- data.frame() | |
| for (i in 2:(event.n+1)) { | |
| event <- i - 1 | |
| y <- strike[[i]]$voltage | |
| phys.df <- rbind(phys.df, data.frame(event=event, time=time, y=y, peak=max(y))) | |
| } | |
| return(phys.df) | |
| } | |
| align.phys.peak <- function(phys, ch, w=c(-0.003, 0.003), bw=c(-0.003, -0.002)){ | |
| n <- length(phys) | |
| phys2 <- data.frame() | |
| for (i in 1:n) { | |
| y <- phys[[i]]$phys[, ch] | |
| t <- phys[[i]]$phys[, 1] # time should be channel one | |
| peak <- max(y) | |
| t <- t - t[y==peak][1] | |
| base.line.y <- y[t >= bw[1] & t <= bw[2]] | |
| base.line.t <- t[t >= bw[1] & t <= bw[2]] | |
| y <- y - mean(base.line.y) | |
| base.line.y <- base.line.y - mean(base.line.y) | |
| peak <- max(y) | |
| phys2 <- rbind(phys2, data.frame( | |
| event = i, | |
| time=t[t >= w[1] & t <= w[2]], | |
| y=y[t >= w[1] & t <= w[2]], | |
| peak=peak)) | |
| } | |
| p <- xyplot(y~time | event, phys2, type="l", strip=FALSE) | |
| print(p) | |
| return(phys2) | |
| } | |
| select.emg.onset <- function(phys){ | |
| strike.num <- length(phys) | |
| emg.onsets <- data.frame() | |
| for (i in 1:strike.num) { | |
| emg <- phys[[i]]$phys$V4 | |
| time <- phys[[i]]$phys$V1 | |
| plot(time, emg, type="l") | |
| emg.onset <- locator(1)$x | |
| emg.onsets <- c(emg.onsets, emg.onset) | |
| time <- time - emg.onset | |
| browser() | |
| } | |
| } | |
| ## read Spike2 data which is exported wave marks | |
| read.diff.strike <- function(){ | |
| ## read differentiated strike data into "diff.strikes" in the current workspace | |
| previous.working.dir <- setwd(tk_choose.dir()) | |
| strike.dir <- getwd() | |
| cat(list.files(), sep="\n") | |
| diff.strikes.name <- file.choose() | |
| cat("Enter animal id and push return key. \n") | |
| animal.id <- scan( what="" ) | |
| diff.strikes.raw <- readLines( diff.strikes.name ) | |
| wave.initial.lines <- c() | |
| strike.time <- c() | |
| sampling.rate <- c() | |
| strike.code <- c() | |
| for ( i in 1:( length( diff.strikes.raw ))) { | |
| if ( grepl( "WAVMK", diff.strikes.raw[i] )){ | |
| wave.info <- unlist( strsplit( diff.strikes.raw[i], split = "\t" )) | |
| strike.time <- c(strike.time, as.numeric( wave.info[2] )) | |
| if (length(sampling.rate) == 0){ | |
| sampling.rate <- as.numeric( wave.info[3] ) | |
| } | |
| strike.code <- c( strike.code, as.numeric( wave.info[4] )) | |
| wave.initial.lines <- c( wave.initial.lines, i+1 ) | |
| } | |
| } | |
| wave.length <- diff( wave.initial.lines )[1] - 3 | |
| diff.strikes <<- data.frame() | |
| for ( i in 1:length( wave.initial.lines )){ | |
| diff.strikes <<- rbind( diff.strikes, | |
| data.frame( | |
| animal.id = animal.id, | |
| session = diff.strikes.name, | |
| strike.id = i, | |
| strike.code = strike.code[i], | |
| strike.time = strike.time[i], | |
| time = seq(0, by = sampling.rate, length.out = wave.length), | |
| wave = as.numeric( diff.strikes.raw[ wave.initial.lines[i]: | |
| ( wave.initial.lines[i] + wave.length - 1)] ))) | |
| } | |
| setwd(previous.working.dir) | |
| cat("Differentiated strike data were read into 'diff.strikes' in the current work space.\n") | |
| } | |
| #### EMG analysis | |
| align.phys.onset <- function(phys, ch=4, r=10, bl=200, pdf=FALSE) { | |
| starts <- c() | |
| rec.starts <- c() | |
| for (i in 1:length(phys)) { | |
| bouts <- bout.detect(phys[[i]], ch, r, bl) | |
| starts <- c(starts, bouts$start[1]) | |
| rec.starts <- c(rec.starts, min(bouts$time)) | |
| } | |
| rec.start <- max(rec.starts) | |
| bout.set <- list() | |
| for (i in 1:length(phys)) { | |
| phys[[i]]$phys[,1] <- phys[[i]]$phys[,1] - starts[i] | |
| ## trim phys by rec.start ## | |
| bouts2 <- bout.detect(phys[[i]], ch, r, bl, event=i, pdf=pdf) | |
| bout.set <- c(bout.set, list(bouts2)) | |
| } | |
| return(bout.set) | |
| } | |
| bout.detect <- function(y=phys[[1]], ch=4, r=10, bl=200, pdf=FALSE, event=1){ | |
| y0 <- y$phys[,ch] | |
| t <- y$phys[,1] | |
| yl <- length(y0) | |
| l <- yl %% r | |
| if (l!=0){ | |
| for (i in 1:l) { | |
| y0 <- y0[-1] | |
| t <- t[-1] | |
| } | |
| } | |
| yl <- length(y0) | |
| m <- yl / r | |
| if (m %% 2 == 1){ | |
| y0 <- y0[-((length(y0):(length(y0) - r + 1)))] | |
| t <- t[-((length(t):(length(t) - r + 1)))] | |
| yl <- yl - r | |
| m <- m - 1 | |
| } | |
| yy <- rep(0, m) | |
| tt <- rep(0, m/2) | |
| for (i in 1:m){ | |
| yy[i] <- y0[i*r] | |
| } | |
| for (i in 1:m/2) { | |
| tt[i] <- t[i*r*2] # tvvar | |
| } | |
| z <- tvvar(yy, 2, 6.6e-06, 1.0e-06, FALSE) | |
| z1 <- ngsmth(z$ts, 2, 2.6e-04,, 2, 1.644934, k=200, plot=FALSE) | |
| ## detect 'on' and 'off' timing of the activity from abrupt positive change | |
| zt <- z1$trend[,4] | |
| zd <- diff(zt) | |
| b <- mean(zd[1:5]) | |
| bsd <- sd(zd[1:5]) | |
| on <- which(zd > b + 100*bsd) | |
| first <- c() | |
| middles <- c() | |
| last <- c() | |
| cluster.i <- which(diff(on) > 10) # 10 points silence in trend | |
| if (length(cluster.i) >= 1) { | |
| first.c <- 1:cluster.i[1] | |
| first <- which(zd == max(zd[on[first.c]])) | |
| last.c <- (cluster.i[length(cluster.i)] + 1):length(on) | |
| last <- which(zd == max(zd[on[last.c]])) | |
| if (length(cluster.i) >= 2) { | |
| middles <- c() | |
| for ( i in 2:length(cluster.i)) { | |
| if (i >= 2) { | |
| cluster <- (cluster.i[i-1] + 1):cluster.i[i] | |
| middles <- c(middles, which(zd == max(zd[on[cluster]]))) | |
| } | |
| } | |
| } | |
| on2 <- c(first, middles, last) | |
| } else { | |
| on2 <- on | |
| } | |
| ## 'off' | |
| off <- which(zd < b - 100*bsd) | |
| cluster.i <- which(diff(off) > 10) # 10 points silence in trend | |
| if (length(cluster.i) >= 1) { | |
| first.c <- 1:cluster.i[1] | |
| first <- which(zd == min(zd[off[first.c]])) | |
| last.c <- (cluster.i[length(cluster.i)] + 1):length(off) | |
| last <- which(zd == min(zd[off[last.c]])) | |
| if (length(cluster.i) >= 2) { | |
| middles <- c() | |
| for ( i in 2:length(cluster.i)) { | |
| if (i >= 2) { | |
| cluster <- (cluster.i[i-1] + 1):cluster.i[i] | |
| middles <- c(middles, which(zd == min(zd[off[cluster]]))) | |
| } | |
| } | |
| } | |
| off2 <- c(first, middles, last) | |
| } else { | |
| off2 <- off | |
| } | |
| on3 <- on2 * 2 * r + l | |
| off3 <- off2 * 2 * r + l | |
| off4 <- c() | |
| for ( i in 1:length(on3)) { | |
| if (i == length(on3)) { | |
| if (length(off3[off3 > on3[i]]) >= 1) { | |
| off4 <- c(off4, min(off3[off3 > on3[i]])) | |
| } else { | |
| on3 <- on3[-length(on3)] | |
| } | |
| } else { | |
| off4 <- c(off4, min(off3[off3 > on3[i] & off3 < on3[i+1]])) | |
| } | |
| } | |
| par(mfrow=c(3,1)) | |
| plot(t, y0, type="l", xlab="time (sec)", ylab="EMG (voltage)", main="bout detection") | |
| for (i in 1:length(on3)) { | |
| rect(t[on3[i]], min(y0), t[off4[i]], max(y0), col="gray", border="transparent") | |
| lines(t, y0) | |
| } | |
| plot(tt, z$ts, type="l", xlab="time (sec)", ylab="logarithm of variance)") | |
| lines(x=tt, y=zt, col="gray", lwd=2) | |
| plot(tt[-length(tt)], zd, type="b", xlab="time (sec)", ylab="") | |
| abline(v=t[on3], col="red") | |
| abline(v=t[off4], col="blue") | |
| if (pdf==TRUE){ | |
| dev.copy2pdf(file=paste("bout_", event, ".pdf", sep="")) | |
| } | |
| return(list(time=t, y=y0, start=t[on3], termination=t[off4], z=z)) | |
| } | |
| my.f <- function(){ | |
| source("strike.probe.r") | |
| } | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment