How to make animated maps with QGIS? With the native temporal support! Already in earlier versions of QGIS it has been possible to visualize temporal data with the excellent Time Manager plugin. I have been making a lot of animations (a.k.a. geogifs) with Time Manager and wrote a blog about the process a few years ago which became really popular. Now starting from the version 3.14, there is a native support to work with the fourth dimension, so time to update the process!
The temporal capabilities have been developed mostly by Nyall Dawson who has also made a tutorial video about the process of making animations. Many of the functionalities are based on Time Manager, so if you have used that previously, you can get going with it quite fast.
It is still very new, so there’s not much about it even in the QGIS documentation, but I will hope that this blog post can give you a nudge to try it out, make some awesome animations and maybe even contribute to the functionality.
About temporal data
Once you have installed a version of QGIS with Temporal Controller (>= 3.14) for your OS, you are good to go. Firstly for this tutorial to make more sense, you need to acquire a vector dataset with some information about time and preferably in a valid way. In QGIS the basic valid datetime format is YYYY-MM-DD hh:mm:ss, but the Temporal Controller can work also only with date information (e.g. . YYYY-MM-DD). Read more about different types to represent date and time from my old blog post.
So just like integers, decimal numbers or strings, time can be represented as a QGIS data column type. Easiest way to make an animation is to have data that has that column type ready, but you can also make that using QGIS expressions out of not-so-perfect date attributes. You can do this by parsing the information and converting it (to_datetime function in the expression evaluator).
If you just want to try it out and don’t have any temporal data on your machine, you can try out some of my previously extracted datasets for Time Manager demos:
- Here you can find an extract of train traffic to create some moving points. It’s a pretty big GeoPackage (90 mb), but is pretty fun to play with.
- Here you can load a set of meteorite landings. Originally from NASA and I’ve extracted it specifically for animation purposes. Craig Taylor has made some cool stuff with it.
- Or you can download buildings in the Helsinki region. Originally extracted from Helsinki Region Infoshare.
The datasets might need a bit of attribute handling to work with the Temporal Controller (except for the trains). Remember that you can use any layer that has any type of information about time. And if you’ve heard the good old GIS phrase of how 80% of all information has a spatial component, I can with good confidence say that the same 80% probably also has a temporal component of some kind.
Temporal Controller walkthrough
So once you have acquired some data you should open up a new project. If you have a vector layer in your project, you should open up the Properties of that layer. You can do that by right clicking the layer and selecting properties or with a double-click on the layer list. Now on the left you will see all the familiar tools and a new one: Temporal. If you go to that menu you should see the following view:
Looks like a nice and simple UI. Next up you need to tick the box and select which configuration type fits your data.
Configuration offers you the following options:
- Fixed time range. Here you can manually select when ALL the features of the layer will be drawn on the map. This option doesn’t require the data to have any date or time fields. Could be helpful e.g. with a background layer in your animation.
- Single field with Date/Time. This option only requires one attribute and set the event duration manually for all features. See more below.
- Separate Fields for Start and End Date/Time. Your data should have two attributes with start and end times. Individual features that interact with the maps temporal extent will be rendered. An example of this type of data could be building vectors which would have building date and demolition date.
- Separate Fields for Start and Event Duration. Like the ones above, this also works on individual features, but event duration should be read from the data. As an example if you are working with the meteorite data, you could build event durations based on the magnitude of the meteorite to build a nice visual effect. So bigger meteorites stay on the map for a longer time.
- Start and End Date/Time from Expressions. If your data does not have a valid datetime column you can use this option to make one form existing fields. For instance if you are using the region_buildings dataset in your animation provided to you earlier, you could build a valid timestamp using the expression to_date(“YYYYMMDD”) as the starting date and for example to_date(‘2020-01-01’) as the end date to make the buildings appear cumulatively.
- Redraw Layer Only. Like the first option, but layer gets redrawn on every frame. The first option and this are probably the biggest changes compared to Time Manager. This basically allows you to redraw layers even without a temporal attribute. You can for example use random values here that change on every frame or parse out seconds from. You can get some crazy ideas by applying the ideas from this presentation by Nyall Dawson.
If you are using the train data that was provided earlier, you should select Single field with Date/Time. The event duration defines how long the features will be visible after the start. As the GPS points in the train data are a bit spotty, I would say that somewhere between 10 seconds and a minute might be a good first try for the event duration in this case.
After setting that part up, you can move to explore and filter your data with the dock widget. Just like with Time Manager, the Temporal Controller has a dock widget which allows you to analyze and preview your masterpiece in the QGIS main window. If you can’t see it, go to View → Panels → Temporal Controller.
After the panel appears, you should click on the green play button on the left to activate the animated temporal navigation. Now you should see more buttons in your dock and in practice this means you can move forward and backwards in your animation. Next you should click on the blue arrows for the Temporal Controller to read the time attributes from your data and filter it accordingly.
The Step value in the dock is basically frame duration: how big of a piece of the data each frame should show. Adjust this accordingly based on your dataset. Because with the train data we are working with only a single attribute, it makes sense to make the Step value in your animation to match your event duration or make it a bit more. Also take note that having a very small step value and a long time frame leads to a huge pile of frames. So getting these values just right (no blank frames, no overlapping frames, not too many output frames etc.) takes a bit of tweaking.
The time how long each frame takes to load (and later the export) depends on your machine performance, file format and the settings you have chosen. If you are working with a large file and updates between frames take a long time, you might want to speed up your process and build an index for your column with the timestamp. You can do this by going to the Processing menu and selecting the “Add attribute index” tool. I have made a feature request to have this option inside the Temporal Controller. Also please use more efficient file formats with bigger files (e.g. PostGIS or GeoPackage instead of CSV or GeoJSON).
So now it’s mostly just styling. Try for example using expressions (e.g. symbol size based on the speed value for a bubbling effect) and categorize the train color by train id. You might end up with something like this:
From frames to an animation
So now you have an animation that you can explore in your QGIS project. Next up if you click on the save button (the floppy disk of course) you get the following dialog where you can pick where to save the results. This is very similar to the normal map image export dialog in QGIS, but unlike with Time Manager you can now define the output resolution by hand and make high-resolution animations if you wish.
Currently by default QGIS outputs frames as individual png files. I am usually making gif animations with something between 100 to 500 frames. These are not too long and the size stays moderate (e.g. for Twitter which has a 15 mb gif limit).
For turning the images to an animation you have several options:
- On Windows 10 you can use the built-in Video Editor app. Just import the frames to a project and make a video. Very simple.
- If you are familiar with using command line tools, on any OS you can use ffmpeg. A really powerful tool and you can find instructions on basic usage from my QGIS Atlas blog post.
- If you want to make an animation online, you can use for example ezGIF.com. Works well on smaller animations.
- For shorter gif animations and if you are more familiar with image editing, on any OS you can use GIMP.
- On Mac you can use gifsicle.
Animation speed and possible effects which you can add in the editing part are totally up to your own imagination. But the framerate of the final animation is a really deifining factor in how easy your animation is to read. Especially with gif animations where you can’t go forward and backwards. Hopefully we will also see a native animation export with Temporal Controller in the future.
Styling with expressions and some more animation ideas
Advanced cartographic styling is undoubtedly one of the most powerful capabilities of QGIS. When writing this I looked back at my old blog post about Time Manager where I gave some styling tips. Those are still very valid:
- Don’t add unnecessary elements on your map. Even ditch (or at least simplify) the background map if you can. Don’t forget that you can change your project background color and black is always cool.
- Experiment with colors and blending modes. Just like with any static map, these really give that extra touch to your outputs.
- Use expressions and dynamic styling.
Let’s stop on that final point for a while. In my old train animation I used the train speed attribute to define the circle size. You can do this by going to Layer properties and clicking the small black arrow on the right side of Size and select Edit. From there you can test out different values for point size, label positions or whatever you think you can use values dynamically from the data.
Now when the Temporal Controller is a native component in QGIS rather than a plugin that brings you even more possibilities. As an example if you were to visualize the train data you end up having sometimes gaps in the animation or alternatively multiple points at the same time. This is due to spotty GPS traces and you might face similar data issues with your own data too. One idea how to tackle this is with expressions and the geometry generator.
In the dialog below I have written an expression that takes the centroid of each individual train. It first groups the set of points which are inside the currently visible timeframe and by the train_id attribute into a multipoint and then replaces that with a centerpoint. As you can see, the expression uses @map_end_time and @map_start_time variables. For some reason this filtering is still painfully slow, but it’s just a proof of concept.
Other time related variables which have been added to the list include variables for the whole animation starting and ending times as well as ones for frame rates and frame numbers. Combining these for instance with the symbol colors could bring you
So what else could you animate besides just the example datasets given earlier? I have made several animations with isochrones that show you how far you can reach from a specific point at a specific time. I think the original idea came from the Digital Geography blog few years ago. But what if you want to do something like this?
You can use the HQGIS plugin to get isochrones through the HERE API from a city (or any location) of your choice and by changing the time attribute. As you change the start time to different times of the day you will see the pulse of the city: during peak rush hours in the morning and in the afternoon you can’t reach as big of an area as you can during the night. I have done this manually 24 times (for each hour of the day) and then merged the vector layers (Processing → Merge vector layers). Doing the data collection manually for a single isochrone animation is still ok, but highly recommended to write a Python script for bigger data collection.
Other ideas for use cases of the Temporal Controller include (but not limited to):
- Animated choropleth maps. Bar chart races have been a huge hit in data visualization over the past year or two. Maybe with a smooth interpolation like that we could make animated thematic maps just as popular?
- Animated GPS tracks. Export data from your training app, GPS device or somewhere else. Really nice and simple data to get started with and contains standard datetime information. See example from Tim Sutton.
- Animated rasters. In this blog post I have been covering vector functionalities, but the Temporal Controller can also work with rasters! For example WMS-T. You are able to constrain the DateTime range for any temporal layer from WMS-T providers.
Of course the temporal functionalities can be now also found from the PyQGIS API. That brings you a whole world of opportunities for automating different workflows and creating animations with purely scripting.
Temporal Controller has just been added to QGIS so it’s not yet perfect and lacks many of the capabilities that Time Manager has. For instance adding animation time as text to the map currently requires tedious work with temporary layers, but hopefully that gets improved e.g. through annotations.
Hope you enjoyed reading and hope to see many creative and beautiful animated maps!