aniMotum estimates locations and movement parameters in
map coordinates, not in longitude and latitude. That means the map you
use is part of the model. If your animals range across a wide band of
latitude, the default map will stretch their movements by different
amounts in different places, and the parameter estimates you get back
will partly describe the map rather than the animal.
For tracks that stay within a narrow band of latitude, this makes almost no difference and you can ignore it. For tracks that cross a wide band - polar and sub-polar animals especially - it can change the answers substantially.
aniMotum does by default
Tracking data usually arrive as longitude and latitude. Those are
angles, not distances, so before fitting a model aniMotum
converts them to x and y coordinates measured in kilometres. Unless you
tell it otherwise, it uses a Mercator grid to do that.
Mercator is a sensible general-purpose default. It is the map most people picture, it never distorts an animal’s direction of travel at a point, and it works anywhere in the world without you having to choose anything.
It has one property that matters here: it stretches distances by more
and more as you move away from the equator. The amount of stretch is
1 / cos(latitude).
lat <- c(0, 30, 45, 50, 60, 70, 80)
data.frame(latitude = lat,
stretch = round(1 / cos(lat * pi / 180), 2))
#> latitude stretch
#> 1 0 1.00
#> 2 30 1.15
#> 3 45 1.41
#> 4 50 1.56
#> 5 60 2.00
#> 6 70 2.92
#> 7 80 5.76So a 10 km move at 70 degrees south appears on a Mercator grid as roughly a 29 km move, while the same 10 km move at 30 degrees south appears as about 11.5 km. The animal did the same thing in both cases. The map did not.
The models estimate how far an animal typically moves in a given
time. In the mp and rw models that quantity is
sigma; in the crw model it appears as the
diffusion coefficient D. Either way it is measured in map
units. If the map stretches distances, the estimate is stretched with
them.
Two things follow.
An animal that spends its time at high latitude looks faster than one at lower latitude, even if they move identically. The difference is entirely the map.
A single animal that travels across a wide band of latitude
has its own movements stretched by different amounts at different points
of its own track. The model fits one value of
sigma to the whole track, so what you get is an average
across all that stretching.
The measurement error parameters are affected in the same way.
tau scales the assumed Argos error, and that error is also
expressed in map units.
The sese data are four southern elephant seals tagged at
Iles Kerguelen. They leave from roughly the same place and then travel
in very different directions: one east, one west, one almost due south,
one southwest. Between them they cover 47 to 69 degrees south.
range(abs(sese$lat))
#> [1] 46.96 69.14
## the average latitude each seal occupies, and the stretch that implies
ll <- tapply(abs(sese$lat), sese$id, mean)
round(1 / cos(ll * pi / 180), 2)
#> ct109-085-14 ct109-186-14 ct109-937-14 ct135-188BAT-14
#> 1.60 2.24 1.65 2.13The four seals sit at stretch factors of roughly 1.6 to 2.2. So before any model is fitted, we should expect the seals that go furthest south to look like faster movers.
Fitting the joint move persistence model on the default Mercator grid, and then again on an equal-area grid centred on the study region:
## default: Mercator
fm <- fit_ssm(sese, vmax = 4, model = "jmp", time.step = 24)
## equal-area, centred on the deployment
sese_ea <- sf::st_transform(
sf::st_as_sf(sese, coords = c("lon", "lat"), crs = 4326),
"+proj=laea +lat_0=-57 +lon_0=70 +datum=WGS84 +units=km +no_defs")
fe <- fit_ssm(sese_ea, vmax = 4, model = "jmp", time.step = 24)The estimates:
| parameter | Mercator | equal-area |
|---|---|---|
sigma_pop_x |
3.31 | 0.71 |
sigma_pop_y |
2.44 | 0.71 |
sigma_g |
0.023 | 0.042 |
tau_x |
0.046 | 0.087 |
tau_y |
0.071 | 0.080 |
rho_o |
0.51 | −0.04 |
sd_lsig |
0.25 | 0 |
Three things are worth pulling out.
The seals only appear to differ on the Mercator
grid. sd_lsig is how much the seals differ from
one another in movement scale. On the Mercator grid it comes out at
0.25. On the equal-area grid it goes to zero: once the map stops
stretching the southern seals more than the northern ones, there is no
difference left to find. The apparent variation between animals was the
map.
The Mercator fit says the seals move differently east-west
than north-south, and the equal-area fit says they do not. On
the Mercator grid sigma_pop_x and sigma_pop_y
differ by about a third. On the equal-area grid they are equal to three
decimal places. Mercator stretches north-south and east-west by the same
amount at any single point, so this is not a direct distortion. It
arises because the seals do their east-west travelling and their
north-south travelling at different latitudes, so the two get stretched
by different average amounts over a whole track.
The measurement error estimates give an independent check,
and they favour the equal-area fit. Argos location error has no
reason to be larger east-west than north-south, and no reason for the
error in one direction to be correlated with the error in the other. On
the equal-area grid that is what we get: tau_x and
tau_y are within 8% of each other, and rho_o
is close to zero. On the Mercator grid they differ by more than half,
and rho_o comes out at 0.51. The equal-area fit recovers a
sensible measurement error model without being asked to; the Mercator
fit does not.
It is tempting to assume that move persistence, g,
escapes all of this. It is a number between 0 and 1 with no units, so a
change in map scale should not touch it.
That reasoning does not hold. g measures how much of an
animal’s previous step carries over into its next one, and a step has a
direction as well as a length. Any map that distorts shape, and any map
whose stretch changes along the track, changes the relationship between
one step and the next. In the example above sigma_g nearly
doubled between the two fits.
So g values are comparable between animals in the same
fit, which is what fitting a joint model buys you, but they are not
comparable across fits made on different maps. If you report move
persistence, report the projection you used.
A quick check:
## how much does the stretch vary across your data?
lat.rng <- range(abs(sese$lat), na.rm = TRUE)
stretch <- 1 / cos(lat.rng * pi / 180)
round(stretch, 2) # least and most stretched
#> [1] 1.47 2.81
round(max(stretch) / min(stretch), 2) # how many times more one than the other
#> [1] 1.92As a rough guide, if that number is below about 1.2 the default is
fine - and that is the threshold projection = "auto" uses
before it changes anything. Above about 1.5 it is worth fitting in a
projection suited to your study region and comparing.
fit_ssm() will also warn you when a joint fit spans a wide
enough band for this to bite.
The same check applies within a single animal. A seal that migrates from 50 to 70 degrees south has this problem on its own, with no other animals involved.
fit_ssm() choose
fit <- fit_ssm(mydata, vmax = 4, model = "mp", time.step = 24,
projection = "auto")projection = "auto" picks a projection from the
geographic extent of your data. You can see what it would choose without
fitting anything:
auto_crs(sese$lon, sese$lat)
#> [1] "+proj=lcc +lat_1=-65.44 +lat_2=-50.66 +lat_0=-58.05 +lon_0=68 +datum=WGS84 +units=km +no_defs"The choice is made once from all the tracks together, never one per animal. Fitting each animal in its own projection would leave their estimates in different frames, so you could not compare them - which is usually the reason for fitting a whole deployment.
The rules are:
lcc) for tracks
within one hemisphere and below 80 degrees, with its two standard
parallels placed to keep scale error small across the band your animals
occupy;stere) beyond 80
degrees, or for tracks that go right around the pole;"auto" therefore changes nothing.All of these keep shape undistorted - a step of a given length maps to the same coordinate length whichever way it points. That property matters more than it might seem, because these models are about movement steps, which have a direction as well as a length. A projection that distorts shape makes the east-west and north-south parts of the process differ for reasons that have nothing to do with the animal, and it changes move persistence.
That last point is why an equal-area projection is not the obvious choice it first appears. Equal-area keeps areas honest but distorts shape away from its centre, which is exactly the wrong trade for a movement model. The equal-area fit in the table above is much better than the Mercator one, but a conformal projection is better still.
If you have a projection your study already uses, supply the data as
an sf object and aniMotum will use it
unchanged:
d <- sf::st_as_sf(mydata, coords = c("lon", "lat"), crs = 4326)
d <- sf::st_transform(d, "+proj=stere +lat_0=-90 +lon_0=70 +units=km")
fit <- fit_ssm(d, vmax = 4, model = "mp", time.step = 24)Note the units=km. aniMotum works in
kilometres internally because it helps the models converge, and it will
convert for you, but stating it avoids doubt.
An sf object is always respected.
aniMotum only chooses a projection for itself when the data
arrive as plain longitude and latitude. If your data have already been
prepared and projected somewhere else - by ArgosQC, for
example - they reach the model exactly as prepared, and
projection is ignored. Nothing is ever projected twice.
If you are unsure, fit twice and compare. Estimates that hold steady across two sensible projections are ones you can report with some confidence. Estimates that move a lot are telling you something about your map.
Estimated locations are barely affected. The models are estimating
where the animal was, and converting back to longitude and latitude at
the end undoes most of the distortion. If all you want from
aniMotum is a quality-controlled track, the default is
fine.
It is the parameters - how fast, how variable between animals, how persistent - that need the care, along with anything computed from them.