tests/testthat/test_recurse.R

library(recurse)

context("recurse")

# support functions
#------------------------------------------------------------------------------------------------

getRevisits = function(data, radius)
{
	return(getRecursions(data, radius)$revisits)
}

createTimeVector = function(n, tz = "")
{
	return(as.POSIXct("2009-5-1 1:00:00", tz = tz) + (1:n) * 60 * 60) # every hour
}

createMoveObj = function(df)
{
	if (requireNamespace("move", quietly = TRUE)) 
	{
		# remove projection in order to remove sp dependency (was proj = sp::CRS("+proj=aeqd"))
		moveObj = move::move(x = df$x, y = df$y, time = df$t, animal = df$id) 
		move::idData(moveObj) = df$id[1] # move ignores id, so set it directly
	}
	else
	{
		moveObj = NULL
	}
	return(moveObj)
}

createMove2Obj = function(df)
{
  if (requireNamespace("move2", quietly = TRUE)) 
  {
    moveObj = move2::mt_as_move2(df, coords =c("x", "y"), time_column = "t", track_id_column = "id") 
  }
  else
  {
    moveObj = NULL
  }
  return(moveObj)
}

testTz = function(df)
{
	output = getRecursions(df, 1)
	expect_equal(attr(output$revisitStats$entranceTime, "tzone"), attr(df$t, "tzone"))
	expect_equal(attr(output$revisitStats$exitTime, "tzone"), attr(df$t, "tzone"))
}

# data
#------------------------------------------------------------------------------------------------

# expected revisits for data "track" included in pacakge and calculated using an alternate method
# as.double(.Call("nvisits", df = track, radius = 1, maxt = 0, PACKAGE = "adehabitatHR"))
expectedRevisistsRadius1 = c(2, 2, 3, 2, 2, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 2, 2, 2, 3, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 3, 1, 1, 1, 2, 2, 2, 2, 1, 1, 2)

# points on a line so distances between are unit lengths
simplePts = data.frame(x = 1, y = 1:5, t = createTimeVector(5), id = "A1")
simplePtsDist = matrix(0, nrow = 5, ncol = 5)
simplePtsDist =  abs(row(simplePtsDist) - col(simplePtsDist))

# different locations than simplePts, but still x = 1 so with easy distances
simpleLocs = data.frame(x = c(1, 1, 1), y = c(1, 0, 10))
simpleLocsDist = matrix(0, nrow = 5, ncol = 3)
simpleLocsDist = cbind(0:4, 1:5, 9:5)

# two tracks, one vertical x = 1, one horizontal y = 3
horzTrack = data.frame(x = -1:3, y = 3, t = createTimeVector(5), id = "B2")
twoTracks = rbind(simplePts, horzTrack)

# one track that revisits one location
oneTrack = twoTracks
oneTrack$t[5:10] = oneTrack$t[5:10] + 1 * 24 * 60 * 60 # make second part of track a day later
oneTrack$id = 1

# track with data points on radius boundries so time in/out is easy to caluculate
gridTrack = data.frame(
	x = c(0, 1, 2, 1, 0, 1, 2, 2, 3, 5, 6, 3, 1, 3, 4),
	y = rep(0, 15),
	t = createTimeVector(15),
	id = rep(1, 15)
)
#plot(gridTrack$x, gridTrack$t/10, type = "b")

# tests
#------------------------------------------------------------------------------------------------

test_that("correct number of revisits",
		  {
		  	expect_equal(length(getRevisits(track, 1)), 100)
		  	
		  	expect_equal(getRevisits(track, 1), expectedRevisistsRadius1)
		  	
		  	expect_equal(getRevisits(twoTracks, 0.5), rep(c(1, 1, 2, 1, 1), 2)) # middle pt overlaps
		  })

test_that("distance matrix",
		  {
		  	expect_equal(getRecursions(simplePts, 1, verbose = TRUE)$dists, simplePtsDist)
		  	expect_equal(getRecursionsAtLocations(simplePts, simpleLocs, 1, verbose = TRUE)$dists, simpleLocsDist)
		  })

test_that("time in radius",
		  {
		  	# examine visits to point at x=2 (use first time at t=3)
		  	stats = getRecursions(gridTrack, 1)$revisitStats
		  	expect_equal(as.numeric(stats[stats$coordIdx==3, "timeInside"]),
		  				 c(2, 3, 2))
		  	expect_equal(as.numeric(stats[stats$coordIdx==3, "timeSinceLastVisit"]),
		  				 c(NA, 2, 3))
		  	})

test_that("verbose",
		  {
		  	expect_no_error(getRecursions(simplePts, 1, verbose = TRUE))
		  	expect_no_error(getRecursions(simplePts, 1, verbose = FALSE))
		  })

