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 data.frames, see df2move() and the example code there for conversion. Let’s have a look at both timestamps and sampling rates of move_data:

timeLag(move_data, unit = "mins")

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 (240 seconds) at the seconds digit “:00”:


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 slippymath package:

You can display a list of all available maps:

# get a list of all available map_services and map_types

 [1] "streets"      "streets_de"   "streets_fr"   "humanitarian" "topographic"  "roads"       
 [7] "hydda"        "hydda_base"   "hike"         "grayscale"    "no_labels"    "watercolor"  
[13] "toner"        "toner_bg"     "toner_lite"   "terrain"      "terrain_bg"   "mtb"         

 [1] "light"                "light_no_labels"      "light_only_labels"    "dark"                
 [5] "dark_no_labels"       "dark_only_labels"     "voyager"              "voyager_no_labels"   
 [9] "voyager_only_labels"  "voyager_labels_under"

 [1] "satellite"     "streets"       "streets_basic" "hybrid"        "light"        
 [6] "dark"          "high_contrast" "outdoors"      "hike"          "wheatpaste"   
[11] "pencil"        "comic"         "pirates"       "emerald"      

Currently, you can use more than 40 types of maps, provided by OpenStreetMap, 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_spatial():

frames <- frames_spatial(move_data, path_colours = c("red", "green", "blue"),

Instead of using path_colours, you can add a colour column to your move or 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[[100]] # 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 du not want to add any customizations 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 GIF from frames, just run:

animate_frames(frames, out_file = "/full/path/to/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?

                         map_service = "osm", map_type = "streets", map_res = 0.8)
frames[[100]] # 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 originially 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"))
                         map_service = "osm", map_type = "streets", map_res = 0.8, equidistant = F)
frames[[100]] # display one of the frames

Finally, animate the newly created frames:

animate_frames(frames, out_file = "/full/path/to/example_1b.gif", width = 700, height = 500, res = 80)