r - compute angle between moving vectors -
i have data frame looks this:
structure(list(k = c(1l, 1l, 1l, 1l, 1l, 1l, 1l, 1l, 1l, 1l, 1l, 1l, 1l, 1l, 1l, 1l, 1l, 1l, 1l, 1l, 1l, 1l, 1l, 1l, 1l, 1l, 1l, 1l, 1l, 1l, 1l, 1l, 1l, 1l, 2l, 2l, 2l, 2l, 2l, 2l, 2l, 2l, 2l, 2l, 2l, 2l, 2l, 2l, 2l, 2l, 2l, 2l, 2l, 2l, 2l, 2l, 2l, 2l, 2l, 2l, 2l, 2l, 2l, 2l, 2l, 2l), t = c(1l, 2l, 3l, 4l, 5l, 6l, 7l, 8l, 9l, 10l, 11l, 12l, 13l, 14l, 15l, 16l, 17l, 18l, 19l, 20l, 21l, 22l, 23l, 24l, 25l, 26l, 27l, 28l, 29l, 30l, 31l, 32l, 33l, 34l, 1l, 2l, 3l, 4l, 5l, 6l, 7l, 8l, 9l, 10l, 11l, 12l, 13l, 14l, 15l, 16l, 17l, 18l, 19l, 20l, 21l, 22l, 23l, 24l, 25l, 26l, 27l, 28l, 29l, 30l, 31l, 32l), x = c(26.892, 23.904, 23.904, 23.904, 23.904, 23.904, 23.904, 23.904, 23.904, 20.916, 20.916, 20.916, 20.916, 20.916, 20.916, 20.916, 20.916, 20.916, 20.916, 20.916, 29.88, 20.916, 14.94, 8.964, 8.964, 5.976, 5.976, 5.976, 5.976, 5.976, 5.976, 5.976, 5.976, 5.976, 857.56, 860.54, 857.56, 857.56, 857.56, 857.56, 857.56, 857.56, 857.56, 857.56, 857.56, 857.56, 857.56, 857.56, 857.56, 857.56, 857.56, 857.56, 857.56, 857.56, 857.56, 857.56, 857.56, 857.56, 857.56, 857.56, 857.56, 857.56, 857.56, 857.56, 857.56, 857.56), y = c(167.33, 167.33, 164.34, 164.34, 164.34, 164.34, 164.34, 164.34, 164.34, 143.42, 143.42, 143.42, 143.42, 143.42, 143.42, 143.42, 143.42, 143.42, 143.42, 143.42, 176.29, 182.27, 185.26, 188.24, 188.24, 188.24, 188.24, 188.24, 188.24, 188.24, 188.24, 188.24, 188.24, 188.24, 256.97, 256.97, 256.97, 256.97, 256.97, 256.97, 256.97, 256.97, 256.97, 256.97, 256.97, 256.97, 256.97, 256.97, 256.97, 256.97, 256.97, 256.97, 256.97, 256.97, 256.97, 256.97, 256.97, 256.97, 256.97, 256.97, 256.97, 256.97, 256.97, 256.97, 256.97, 256.97 ), v = c(2.1128, 1.494, 0, 0, 0, 0, 0, 10.564, 10.564, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17.034, 19.422, 8.7114, 6.6814, 3.3407, 1.494, 1.494, 0, 0, 0, 0, 0, 0, 0, 0, 20.1, 0, 1.494, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.494, 1.494), p = c(-135, -90, 0, 0, 0, 0, 0, -98.13, -98.13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 74.745, 90, 149.04, 153.43, 153.43, 180, 180, 0, 0, 0, 0, 0, 0, 0, 0, 41.987, 0, 180, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 90, 90)), .names = c("k", "t", "x", "y", "v", "p"), row.names = c(na, 66l), class = "data.frame") since have x, y positions, make 2 vectors, should consider 3 x,y positions able compute angle. know that:
theta <- acos( sum(a*b) / ( sqrt(sum(a * a)) * sqrt(sum(b * b)) ) ) from stackoverflow answer (angle between 2 vectors in r).
i need compute angle per t factor within each k. know use split in this.
but how define vector computation of angle , function angle itself? thanks.
on diagram, have x,y positions of movement , need compute angle of movement. hope helps. should noted there no angle possible first , last x,y positions. thanks

so data frame has 6 rows. first 3 sets of (x,y) define right angle (th=90). next 3 sets of (x,y), rows 4-6, identical row 3. points sit on top of each other , there no angle. there 1 value of k it's kind of hard demonstrate aggregation k.
nevertheless, seems work:
df <- rbind(df,df,df) # replicate original data 3 times df$k <- rep(1:3,each=6) # k = 1, 2, 3 # theta in degrees theta <- function(a,b)(180/pi)*(acos( sum(a*b) / ( sqrt(sum(a * a)) * sqrt(sum(b * b))))) # returns vector of angles between successive line segmeents get.angles <- function(df.split){ dx<- diff(df.split$x) dy<- diff(df.split$y) sapply(1:(nrow(df.split)-2),function(i){ <- c(dx[i],dy[i]) b <- c(dx[i+1],dy[i+1]) theta(a,b) }) } # calls get.angles(...) each subset of df, based on k sapply(split(df,df$k),get.angles) # 1 2 3 # [1,] 90 90 90 # [2,] nan nan nan # [3,] nan nan nan # [4,] nan nan nan edit (response op's additional data, , comments)
so rather substantial change question, reworked solution seems work. using new definition of df,
theta <- function(a,b)(180/pi)*(acos(sum(a*b)/(sqrt(sum(a*a))*sqrt(sum(b*b))))) get.angles <- function(df.split){ dx<- diff(df.split$x) dy<- diff(df.split$y) stops <- which(dx^2+dy^2==0) dx<- dx[-stops] dy<- dy[-stops] df<- df.split[-(stops+1),] sapply(1:(length(dx)-1),function(i){ <- c(dx[i],dy[i]) b <- c(dx[i+1],dy[i+1]) return(cbind(df[i+1,],angle=180-theta(a,b))) }) } result <- t(do.call(cbind,lapply(split(df,df$k),get.angles))) result # k t x y v p angle # [1,] 1 2 23.904 167.33 1.494 -90 90 # [2,] 1 3 23.904 164.34 0 0 171.8714 # [3,] 1 10 20.916 143.42 0 0 7.125665 # [4,] 1 21 29.88 176.29 8.7114 149.04 108.4535 # [5,] 1 22 20.916 182.27 6.6814 153.43 172.8726 # [6,] 1 23 14.94 185.26 3.3407 153.43 179.9233 # [7,] 1 24 8.964 188.24 1.494 180 153.4963 # [8,] 2 2 860.54 256.97 1.494 180 0 this version removes points dx2+dy2=0 (lines of length=0), in other words repeated points @ same location, , calculates angles remaining points. note i'm using "internal" angles (<180). finally, plot data show these indeed proper angles:
library(ggplot2) ggplot(df[df$k==1,],aes(x=x,y=y))+ geom_path()+geom_point(colour="red")+coord_fixed() 
note use of coord_fixed(). forces aspect ration 1:1. otherwise angles distorted.
Comments
Post a Comment