First, load the required packages for this example and the
moveVis example movement data:
move_data is a
moveStack, containing three individual tracks.
moveVis works with
move class objects. If your movement tracks are present as
df2move() and the example code there for conversion. Let’s have a look at both timestamps and sampling rates of
We can conclude that each track has a sampling rate of roughly 4 minutes, however sampling rates differ over time. Due to this, tracks do not share unique timestamps. For animation, unique frame times are needed, regardless if we want to animate a single track or multiple at once. Thus, we need to align
move_data in order to * make all tracks share unique timestamps that can be assigned to frames * make all tracks share unique, steady sampling rates without gaps
You can use
align_move() to align
move_data to a sampling rate of 4 minutes:
move_data <- align_move(move_data, res = 4, unit = "mins")
Instead, you could apply your own functions for aligning your data, e.g. using more advanced interpolation methods.
Now, as the movement tracks are aligned, we can pair them with a base map to create frames that can be turned into an animation later on. You can use your own custom base map imagery or choose from default map types. Here is a GIF of some example base maps you can use out of the box thanks to the
You can display a list of all available maps:
# get a list of all available map_services and map_types get_maptypes()` $osm  "streets" "streets_de" "streets_fr" "humanitarian" "topographic" "roads"  "hydda" "hydda_base" "hike" "grayscale" "no_labels" "watercolor"  "toner" "toner_bg" "toner_lite" "terrain" "terrain_bg" "mtb" $carto  "light" "light_no_labels" "light_only_labels" "dark"  "dark_no_labels" "dark_only_labels" "voyager" "voyager_no_labels"  "voyager_only_labels" "voyager_labels_under" $mapbox  "satellite" "streets" "streets_basic" "hybrid" "light"  "dark" "high_contrast" "outdoors" "hike" "wheatpaste"  "pencil" "comic" "pirates" "emerald"
Currently, you can use more than 40 types of maps, provided by
Carto (both free without registration) and
Mapbox (free, but registration required). Most maps display thematic or terrain data, while
Mapbox also offers satellite imagery (see Example 3: using a mapbox satellite base map for details on how to register and use mapbox).
In this example, we want to use the OpenStreetMap ‘watercolour’ imagery with a transparency of 50% to start with something nice looking and colourful. To create a list of spatial frames from
move_data using a map, we can use
frames <- frames_spatial(move_data, path_colours = c("red", "green", "blue"), map_service = "osm", map_type = "watercolor", alpha = 0.5)
Instead of using
path_colours, you can add a
colour column to your
moveStack object. This allows you to colour your movement tracks as you want, e.g. not only by individual track, but by behavioral segment, time, age, speed or something different (see
?frames_spatial for details).
Have a look at the newly created
frames list object and display a randomly selected frame to get a first impression, how your animation will look like:
length(frames) # number of frames frames[] # display one of the frames
You can pass any list of frames like the one we just created to
animate_frames(). This function will turn your frames into an animation, written as a GIF image or a video file. For now, we do not want to add any customization to
frames and just create a
GIF from it. If you are not sure, which output formats can be used, run
suggest_formats() that returns you a vector of file suffixes that can be created on your system. For making a
frames, just run:
animate_frames(frames, out_file = "example_1.gif")
We have just used an
OSM base map that does not contain any map labels. How would the same frames look like with a standard
OSM streets base map?
frames <- frames_spatial(move_data, path_colours = c("red", "green", "blue"), map_service = "osm", map_type = "streets", map_res = 0.8) frames[] # display one of the frames
You may recognize that the map seems to be distorted which becomes mainly visible when looking at the map labels. By default,
moveVis calculates an equidistant map extent (squared), with y and x axis measuring equal surface distances. In addition,
moveVis reprojects the default base maps to the projection of your movement data. The default base maps are originally projected as
WGS 84 / Pseudo Mercator (
epsg:3857), also referred to as
Web Mercator, and thus are squeezed or stretched onto the projection grid of the movement data (in this case
WGS 84 / LatLon).
To represent the base map in its original projection, just reproject your movement data to the
WGS 84 / Pseudo Mercator projection and disable the calculation of an equidistant extent:
move_data <- sp::spTransform(move_data, crs("+init=epsg:3857")) frames <- frames_spatial(move_data, path_colours = c("red", "green", "blue"), map_service = "osm", map_type = "streets", map_res = 0.8, equidistant = F) frames[] # display one of the frames
Finally, animate the newly created frames:
animate_frames(frames, out_file = "example_1b.gif", width = 700, height = 500, res = 80)