# [AniMov] Re: Question about turning angles?

Clément Calenge calenge at biomserv.univ-lyon1.fr
Thu Nov 4 13:59:54 CET 2004

```At 13:42 03/11/2004 +0200, Sander Oom wrote:
>Hi Clément,
>
>Another question. I was clearing all my R code which is now surplus to
>requirements as your package does the same things! At least so I thought.
>My code for calculating turning angles produces different results from
>yours in some cases. See attached eps file based on my own data. I tried
>to produce the same graph with the code below, but the two resulting
>turning angle variables are of different length. The data has 204 rows,
>but your turning angle variable only has 196 rows?

Three relocations are needed to define one angle. Therefore, the
first three relocations are used to compute the first turning angle.
Consequently, there are necessarily less angles than relocations.
See the examples of the function angles (just copy and paste to R):

## loads an object of class "traj"
data(puechcirc)
puechcirc

## Gets a part of the trajectory of the wild boar named
## CH93 and draws it
## Also displays the turning angles
toto <- puechcirc[2:5,]
plot(toto\$x, toto\$y, asp = 1, ylim = c(3158300, 3158550),
pch = 16,
main = "Turning angles between\nthree consecutive moves",
xlab="X", ylab="Y")
lines(toto\$x, toto\$y)
lines(c(toto\$x[2], 700217.6),
c(toto\$y[2], 3158310), lty=2)
lines(c(toto\$x[3],700289),
c(toto\$y[3],3158546), lty=2)
ang1x <- c(700234.8, 700231.9, 700231, 700233.7, 700238.8, 700243.2)
ang1y <- c(3158332, 3158336, 3158341, 3158347, 3158350, 3158350)
ang2x <- c(700283.3, 700278.8, 700275.4, 700272.4, 700271.2, 700271.6,
700274.7)
ang2y <- c(3158522, 3158522, 3158520, 3158517, 3158514, 3158508, 3158504)
lines(ang1x, ang1y)
lines(ang2x, ang2y)
text(700216.1, 3158349, expression(theta[1]), cex=2)
text(700247.7, 3158531, expression(theta[2]), cex=2)
text(c(700301, 700231), c(3158399, 3158487),
c("Beginning", "End"), pos=4)

In this example, the part of the circuit considered is defined by 4
relocations, so that we can compute only 4 - 2 = 2 angles.
(which are displayed on the graph). The data "puechcirc" has 204 rows and 4
circuits. For each circuit defined by
N relocations, The function angles will compute N-2 angles. Therefore,
there are 4 circuits * 2 = 8 rows missing in the results,
relative to the data. That is, we can compute 204 - 8 = 196 angles.

In the example below, you compute the angles without considering that there
are 4 circuits.
Some of the angles do not have any biological meaning (for example the
angle between the
last part of the circuit of CH93 and the first part of JE93). This explains
that some of the angles
do not match between your function and mine. However, I cannot explain why
there are 10
angles not fitting the line, instead of 8. I cannot paste to R the code you
sent, because I
didn't find the the function "running" (maybe a sort of "apply"?).

And finally, the sign of the angle is different between your function and
mine, because the angles
measured by the function "angles" are trigonometric measure (that is
counterclockwise = +).
Indeed, the function "angles" relies on the R function atan2 (see the help
page of this function
for further details).

However, in the function angles, I did not consider the possibility of
successive relocations
located at the same place (i.e. with zero distance). When such cases
arised, I used the function
"jitter", to slightly move the relocations before the use of "angles".
This adds a little noise in the data, by replacing missing values by random
values, whereas other angles
are not significantly changed. However, I agree that it could be a benefit
for a further version
of adehabitat to consider such cases in the function "angles".

Hope this helps,

Clément Calenge.

>##########################################
>
>data(puechcirc)
>summary(puechcirc)
>puechcirc
>tmpXY <- data.frame(A=puechcirc\$x, B=puechcirc\$y)
>
>     # If distance is zero (i.e. duplicate records in data), direction
> will be set to zero
>     # check how to enter NA instead of zero!!
>     DirXY <- function(idx) {
>      i <- idx[2]
>      with(tmpXY,
>       ifelse( (A[i]-A[i-1]) == 0  & (B[i]-B[i-1]) > 0 , 0,
>       ifelse( (A[i]-A[i-1]) == 0  & (B[i]-B[i-1]) < 0 , 180,
>       ifelse( (A[i]-A[i-1]) > 0   & (B[i]-B[i-1]) > 0 , atan(
> (A[i]-A[i-1])/(B[i]-B[i-1]) )*(180/pi),
>       ifelse( (A[i]-A[i-1]) > 0   & (B[i]-B[i-1]) < 0 , 180 + atan(
> (A[i]-A[i-1])/(B[i]-B[i-1]) )*(180/pi),
>       ifelse( (A[i]-A[i-1]) < 0   & (B[i]-B[i-1]) < 0 , 180 + atan(
> (A[i]-A[i-1])/(B[i]-B[i-1]) )*(180/pi),
>       ifelse( (A[i]-A[i-1]) < 0   & (B[i]-B[i-1]) > 0 , 360 + atan(
> (A[i]-A[i-1])/(B[i]-B[i-1]) )*(180/pi), 0 ))))))
>       )
>     }
>
>     DirOom <- running( 1:nrow(tmpXY), width=2, fun = DirXY, pad = TRUE )
>
>     ## calculate turning angle
>     # Left turn = counterclockwise = - ; right turn = clockwise = +
>     # Is a 180 degree turn a left or right turn?
>     tmpDir <- data.frame(Dir=DirOom)
>     nrow(tmpDir)
>     TurnXY <- function(idx) {
>         i <- idx[2]
>         z <- with(tmpDir,
>             ifelse( (Dir[i]-Dir[i-1]) < -180 , 360+(Dir[i]-Dir[i-1]),
>             ifelse( (Dir[i]-Dir[i-1]) > 180 , (Dir[i]-Dir[i-1])-360,
> (Dir[i]-Dir[i-1]) ))
>             )
>         names(z) <- NULL
>         z
>     }
>     tmpTurn <- running( 1:nrow(tmpDir), width=2, fun = TurnXY, pad = TRUE )
>     print(tmpTurn)
>     summary(tmpTurn)
>     TurnOom <- na.omit(tmpTurn)
>
>########################################################################################
>
>########################################################################################
>
>
>print(TurnOom)
>summary(TurnOom)
>rose.diag(na.omit(TurnOom), bins = 18)
>
>##############################################################
>
>
>---------------------------------------------------------
>Sander Oom
>PO Box 19426
>Noordbrug
>Potchefstroom 2522
>South Africa
>
>Tel     +27 (18) 297 44 51
>Fax:    +27 (18) 299 24 64
>
>Email   sander at oomvanlieshout.net
>Web     www.oomvanlieshout.net/sander
>---------------------------------------------------------
>

======================================
UMR CNRS 5558 - Equipe "Ecologie Statistique"
Laboratoire de Biométrie et Biologie Evolutive
Université Claude Bernard Lyon 1
43, Boulevard du 11 novembre 1918
69622 Villeurbanne Cedex
FRANCE
tel. (+33) 04.72.43.27.57
fax. (+33) 04.72.43.13.88

```