Hi there!
I was training some ways to simulate animal (or other organisms) movements having into account habitat suitability. To do this, I used my previous eWalk model as the underlying process to simulate random or directional walks. This model is based on Brownian / Ornstein–Uhlenbeck process. You can find more about eWalk model here!
Today, I will add one more element to this movement simulations. In this case, we will have into account the habitat or environmental preferences of the simulated species, to perform a simulation like this:
First, we will create a raster layer as a random environmental variable, for example tree cover.
library (raster)
library (dismo)
tc <- raster(nrows=100, ncols=100, xmn=0, xmx=100, ymn=0,ymx=100)
tc[] <- runif(10000, -80, 180)
tc <- focal(tc, w=matrix(1, 5, 5), mean)
tc <- focal(tc, w=matrix(1, 5, 5), mean)
plot(tc)
species <- setClass("species", slots=c(x="numeric", y="numeric", opt="numeric"))
Red_deer <- species(x= 50, y =50, opt= 90)
Egyptian_mongoose <- species(x= 50, y =50, opt= 30)
Now, we will load the "go" function (I do not have a name for it yet). It require a species (sp), a raster layer with any environmental variable (env), number of iterations (n), a Brownian motion parameter (that is, how random is the movement of your species), a geographical optimum (the wanted destination of your species theta_x and theta_y), and the attraction strength or "interest" of the species to get this position (alpha_x and alpha_y). The syntaxis should be something like this:
path <- go (sp, env, n, sigma, theta_x, alpha_x, theta_y, alpha_y)
Here is the function to load (I will comment the function in a future post):
go <- function (sp, env, n, sigma, theta_x, alpha_x, theta_y, alpha_y) {
track <- data.frame()
track[1,1] <- sp@x
track[1,2] <- sp@y
for (step in 2:n) {
neig <- adjacent(env,
cellFromXY(env, matrix(c(track[step-1,1],
track[step-1,2]), 1,2)),
directions=8, pairs=FALSE )
options <- data.frame()
for (i in 1:length(neig)){
options[i,1]<-neig[i]
options[i,2]<- sp@opt - env[neig[i]]
}
option <- c(options[abs(na.omit(options$V2)) == min(abs(na.omit(options$V2))), 1 ],
options[abs(na.omit(options$V2)) == min(abs(na.omit(options$V2))), 1 ])
new_cell <- sample(option,1)
new_coords <- xyFromCell(env,new_cell)
lon_candidate<--9999
lat_candidate<--9999
while ( is.na(extract(env, matrix(c(lon_candidate,lat_candidate),1,2)))) {
lon_candidate <- new_coords[1]+ (sigma * rnorm(1)) + (alpha_x * ( theta_x - new_coords[1]))
lat_candidate <- new_coords[2]+ (sigma * rnorm(1)) + (alpha_y * ( theta_y - new_coords[2]))
}
track[step,1] <- lon_candidate
track[step,2] <- lat_candidate
}
return(track)
}
Well, now we can perform a simple experiment with our two specimens. We will simulate random movement of these two species having into account their environmental optimums. The "go" function will return us the track or the path followed by each specimen (coordinates by each step).
deer_simul <- go (Red_deer, tc, 100, 2, 90, 0, 90, 0)
mongoose_simul <- go (Egyptian_mongoose, tc, 100, 2, 90, 0, 90, 0)
We can plot the paths...
plot(tc)
lines(deer_simul, lwd=1.5, col="red")
points(deer_simul, cex=0.3, col="red")
lines(mongoose_simul, lwd=1.5, col="blue")
points(mongoose_simul, cex=0.3, col="blue")
legend("topleft", legend=c("deer","mongoose"), col=c("red","blue"),
lty=c(1,1), lwd=c(2,2))
To test if each species is actually "searching" their environmental optimum, we can extract the environmental values by step for each species and plot their density distributions.
plot(density(extract(tc, deer_simul)),lwd=3, col="red", xlim=c(20,80),
ylim=c(0,max(c(density(extract(tc, deer_simul))$y,
density(extract(tc, mongoose_simul))$y))),
main="locations density distribution", xlab="tree cover")
lines(density(extract(tc, mongoose_simul)),lwd=3, col="blue")
legend("topleft", legend=c("deer","mongoose"), col=c("red","blue"),
lty=c(1,1), lwd=c(3,3))
So, we can see that the deer is actually using patches with a higher value of tree cover than the mongoose... our simulation worked! You can use the code of this post to perform a GIF like the one above.
That's all I have to say about this for now... In the next posts we will simulate more animal movements and migrations!
PD: Let me show you a nice song about the mongoose...
Hello,
ResponderEliminarThanks for sharing this, I can see how this can be very useful for my work.
When I run this code I get the following error : Error in UseMethod("extract_") :
no applicable method for 'extract_' applied to an object of class "c('RasterLayer', 'Raster', 'BasicRaster')"
Any idea why this may happen?
Thanks
Hi! Thanks for your comment!
ResponderEliminarHave you check if raster package is loaded? extract() funciton is in several libraries, so maybe you are calling a wrong one. Use sessionInfo() to see the libraries you have loaded. You can also substitute in the script "extract" by "raster::extract" after load "raster" package
Cheers