Skip to contents

Utility functions for animal-movement data stored as move2 objects. A home for a handful of ports from the legacy move package, together with a small amount of novel scientific machinery described in a companion paper.

What’s in the package

Topic Functions Provenance
Utilisation distributions & variance mt_dbbmm_variance(), mt_dbbmm_ud(), mt_dbgb_variance(), mt_dbgb_ud(), mt_motion_variance(), mt_suggest_dbbmm_window(), ud_volume(), ud_outer_probability(), emd() Ported from move. C kernels kept; deprecated sp dependencies dropped in favour of sf/terra.
Corridor detection mt_corridor() Ported from move::corridor() (LaPoint et al. 2013). Spatial-indexing (sf R-tree) replaces the old sp/rgeos path.
Outlier detection — four primitives + unified entry-point mt_clean_track() (unified entry-point), mt_flag_outliers_bridge(), mt_flag_outliers_detour(), mt_flag_outliers(), mt_flag_speed_cap(), mt_peel_speed(), v_phys_estimate(), mt_suggest_speed_cap(), mt_diagnose_clean_track(), mt_flag_consensus() New. Four complementary primitives (geometric bridge-residual, path-vs-displacement detour ratio, probabilistic movement-metric, step-level speed cap) composable individually or through mt_clean_track() which iterates them under the class-aware consensus rule (configurable via consensus =) plus topological block-expansion. Described in the companion paper.
Outlier detection — state-aware bridge variants (standalone) mt_flag_outliers_dbgb(), mt_flag_outliers_dbbmm() Estimate per-axis bridge motion variance and flag fixes via an envelope rule across three Z channels (bridge_z_class taxonomy); useful when behavioural states make a single global threshold over- or under-flag. Currently exported as standalone primitives, not wired into the cascade.
Outlier detection — alternative strategies mt_sequential_outliers(), mt_combined_outliers() Voting/scanning alternatives on the probability surface. See ?mt_clean_track’s @seealso for when to reach for each.
Outlier detection — multi-scale persistence annotation mt_persistence_score() Detector-agnostic confidence helper. Annotates any flagger’s output with a per-flag persistence score across temporal scales; recommended use is class-aware filtering on cascade output. See vignette("OUTLIER_5_persistence_score").
Pre-cleaning helpers mt_filter_gps_quality(), mt_mask_segments() Drop fixes whose GPS geometry is unreliable; mask track segments by predicate.
Trajectory utilities mt_thin_distance(), mt_thin_time() Distance- and time-based thinning, preserving track IDs.

All functions operate directly on move2 objects and preserve CRS, track IDs, timestamps, and metadata.

Installation

# install.packages("remotes")

# MPCDF GitLab (the canonical home; CI builds the docs site here)
remotes::install_gitlab("anenvi/r-packages/move2utils", host = "gitlab.mpcdf.mpg.de", build_vignettes=TRUE)
  • Required: move2, sf, terra, units.
  • Suggested: circular, geosphere, MASS, lwgeom, lubridate, dplyr, parallel, testthat, knitr.

Quick tour

Utilisation distributions

library(move2)
library(move2utils)
fishers <- mt_read(mt_example())
fishers <- fishers[!sf::st_is_empty(fishers), ]
leroy   <- fishers[mt_track_id(fishers) == "M1", ]

var <- mt_dbbmm_variance(leroy)      # scalar dynamic Brownian bridge
ud  <- mt_dbbmm_ud(var)              # UD on a common grid

var_d <- mt_dbgb_variance(leroy)     # bivariate (directional) bridge
ud_d  <- mt_dbgb_ud(var_d)

Corridor detection

leroy_ll <- sf::st_transform(leroy, 4326)
out <- mt_corridor(leroy_ll)
table(out$corridor)

Outlier detection

## One-call unified detector -- iterates the four primitives with
## class-aware flagging plus topological block expansion, auto-
## projects lon/lat internally, returns in the original CRS.
clean <- mt_clean_track(fishers)

## Or use the primitives individually:
flagged_b <- mt_flag_outliers_bridge(fishers)             # geometric (bridge residual)
flagged_t <- mt_flag_outliers_detour(fishers)             # geometric (path/displacement)
flagged_p <- mt_flag_outliers(fishers)                     # probabilistic
flagged_s <- mt_flag_speed_cap(fishers)                    # step-level speed

## Directional bridge variant -- classify errors into parallel vs
## perpendicular residuals (error-morphology classification)
flagged_d <- mt_flag_outliers_bridge(fishers, method = "directional")

## State-aware bridge primitive -- per-axis envelope rule with the
## bridge_z_class diagnostic taxonomy.  Standalone (not wired into
## the cascade); useful when behavioural states make a global
## threshold over- or under-flag.
flagged_z <- mt_flag_outliers_dbgb(fishers)

Which function should I use?

Task Function
Estimate dynamic motion variance mt_dbbmm_variance() / mt_dbgb_variance()
Compute a utilisation distribution mt_dbbmm_ud() / mt_dbgb_ud()
Flag corridor segments mt_corridor()
One-call outlier cleanup mt_clean_track()
Post-run health check on mt_clean_track() output mt_diagnose_clean_track()
Geometric per-fix outlier detection (leverage-immune) mt_flag_outliers_bridge()
Geometric, time-insensitive (path/displacement ratio) mt_flag_outliers_detour()
Probabilistic per-fix outlier detection mt_flag_outliers()
Step-level impossible-speed outlier detection mt_flag_speed_cap()
Iterative speed peel for coherent multi-fix error clusters mt_peel_speed()
Allometric physiological speed cap from (mass, mode) v_phys_estimate()
Inspect a track’s speed distribution and suggest a cap mt_suggest_speed_cap()
Classify the kind of error at each flagged location (directional residual) mt_flag_outliers_bridge(method = "directional")
State-aware bridge primitive with per-axis envelope rule + bridge_z_class taxonomy mt_flag_outliers_dbgb()
Isotropic state-aware bridge primitive (faster; one Z channel) mt_flag_outliers_dbbmm()
Sequential scan from confirmed-good fixes (alternative strategy) mt_sequential_outliers()
Majority vote across gap / entropy / sequential strategies mt_combined_outliers()
Per-flag confidence via multi-scale persistence (cascade or any flagger) mt_persistence_score()
Short track with a longer clean reference mt_flag_outliers(x, reference = long)
Pre-cleaning: drop fixes with bad GPS geometry mt_filter_gps_quality()

Vignettes

The cleaning workflow has its own ordered set of vignettes; readers new to the package should walk them in this order.

Outlier cleaning (workflow order):

  1. vignettes/OUTLIER_1_getting_started.Rmd — the one-call mt_clean_track() workflow on a bundled synthetic track with known outliers, then a brief tour of each primitive for users who want finer control.
  2. vignettes/OUTLIER_4_outlier_bridge.Rmd — the geometric bridge-residual primitive in depth (combined / isotropic / directional methods, error-morphology classification).
  3. vignettes/OUTLIER_example_outlier_whitestork.Rmd — a worked example on a real white-stork track with multi-state behaviour and migration spikes.
  4. vignettes/OUTLIER_2_diagnose_clean_track.Rmdpost-run health check. Six diagnostic panels analogous to plot.lm() for a GLM; tells you when the cleaner over-flagged and points at the remedy. Read this if your mt_clean_track() result looks suspicious.
  5. vignettes/OUTLIER_3_state_conditional.Rmd — recipe for the multi-state failure mode the diagnostic flags. The supported manual path until a first-class state-conditional API ships.

Other utilities:

  • vignettes/OUTLIER_example_leo_migration.Rmd — worked outlier-detection example on long-distance migration data.
  • vignettes/UD_dbbmm_ud.Rmd / vignettes/UD_dbgb_ud.Rmd / vignettes/UD_ud_comparison.Rmd — utilisation-distribution workflows.
  • vignettes/UD_bursted_uds.Rmd — context-aware (per-burst) dBBMM/dBGB using the dplyr idiom that replaces move::burst.
  • vignettes/corridor.Rmd — corridor detection on a raw track.
  • vignettes/UD_gap_aware_ud.Rmd / vignettes/interpolate_and_thin.Rmd — supporting workflows.

When the cleaner over-flags (and when to supply (mass, mode))

mt_clean_track() has two failure modes the user should recognise. Both are documented by empirical benchmarks committed in this repo and are signalled by the diagnostic suite at run time.

Failure mode 1 — multi-state behaviour with no real outliers

On tracks where the animal has very different speed regimes (resting at colony + flight, wintering + migration, perched + foraging), per-fix detectors threshold against the dominant baseline distribution and flag the minority state’s fixes as anomalous — even when none are GPS errors.

Empirical example: Columba livia Saline-20160803-048308 (homing pigeon, n = 5479). The pigeon has two modes — perched at the loft (0.10 m/s) and racing flight (15.2 m/s). With naive defaults mt_clean_track() flags 696 fixes (12.7 %) — all of which are racing flight, not GPS errors. Naive speed cap and atlastools correctly flag 0 on this track because the racing flight is biologically below the 30 m/s physiological cap.

Symptoms: very high flag rate (>5 %) on a track with no visible off-trajectory fixes; mt_diagnose_clean_track() Panel 1 shows multiple substantive modes; Panel 2 shows a sustained band of elevated flag rate corresponding to the minority state.

What to do: see vignette(“OUTLIER_3_state_conditional”) — segment by speed mode, run mt_clean_track() per segment, recombine. Or filter the track to one state before cleaning.

Failure mode 2 — block-shaped contamination at naive defaults

On tracks with sustained contaminated trains (GPS spoofs, deployment confusion, multi-fix data corruption) the auto-cap can land at biologically absurd values (the data’s own outliers define a “gap” the auto-cap finds). The speed primitive then doesn’t fire on the spoof boundaries reliably enough for block expansion to seed, so the contaminated train is silently kept.

Empirical example: K02 golden eagle (real Movebank study 2830439412, n = 851 k, 175-fix spoof in 2025-06-14). With naive defaults mt_clean_track() recovers 0 / 175 spoof fixes (auto-cap landed at 88 m/s, far above any biological eagle speed). With (mass = 4.5, mode = "flying") the same wrapper recovers 175 / 175 via block expansion.

Symptoms: very few final flags despite a track that obviously has contaminated regions; the wrapper now prints a “primitive-disagreement signature” warning when bridge caught flags the conjunction dropped — supplying mass+mode resolves this.

What to do: supply (mass, mode) to mt_clean_track() (auto-derives a Hirt 2017 physiological cap), or pass v_max = <published_value> for sprint-mode-aware species. The wrapper also warns when the auto-cap lands above 50 m/s.

Empirical evidence

  • 65-individual stratified Movebank audit (audits/2026-04-29-stratified-movebank/findings.md): 75 % PASS, 95 % defensible, 0 crashes on naive defaults; the 5 % OVER_FLAG cases all hit Failure mode 1.
  • Three head-to-head benchmarks (benchmarks/2026-XX-XX-vs-competitors/):
    • Phase 1 (synthetic): mt_clean F1 = 0.98, atlastools F1 = 0.74, naive F1 = 0.76, trip::sda F1 = 0.04.
    • Phase 2 (K02 spoof): mt_clean tier 1 (mass+mode) recovers 175/175; per-fix competitors recover 2/175 (boundaries only).
    • Phase 3 (audit subset, real multi-state): mt_clean over-flags 5892 multi-state behaviour fixes; naive and atlastools correctly flag 0.

Each adjustable parameter targets a specific empirically-distinguishable failure mode. The diagnostic suite tells the user which knob to reach for.

Companion projects

The two manuscripts evolve at their own cadences and live in their own GitLab repositories; this package no longer carries them as submodules.

Background

The corridor concept follows LaPoint, Gallery, Wikelski & Kays (2013) Landscape Ecology 28: 1615–1630.

The outlier-detection framework — four complementary primitives (geometric bridge residual, path-vs-displacement detour ratio, probabilistic movement-metric, step-level speed cap) sharing a gap-aware non-parametric normalisation and combinable through an iterative unified detector with class-aware flagging plus topological block expansion — is the novel scientific content of the package and is described in the companion paper (in preparation, Methods in Ecology and Evolution).

Citation

Safi K (2026). move2utils: Utility Functions for Movement Data Based on move2.
R package version 0.3.2. https://gitlab.mpcdf.mpg.de/anenvi/r-packages/move2utils

Contributing

See CONTRIBUTING.md for the workflow (issue first, feature branches from main, R CMD check must stay green). The package is intentionally minimal in scope — move2-native utilities. Proposals outside that scope are likely better placed in their own package.

License

GPL (>= 3). Full text in LICENSE.md.