test_that("revisit stats",
		  {
		  	stats = getRecursions(simplePts, 0.5)$revisitStats
		  	n = nrow(simplePts)
		  	
		  	expect_equal(stats$id, simplePts$id)
		  	expect_equal(stats$x, simplePts$x)
		  	expect_equal(stats$y, simplePts$y)
		  	expect_equal(stats$coordIdx, 1:n)
		  	expect_equal(stats$visitIdx, rep(1, n))
		  	expect_equal(stats$entranceTime, c(simplePts$t[1], simplePts$t[2:n] - as.difftime(30, units = "mins")))
		  	expect_equal(stats$exitTime, c(simplePts$t[1:(n-1)] + as.difftime(30, units = "mins"), simplePts$t[n]))
		  	expect_equal(stats$timeInside, c(0.5, 1, 1, 1, 0.5))
		  	expect_equal(stats$timeSinceLastVisit, c(1, rep(NA, n))[-1])
		  	
		  	
		  	stats2 = getRecursions(twoTracks, 0.5)$revisitStats
		  	expectedCoordIdx = c(1, 2, 3, 3, 4, 5, 6, 7, 8, 8, 9, 10)
		  	expectedIdIdx = c(1, 1, 1, 2, 1, 1, 2, 2, 1, 2, 2, 2)
		  	
		  	expect_equal(stats2$id, unique(twoTracks$id)[expectedIdIdx]) #unique orders A1 B2
		  	expect_equal(stats2$x, twoTracks$x[expectedCoordIdx])
		  	expect_equal(stats2$y, twoTracks$y[expectedCoordIdx])
		  	expect_equal(stats2$coordIdx, expectedCoordIdx)
		  	expect_equal(stats2$visitIdx, rep(c(1, 1, 1, 2, 1, 1), 2))
		  	expect_equal(stats2$entranceTime, twoTracks$t[expectedCoordIdx] - as.difftime(rep(c(0, rep(30, 5)), 2), units = "mins"))
		  	expect_equal(stats2$exitTime, twoTracks$t[expectedCoordIdx] + as.difftime(rep(c(rep(30, 5), 0), 2), units = "mins"))
		  	expect_equal(stats2$timeInside, rep(c(0.5, 1, 1, 1, 1, 0.5), 2))
		  	expect_equal(stats2$timeSinceLastVisit, c(1, rep(NA, length(expectedCoordIdx)))[-1]) 
		  	
		  })

test_that("threshold",
		  {
		  	expect_equal(sum(getRecursions(oneTrack, 0.5, threshold = 0)$revisits), 12)
		  	expect_equal(sum(getRecursions(oneTrack, 0.5, threshold = 1)$revisits), 12)
		  	expect_equal(sum(getRecursions(oneTrack, 0.5, threshold = 23)$revisits), 12)
		  	expect_equal(sum(getRecursions(oneTrack, 0.5, threshold = 24)$revisits), 10)
		  	expect_equal(sum(getRecursions(oneTrack, 0.5, threshold = 100)$revisits), 10)
		  })

test_that("move objects",
		  {
		    if (requireNamespace("move2", quietly = TRUE)) 
		    {
		      move2Pts = createMove2Obj(simplePts)
		      expect_equal( getRecursions(move2Pts, 1), getRecursions(simplePts,1) )
		    } 
		    
		    if (requireNamespace("move", quietly = TRUE)) 
		  	{
			  	movePts = createMoveObj(simplePts)
			  	expect_equal( getRecursions(movePts, 1), getRecursions(simplePts,1) )
			  	
			  	moveStackPts = createMoveObj(twoTracks)
			  	expect_equal( getRecursions(moveStackPts, 1), getRecursions(twoTracks,1) )
		  	}
		  })

test_that("move2 objects",
          {
            if (requireNamespace("move2", quietly = TRUE)) 
            {
              movePts = createMove2Obj(simplePts)
              expect_equal( getRecursions(movePts, 1), getRecursions(simplePts,1) )
              
              moveStackPts = createMoveObj(twoTracks)
              expect_equal( getRecursions(moveStackPts, 1), getRecursions(twoTracks,1) )
            }
          })

test_that("timezone",
		  {
		  	defaultTz = data.frame(x = 1, y = 1:5, t = createTimeVector(5), id = "default")
		  	utcTz = data.frame(x = 1, y = 1:5, t = createTimeVector(5, tz = "UTC"), id = "UTC")
		  	sydneyTz = data.frame(x = 1, y = 1:5, t = createTimeVector(5, tz = "Australia/Sydney"), id = "Australia/Sydney")
		  	limaTz = data.frame(x = 1, y = 1:5, t = createTimeVector(5, tz = "America/Lima"), id = "America/Lima")

		  	testTz(defaultTz)
		  	testTz(utcTz)
		  	testTz(sydneyTz)
		  	testTz(limaTz)
		  })

test_that("interval res time",
		  {
		  	vis = getRecursions(simplePts, 0.5)
		  	
		  	expect_equal(as.vector(calculateIntervalResidenceTime(vis, breaks = simplePts$t[c(1,5)])),
		  				 vis$residenceTime)
		  	
		  	expectedMatrix = matrix(c(0.5, 1, 0.5, 0, 0, 0, 0, 0.5, 1, 0.5), ncol = 2, 
		  							dimnames = list(1:5, c("A", "B")))
		  	expect_equal(calculateIntervalResidenceTime(vis, breaks = simplePts$t[c(1,3,5)], labels = c("A", "B")),
		  				 expectedMatrix)
		  	
		  })

test_that("polygon",
		  {
		  	if (requireNamespace("sf", quietly = TRUE)) 
		  	{
			  	poly = sf::st_polygon(list(cbind(c(4,6,6,3,4), c(1,2,4,3,1))))
			  	polyc = sf::st_sfc(poly, crs = "EPSG:4326")
			  	recursions = getRecursionsInPolygon(track, polyc)
			  	expect_equal(recursions$revisits, 2)
			  	expect_equal(round(as.numeric(recursions$revisitStats$timeInside[1]), digits = 2), 44.99)
			  	expect_equal(round(as.numeric(recursions$revisitStats$timeInside[2]), digits = 2), 108.9)
			  	
			  	recursions2 = getRecursionsInPolygon(createMove2Obj(track), polyc)
			  	expect_equal(recursions2$revisits, 2)
		  	}
		  })
cbracis/recurse documentation built on July 23, 2024, 5:18 a.m.