How to Make a Choropleth Map GIF – A COVID19 Map Over Time
In a previous post we showed you how to make choropleth maps in Stata using case data for COVID19. In this tip I will go through the steps needed to take time-series COVID19 data, combine it with map data and make a moving graphic (GIF) of COVID19 cases over time. I have already saved my map data, population data and COVID19 data for Australia. This data is set up and loaded according to the steps I went through previously here.
In this post I make use of the new Stata v16 feature of multiple frames in memory. I found using frames was the easiest way to create my GIF image. In a previous post about creating a GIF image from Stata graphs I used an online tool to compile the images into a moving graphic. In this post I use python instead, because with python integration in Stata v16 this allows me to create the images and assemble the GIF entirely from within Stata.
Part 1 – Setting up datasets in Stata
To start, I need to set up my frames in Stata to make sure they contain all the information I need. I also set my current working directory to a folder within my Documents where all my images will be created. In this folder I have placed all the datasets I need. In the command pane:
I now have my frames set up the way that I want. The frlink and frget commands can be used to link two frames in memory and then grab variables. This is similar to merging, but can be done completely within memory rather than having to merge in a saved dataset. This makes it a faster way to grab other variables than merge.
Part 2 – Looping through the days to make images
Now that we have all our frames set up, I am going to set up a loop to create the COVID19 map for each day starting with 12 March 2020. I will stop at the day before, as we do not have cases data for the current day. For this loop I use the frlink, frget and frame put commands to add the case data one day at a time to the map data. If you do not have Stata v16 you will need to do this using merge instead, however I find it much faster and easier to use frames. In the command pane:
This set of commands uses Stata loops and macros to work through each day’s COVID19 data and generate a map for that day. I use the set graphics off command at the start of the loop, and turn the graphics back on at the end. I do this to improve the Stata processing time, as Stata is not required to put the image on screen for me to see. I ran this command on 14 May. The first two lines are creating the local macros startday and today. They record the 12 March and the 14 May respectively in numeric form. This allows me to run a while loop which will stop when startday (which is added to at the end of each loop run) is no longer less than today.
Within the while loop I start by putting the COVID19 data for the day startday into its own separate frame (day). I then swap to the map frame and use frlink to link the new frame day which contains COVID19 data for only one day. I do this because the COVID19 cases dataset contains the case numbers for each state from January 2020 to the 13 May. To create my map I need the data one day at a time, not all at once. By using frame put I create a new frame with only one day’s worth of COVID19 data, which I can then link to my map data with frlink and then transfer case data into the map dataset with frget.
Once the case data is together with the map data, I use grmap to draw a map of case data and export that as a png. I use the count local macro to suffix the name of each exported graph, so my graphs are named “map1”, “map2”, …, “map63”.
The final comment to make is regarding the if-statements in the middle which are needed for a choropleth map of Australia. For most countries or regions that you map the if-statements will be unnecessary. However, a map of Australia draws the ACT, a territory contained entirely within the state of NSW. When you draw a normal choropleth map the ACT is coloured-over with the NSW colour. To fix this, I sort states by number of cases, and then use the if statements to work out which of the four colours the ACT should be. Then when I draw my map with grmap I can specify which colour the ACT needs to be using a local macro. These extra steps are only needed when you have a situation where there is one region entirely contained within another that you are mapping different colours.
Part 3 – Generating a GIF with your individual map images
There are many online tools that allow you to create GIF images by uploading the individual images. However, it is also possible to create a GIF entirely from within Stata using the new Python integration for Stata v16. To do this you will need to have Python installed and initialised in Stata. To check, type the command python query in Stata. This should give you information about which python you have installed. Stata should be able to automatically detect the python you have installed, provided you installed it in the default path.
Once you have python installed and set up in Stata you will need to obtain the imageio python package. You can download this using pip through the command window. You can access the command window through Stata using the Stata command shell, and you can give the pip install command straight to shell in Stata. If you put command shell pip install imageio into Stata, this will tell Stata to open the command window, run the pip command, and then return control to Stata. Alternatively, just typing shell will open the command window for you to use. Remember if you just use shell by itself, you will need to close the command window before you can continue to use Stata. I also use the Python package pygifsicle to compress my GIF file so it isn’t so big.
Having imported the imageio python package, I use the following commands in a Stata do-file to create my GIF image. Make sure to run these commands from within a do-file, as the tabs are important for Python looping. The do-file contains the following:
This uses the python package imageio to create a GIF from my 63 individual map images. The finished GIF image is called "finalgif.gif", and is shown below: