Example analysis of albatross trajectories

First the move2 package needs to be loaded.

library(move2)

First valid movebank credentials need to be stored. Here the ‘username’ needs to be set. In an interactive session the user will be prompted for a password and possibly will be prompted to install additional packages. Alternatively the password can be provided on the command line as a second argument however it is then important to ensure it will not be stored in the R history. For more details and setups storing multiple credentials we refer to the “movebank” vignette.

movebank_store_credentials("username")

For this example we download the data from the study ‘Galapagos Albatrosses’ (notice that matching is conducted if no study is named as such). Here we specify to only download data from the ‘gps’ sensor. Filtering at this early stage speeds up the working cycle as no unneeded data is extracted from the database. The resulting data is printed to the screen showing an overview of the data (here the number of lines are reduced). First general properties of the data are shown including the number of tracks and the average track duration. After, the first observations are printed. The units of attributes derived from the movebank vocabulary are associated to the locations are shown between square brackets. Finally, the summary of the track_data is printed, where each row corresponds to the track level data for each track.

In case the license terms for the study have not been accepted before, the download command will fail and prompt the user to read the license terms and accept these. This can be done by adding the license-md5 argument to the download command with the hash provided in the error message.

data <- movebank_download_study("Galapagos Albatrosses", sensor_type_id = "gps")
data
#> A <move2> with `track_id_column` "individual_local_identifier" and `time_column`
#> "timestamp"
#> Containing 28 tracks lasting on average 37.1 days in a
#> Simple feature collection with 16414 features and 18 fields (with 386 geometries empty)
#> Geometry type: POINT
#> Dimension:     XY
#> Bounding box:  xmin: -91.3732 ymin: -12.79464 xmax: -77.51874 ymax: 0.1821983
#> Geodetic CRS:  WGS 84
#> # A tibble: 16,414 × 19
#>   sensor_type_id individual_local_iden…¹ eobs_battery_voltage eobs_fix_battery_vol…²
#>          <int64> <fct>                                   [mV]                   [mV]
#> 1            653 4264-84830852                           3686                   3437
#> 2            653 4264-84830852                           3701                   3452
#> 3            653 4264-84830852                           3701                   3482
#> # ℹ 16,411 more rows
#> # ℹ abbreviated names: ¹​individual_local_identifier, ²​eobs_fix_battery_voltage
#> # ℹ 15 more variables: eobs_horizontal_accuracy_estimate [m],
#> #   eobs_key_bin_checksum <int64>, eobs_speed_accuracy_estimate [m/s],
#> #   eobs_start_timestamp <dttm>, eobs_status <ord>, …
#> First 3 track features:
#> # A tibble: 28 × 52
#>   deployment_id  tag_id individual_id animal_life_stage attachment_type
#>         <int64> <int64>       <int64> <fct>             <fct>          
#> 1       2911170 2911124       2911090 adult             tape           
#> 2       2911150 2911126       2911091 adult             tape           
#> 3       2911167 2911127       2911092 adult             tape           
#> # ℹ 25 more rows
#> # ℹ 47 more variables: deployment_comments <chr>, deploy_on_timestamp <dttm>,
#> #   duty_cycle <chr>, deployment_local_identifier <fct>, manipulation_type <fct>, …

As the move2 class extends sf we can profit from existing plotting functionality. Here we use ggplot2 to visualize the data. Notice that geom_sf is called twice, once to plot the location records, and a second time to plot the tracks for each individual. For the later mt_track_lines is used convert the point location data to a single line geometry per individual.

library(ggplot2)
ggplot() +
  ggspatial::annotation_map_tile(zoom = 5) +
  ggspatial::annotation_scale() +
  theme_linedraw() +
  geom_sf(data = data, color = "darkgrey", size = 1) +
  geom_sf(data = mt_track_lines(data), aes(color = individual_local_identifier)) +
  coord_sf(
    crs = sf::st_crs("+proj=aeqd +lon_0=-83 +lat_0=-6 +units=km"),
    xlim = c(-1000, 600),
    ylim = c(-800, 700)
  ) +
  guides(color = "none")
#> In total 386 empty location records are removed before summarizing.
#> Zoom: 5
#> 
#> Fetching 9 missing tiles
#>   |                                                                                  |                                                                          |   0%  |                                                                                  |========                                                                  |  11%  |                                                                                  |================                                                          |  22%  |                                                                                  |=========================                                                 |  33%  |                                                                                  |=================================                                         |  44%  |                                                                                  |=========================================                                 |  56%  |                                                                                  |=================================================                         |  67%  |                                                                                  |==========================================================                |  78%  |                                                                                  |==================================================================        |  89%  |                                                                                  |==========================================================================| 100%
#> ...complete!

For more interactive explorations of the data other packages like mapview and leaflet might be of interest, as it allows to zoom into the tracks and explore the attributes of each location.

Animating

Using the tools from gganimate and ggspatial we can also add more context to the map and animate it. Here annotate_map_tile is used to add the OpenStreetMap background map and annotate_scale to add a scale bar. A variety of different animations are possible, here we show birds originating from different study_site’s. These kind of animations help to gain insights into the differences between subgroups of the data set. Besides tagging location, also different years, life stages or sexes are clear candidates to compare.

require(gganimate)
require(ggspatial)
animation_site <- ggplot() +
  annotation_map_tile(zoom = 5, progress = "none") +
  geom_sf(
    data = mt_track_lines(data),
    mapping = aes(group = individual_local_identifier),
    color = "black"
  ) +
  transition_states(study_site, state_length = 2) +
  enter_fade() +
  exit_fade() +
  ease_aes("cubic-in-out") +
  labs(title = "{closest_state}") +
  annotation_scale()
#> In total 386 empty location records are removed before summarizing.
animation_site

We can also take this one step further by animating the map view. To do that we use a local equal area projection and define for each state a manual zoom.

animation_site +
  coord_sf(
    crs = sf::st_crs("+proj=aeqd +lon_0=-83 +lat_0=-6 +units=km")
  ) +
  view_zoom_manual(
    pause_length = 2,
    xmin = c(-850, -900, -950),
    ymin = c(-350, -800, -350),
    ymax = c(610, 700, 610),
    xmax = c(500, 600, 500)
  )