Econometrics and Free Software by Bruno Rodrigues.
RSS feed for blog post updates.
Follow me on Mastodon, twitter, or check out my Github.
Check out my package that adds logging to R functions, {chronicler}.
Or read my free ebooks, to learn some R and build reproducible analytical pipelines..
You can also watch my youtube channel or find the slides to the talks I've given here.
Buy me a coffee, my kids don't let me sleep.

How to draw a map of arbitrary contiguous regions, or visualizing the spread of COVID-19 in the Greater Region

R

Introduction

I was able to blog during the year 2020 without mentioning the ongoing pandemic once. It’s not that I made any conscious effort not to talk about it, but I did not really want to do something that had already been done a 1000 times. This changed this year, when I wanted to look at the spread of COVID-19, not only in the Grand-Duchy of Luxembourg, the country I live in, but also among our neighbours. You see, the Grand-Duchy of Luxembourg is like an island, but instead of being surrounded by water, it’s surrounded by Belgians, Germans and Frenchmen. Many of them commute every day to Luxembourg to work, and even though they technically don’t live inside the country, many aspects of their lives happen inside Luxembourguish borders. Their children might even come to school here, and sometimes they live so close by the border, that they can catch Luxembourguish public transportation in their towns. 200k commuters from Belgium, Germany and France work here every day. That’s half our workforce! So that’s why I thought that it would make sense to look at the spread of the disease at the level of the so-called Greater Region. This Greater Region is made up of the Grand-Duchy of Luxembourg, the Provinces of Liège and Luxembourg in Belgium (hence why I keep writing the Grand-Duchy of Luxembourg to refer to the country, and the Province of Luxembourg to refer to the Belgian province of the same name), and two German Länders, the Saarland and the Rhineland-Palatinate. Confused? Welcome to Europe, where supranational institutions literally have to have a page entitled Do not get confused so that citizens don’t get lost (we still do).

So the Greater Region is not a state, but facilitates collaboration between the regions comprising it. To me, technically a citizen of the Greater Region, it feels like there was a want to peacefully correct for the randomness of history, where German-speaking regions ended up in both France and Belgium, and where Belgium and Luxembourg, well, somehow became independent countries.

Anyways, what I wanted to do was to first of all get the COVID-19 daily cases data for each of these regions. I did that, and even created a package called {covidGrandeRegion} hosted here that makes it very easy to download the latest data for the Greater Region. I will write another blog post about it, I have something in mind that I wanted to try for some time, and this was the first step. Then I thought that adding a function that would create a map could also be nice. And this is where the technical aspect of this blog post starts.

The problems to map the Greater Region

So how do you draw a map for an arbitrary landmass like the Greater Region? I wanted to draw the maps using {echarts4r}, and there’s a very easy guide you can read. If you want to draw a map for one, or several, countries, this guide is all you need. But I wanted a map with only parts of France, Belgium and Germany. The only complete country was Luxembourg. So the first problem was how to get only parts of a country. The second problem, is that I had daily covid cases for the lowest administrative levels for France (which are Départements), Belgium (the Provinces) and Germany (Land- and Stadtkreise). But for the Grand-Duchy of Luxembourg, there’s only data at the level of the country. So this would be another problem. How to draw a map with unequal levels of precision? One final problem: the names of the administrative divisions in my covid datasets are not the same than the ones that get downloaded if you follow the guide I linked before. So I had to rename them as well.

The solutions

Let’s first start by following the guide, so loading the packages, and getting the maps I need:

library(echarts4r)
library(sp)
library(raster)
library(geojsonio)
france_dep <- getData("GADM", country = "FRANCE", level = 2)

ger_kreise <- getData("GADM", country = "GERMANY", level = 2)

be_province <- getData("GADM", country = "BELGIUM", level = 2)

The above lines of code load the required packages, and download the maps for France, Belgium and Germany with the required administrative level I need. I’ll leave Luxembourg for last.

Let’s take a look at what type of object we’re dealing with:

class(france_dep)
## [1] "SpatialPolygonsDataFrame"
## attr(,"package")
## [1] "sp"

So it seems to be something like a data frame, but probably more complex. Looking for some help online, I saw that you can coerce it to a data frame:

as.data.frame(be_province)
##    GID_0  NAME_0   GID_1     NAME_1 NL_NAME_1     GID_2          NAME_2
## 1    BEL Belgium BEL.1_1  Bruxelles      <NA> BEL.1.1_1       Bruxelles
## 2    BEL Belgium BEL.2_1 Vlaanderen      <NA> BEL.2.1_1       Antwerpen
## 3    BEL Belgium BEL.2_1 Vlaanderen      <NA> BEL.2.2_1         Limburg
## 4    BEL Belgium BEL.2_1 Vlaanderen      <NA> BEL.2.3_1 Oost-Vlaanderen
## 5    BEL Belgium BEL.2_1 Vlaanderen      <NA> BEL.2.4_1  Vlaams Brabant
## 6    BEL Belgium BEL.2_1 Vlaanderen      <NA> BEL.2.5_1 West-Vlaanderen
## 7    BEL Belgium BEL.3_1   Wallonie      <NA> BEL.3.1_1  Brabant Wallon
## 8    BEL Belgium BEL.3_1   Wallonie      <NA> BEL.3.2_1         Hainaut
## 9    BEL Belgium BEL.3_1   Wallonie      <NA> BEL.3.3_1           Liège
## 10   BEL Belgium BEL.3_1   Wallonie      <NA> BEL.3.4_1      Luxembourg
## 11   BEL Belgium BEL.3_1   Wallonie      <NA> BEL.3.5_1           Namur
##                                                                                                             VARNAME_2
## 1  Brussel Hoofstadt|Brusselse Hoofdstedelijke Gewest|Brüssel|Bruxelas|Région de Bruxelles-Capitale|Brussels|Bruselas
## 2                                                                            Amberes|Antuérpia|Antwerp|Anvers|Anversa
## 3                                                                                                   Limbourg|Limburgo
## 4                   Flandres Oriental|Fiandra Orientale|Flandes Oriental|Flandre orientale|East Flanders|Ost Flandern
## 5                                                 Brabant Flamand|Brabante Flamenco|Brabante Flamengo|Flemish Brabant
## 6           Fiandra Occidentale|Flandes Occidental|Flandre occidentale|Flandres Ocidental|West Flandern|West Flanders
## 7                                                                                       Waals Brabant|Walloon Brabant
## 8                                                                                                 Henegouwen|Hennegau
## 9                                                                                            Luik|Liegi|Lieja|Lüttich
## 10                                                                                   Lussemburgo|Luxemburg|Luxemburgo
## 11                                                                                                              Namen
##    NL_NAME_2                                TYPE_2      ENGTYPE_2 CC_2 HASC_2
## 1       <NA> Hoofdstedelijk Gewest|Région Capitale Capital Region <NA>  BE.BU
## 2       <NA>                             Provincie       Province <NA>  BE.AN
## 3       <NA>                             Provincie       Province <NA>  BE.LI
## 4       <NA>                             Provincie       Province <NA>  BE.OV
## 5       <NA>                             Provincie       Province <NA>  BE.VB
## 6       <NA>                             Provincie       Province <NA>  BE.WV
## 7       <NA>                              Province      Provincie <NA>  BE.BW
## 8       <NA>                              Province      Provincie <NA>  BE.HT
## 9       <NA>                              Province      Provincie <NA>  BE.LG
## 10      <NA>                              Province      Provincie <NA>  BE.LX
## 11      <NA>                              Province      Provincie <NA>  BE.NA

We’re not going to convert them to data frames however; but this is an interesting clue; these SpatialPolygonsDataFrame objects share common methods with data frames. What this means is that we can use the usual, base R way of manipulating these objects.

So to get only the French départements I need, I can slice them like so:

lorraine <- france_dep[`%in%`(france_dep$NAME_2, c("Meurthe-et-Moselle", "Meuse", "Moselle", "Vosges")),]

Same for the German kreise, here I select the Länder which are a higher administrative division than the Kreise, which makes it faster (so I don’t need to type all the 40+ Kreise):

ger_kreise <- ger_kreise[`%in%`(ger_kreise$NAME_1, c("Rheinland-Pfalz", "Saarland")),]

For Germany, many Kreise had a name which was different than on my covid data, so I had to rename them. So here again, the base R way of doing things works:

ger_kreise$NAME_2[ger_kreise$NAME_2 == "Eifelkreis Bitburg-Prüm"]  <- "Bitburg-Prüm"
ger_kreise$NAME_2[ger_kreise$NAME_2 == "St. Wendel"]  <- "Sankt Wendel"
ger_kreise$NAME_2[ger_kreise$NAME_2 == "Altenkirchen (Westerwald)"]  <- "Altenkirchen"
ger_kreise$NAME_2[ger_kreise$NAME_2 == "Neustadt an der Weinstraße"]  <- "Neustadt a.d.Weinstraße"
ger_kreise$NAME_2[ger_kreise$NAME_2 == "Landau in der Pfalz"]  <- "Landau i.d.Pfalz"
ger_kreise$NAME_2[ger_kreise$NAME_2 == "Ludwigshafen am Rhein"]  <- "Ludwigshafen"
ger_kreise$NAME_2[ger_kreise$NAME_2 == "Frankenthal (Pfalz)"]  <- "Frankenthal"

Finally, I do the same for Belgium, and rename their province of Luxembourg, which was simply called “Luxembourg”, to “Province de Luxembourg”:

be_wallonia <- be_province[be_province$NAME_1 == "Wallonie", ]
be_wallonia$NAME_2[be_wallonia$NAME_2 == "Luxembourg"]  <- "Province de Luxembourg"

I rename the province because the Grand-Duchy of Luxembourg is also only called “Luxembourg” in the data, and this would cause issues when mapping.

Now, comes Luxembourg. As I’ve written above, I only have data at the level of the country, so I download the country map:

lu_map_0 <- getData("GADM", country = "LUXEMBOURG", level = 0)

Let’s also see how it looks like as a data frame:

as.data.frame(lu_map_0)
##   GID_0     NAME_0
## 1   LUX Luxembourg

Unlike the previous SpatialPolygonsDataFrames, there are much less columns and this will cause an issue. Indeed, in order to have a single SpatialPolygonsDataFrame object to draw my map, I will need to combine them. This will be very easy, by simple using the rbind() function. Again, simply using base R functions. However, this only works if the data frames have the same columns. Another issue, is that I will be using the names of the regions which are in the SpatialPolygonsDataFrames’ column called NAME_2, but for Luxembourg, the name of the region (in this case the whole country) is in the column called NAME_0. So I need to add this columns to the SpatialPolygonsDataFrame object for Luxembourg:

lu_map_0$GID_1 <- NA
lu_map_0$NAME_1 <- NA
lu_map_0$NL_NAME_1 <- NA
lu_map_0$GID_2 <- NA
lu_map_0$NAME_2 <- "Luxembourg"
lu_map_0$VARNAME_2 <- NA
lu_map_0$NL_NAME_2 <- NA
lu_map_0$TYPE_2 <- NA
lu_map_0$ENGTYPE_2 <- NA
lu_map_0$CC_2 <- NA
lu_map_0$HASC_2 <- NA

Aaaand… that’s it! Wasn’t that hard, but a bit convoluted nonetheless. Now I can bind all the SpatialPolygonsDataFrame objects in one and use that for mapping:

grande_region <- do.call(rbind, list(lorraine, ger_kreise, be_wallonia, lu_map_0))

as.data.frame(grande_region)
##     GID_0     NAME_0    GID_1          NAME_1 NL_NAME_1       GID_2
## 76    FRA     France  FRA.6_1       Grand Est      <NA>   FRA.6.7_1
## 77    FRA     France  FRA.6_1       Grand Est      <NA>   FRA.6.8_1
## 78    FRA     France  FRA.6_1       Grand Est      <NA>   FRA.6.9_1
## 70    FRA     France  FRA.6_1       Grand Est      <NA>  FRA.6.10_1
## 99    DEU    Germany DEU.11_1 Rheinland-Pfalz      <NA>  DEU.11.1_1
## 110   DEU    Germany DEU.11_1 Rheinland-Pfalz      <NA>  DEU.11.2_1
## 121   DEU    Germany DEU.11_1 Rheinland-Pfalz      <NA>  DEU.11.3_1
## 129   DEU    Germany DEU.11_1 Rheinland-Pfalz      <NA>  DEU.11.4_1
## 130   DEU    Germany DEU.11_1 Rheinland-Pfalz      <NA>  DEU.11.5_1
## 131   DEU    Germany DEU.11_1 Rheinland-Pfalz      <NA>  DEU.11.6_1
## 132   DEU    Germany DEU.11_1 Rheinland-Pfalz      <NA>  DEU.11.7_1
## 133   DEU    Germany DEU.11_1 Rheinland-Pfalz      <NA>  DEU.11.8_1
## 134   DEU    Germany DEU.11_1 Rheinland-Pfalz      <NA>  DEU.11.9_1
## 100   DEU    Germany DEU.11_1 Rheinland-Pfalz      <NA> DEU.11.10_1
## 101   DEU    Germany DEU.11_1 Rheinland-Pfalz      <NA> DEU.11.11_1
## 102   DEU    Germany DEU.11_1 Rheinland-Pfalz      <NA> DEU.11.12_1
## 104   DEU    Germany DEU.11_1 Rheinland-Pfalz      <NA> DEU.11.14_1
## 103   DEU    Germany DEU.11_1 Rheinland-Pfalz      <NA> DEU.11.13_1
## 105   DEU    Germany DEU.11_1 Rheinland-Pfalz      <NA> DEU.11.15_1
## 106   DEU    Germany DEU.11_1 Rheinland-Pfalz      <NA> DEU.11.16_1
## 107   DEU    Germany DEU.11_1 Rheinland-Pfalz      <NA> DEU.11.17_1
## 108   DEU    Germany DEU.11_1 Rheinland-Pfalz      <NA> DEU.11.18_1
## 111   DEU    Germany DEU.11_1 Rheinland-Pfalz      <NA> DEU.11.20_1
## 109   DEU    Germany DEU.11_1 Rheinland-Pfalz      <NA> DEU.11.19_1
## 112   DEU    Germany DEU.11_1 Rheinland-Pfalz      <NA> DEU.11.21_1
## 113   DEU    Germany DEU.11_1 Rheinland-Pfalz      <NA> DEU.11.22_1
## 114   DEU    Germany DEU.11_1 Rheinland-Pfalz      <NA> DEU.11.23_1
## 115   DEU    Germany DEU.11_1 Rheinland-Pfalz      <NA> DEU.11.24_1
## 116   DEU    Germany DEU.11_1 Rheinland-Pfalz      <NA> DEU.11.25_1
## 117   DEU    Germany DEU.11_1 Rheinland-Pfalz      <NA> DEU.11.26_1
## 118   DEU    Germany DEU.11_1 Rheinland-Pfalz      <NA> DEU.11.27_1
## 119   DEU    Germany DEU.11_1 Rheinland-Pfalz      <NA> DEU.11.28_1
## 120   DEU    Germany DEU.11_1 Rheinland-Pfalz      <NA> DEU.11.29_1
## 122   DEU    Germany DEU.11_1 Rheinland-Pfalz      <NA> DEU.11.30_1
## 124   DEU    Germany DEU.11_1 Rheinland-Pfalz      <NA> DEU.11.32_1
## 123   DEU    Germany DEU.11_1 Rheinland-Pfalz      <NA> DEU.11.31_1
## 125   DEU    Germany DEU.11_1 Rheinland-Pfalz      <NA> DEU.11.33_1
## 126   DEU    Germany DEU.11_1 Rheinland-Pfalz      <NA> DEU.11.34_1
## 127   DEU    Germany DEU.11_1 Rheinland-Pfalz      <NA> DEU.11.35_1
## 128   DEU    Germany DEU.11_1 Rheinland-Pfalz      <NA> DEU.11.36_1
## 135   DEU    Germany DEU.12_1        Saarland      <NA>  DEU.12.1_1
## 136   DEU    Germany DEU.12_1        Saarland      <NA>  DEU.12.2_1
## 137   DEU    Germany DEU.12_1        Saarland      <NA>  DEU.12.3_1
## 138   DEU    Germany DEU.12_1        Saarland      <NA>  DEU.12.4_1
## 139   DEU    Germany DEU.12_1        Saarland      <NA>  DEU.12.5_1
## 140   DEU    Germany DEU.12_1        Saarland      <NA>  DEU.12.6_1
## 7     BEL    Belgium  BEL.3_1        Wallonie      <NA>   BEL.3.1_1
## 8     BEL    Belgium  BEL.3_1        Wallonie      <NA>   BEL.3.2_1
## 9     BEL    Belgium  BEL.3_1        Wallonie      <NA>   BEL.3.3_1
## 10    BEL    Belgium  BEL.3_1        Wallonie      <NA>   BEL.3.4_1
## 11    BEL    Belgium  BEL.3_1        Wallonie      <NA>   BEL.3.5_1
## 1     LUX Luxembourg     <NA>            <NA>      <NA>        <NA>
##                                NAME_2                        VARNAME_2
## 76                 Meurthe-et-Moselle                             <NA>
## 77                              Meuse                             <NA>
## 78                            Moselle                       Lothringen
## 70                             Vosges                             <NA>
## 99                          Ahrweiler                             <NA>
## 110                      Altenkirchen                             <NA>
## 121                       Alzey-Worms                             <NA>
## 129                      Bad Dürkheim                             <NA>
## 130                     Bad Kreuznach                             <NA>
## 131               Bernkastel-Wittlich                             <NA>
## 132                        Birkenfeld                             <NA>
## 133                       Cochem-Zell                             <NA>
## 134                  Donnersbergkreis                             <NA>
## 100                      Bitburg-Prüm                             <NA>
## 101                       Frankenthal                             <NA>
## 102                       Germersheim                             <NA>
## 104                    Kaiserslautern                             <NA>
## 103 Kaiserslautern (Kreisfreie Stadt)                             <NA>
## 105                           Koblenz                             <NA>
## 106                             Kusel                             <NA>
## 107                  Landau i.d.Pfalz                             <NA>
## 108                      Ludwigshafen                             <NA>
## 111                             Mainz                             <NA>
## 109                      Mainz-Bingen                             <NA>
## 112                     Mayen-Koblenz                             <NA>
## 113           Neustadt a.d.Weinstraße                             <NA>
## 114                           Neuwied                             <NA>
## 115                         Pirmasens                             <NA>
## 116              Rhein-Hunsrück-Kreis                             <NA>
## 117                  Rhein-Lahn-Kreis                             <NA>
## 118                 Rhein-Pfalz-Kreis                             <NA>
## 119                            Speyer                             <NA>
## 120               Südliche Weinstraße                             <NA>
## 122                      Südwestpfalz                             <NA>
## 124                             Trier                             <NA>
## 123                    Trier-Saarburg                             <NA>
## 125                       Vulkaneifel                             <NA>
## 126                   Westerwaldkreis                             <NA>
## 127                             Worms                             <NA>
## 128                       Zweibrücken                             <NA>
## 135                     Merzig-Wadern                             <NA>
## 136                       Neunkirchen                             <NA>
## 137       Regionalverband Saarbrücken                             <NA>
## 138                         Saarlouis                             <NA>
## 139                   Saarpfalz-Kreis                             <NA>
## 140                      Sankt Wendel                             <NA>
## 7                      Brabant Wallon    Waals Brabant|Walloon Brabant
## 8                             Hainaut              Henegouwen|Hennegau
## 9                               Liège         Luik|Liegi|Lieja|Lüttich
## 10             Province de Luxembourg Lussemburgo|Luxemburg|Luxemburgo
## 11                              Namur                            Namen
## 1                          Luxembourg                             <NA>
##     NL_NAME_2           TYPE_2  ENGTYPE_2  CC_2   HASC_2
## 76       <NA>      Département Department    54    FR.MM
## 77       <NA>      Département Department    55    FR.MS
## 78       <NA>      Département Department    57    FR.MO
## 70       <NA>      Département Department    88    FR.VG
## 99       <NA>        Landkreis   District 07131 DE.RP.AR
## 110      <NA>        Landkreis   District 07132 DE.RP.AT
## 121      <NA>        Landkreis   District 07331 DE.RP.AW
## 129      <NA>        Landkreis   District 07332 DE.RP.BD
## 130      <NA>        Landkreis   District 07133 DE.RP.BK
## 131      <NA>        Landkreis   District 07231 DE.RP.BW
## 132      <NA>        Landkreis   District 07134 DE.RP.BR
## 133      <NA>        Landkreis   District 07135 DE.RP.CZ
## 134      <NA>        Landkreis   District 07333 DE.RP.DN
## 100      <NA>        Landkreis   District 07232 DE.RP.EB
## 101      <NA> Kreisfreie Stadt   District 07311 DE.RP.FA
## 102      <NA>        Landkreis   District 07334 DE.RP.GR
## 104      <NA>        Landkreis   District 07335 DE.RP.KL
## 103      <NA> Kreisfreie Stadt   District 07312 DE.RP.KL
## 105      <NA> Kreisfreie Stadt   District 07111 DE.RP.KO
## 106      <NA>        Landkreis   District 07336 DE.RP.KU
## 107      <NA> Kreisfreie Stadt   District 07313 DE.RP.LP
## 108      <NA> Kreisfreie Stadt   District 07314 DE.RP.LR
## 111      <NA> Kreisfreie Stadt   District 07315 DE.RP.MI
## 109      <NA>        Landkreis   District 07339 DE.RP.MB
## 112      <NA>        Landkreis   District 07137 DE.RP.MK
## 113      <NA> Kreisfreie Stadt   District 07316 DE.RP.NW
## 114      <NA>        Landkreis   District 07138 DE.RP.NU
## 115      <NA> Kreisfreie Stadt   District 07317 DE.RP.PR
## 116      <NA>        Landkreis   District 07140 DE.RP.RH
## 117      <NA>        Landkreis   District 07141 DE.RP.RN
## 118      <NA>        Landkreis   District 07338 DE.RP.RZ
## 119      <NA> Kreisfreie Stadt   District 07318 DE.RP.SE
## 120      <NA>        Landkreis   District 07337 DE.RP.SW
## 122      <NA>        Landkreis   District 07340 DE.RP.SD
## 124      <NA> Kreisfreie Stadt   District 07211 DE.RP.TI
## 123      <NA>        Landkreis   District 07235 DE.RP.TS
## 125      <NA>        Landkreis   District 07233 DE.RP.VL
## 126      <NA>        Landkreis   District 07143 DE.RP.WS
## 127      <NA> Kreisfreie Stadt   District 07319 DE.RP.WR
## 128      <NA> Kreisfreie Stadt   District 07320 DE.RP.ZE
## 135      <NA>        Landkreis   District 10042 DE.SL.MW
## 136      <NA>        Landkreis   District 10043 DE.SL.NU
## 137      <NA>        Landkreis   District 10041 DE.SL.SB
## 138      <NA>        Landkreis   District 10044 DE.SL.SA
## 139      <NA>        Landkreis   District 10045 DE.SL.SP
## 140      <NA>        Landkreis   District 10046 DE.SL.SW
## 7        <NA>         Province  Provincie  <NA>    BE.BW
## 8        <NA>         Province  Provincie  <NA>    BE.HT
## 9        <NA>         Province  Provincie  <NA>    BE.LG
## 10       <NA>         Province  Provincie  <NA>    BE.LX
## 11       <NA>         Province  Provincie  <NA>    BE.NA
## 1        <NA>             <NA>       <NA>  <NA>     <NA>

And now I can continue following the tutorial from the {echarts4r} website, by converting this SpatialPolygonsDataFrame object for the Greater Region into a geojson file which can now be used to draw maps! You can take a look at the final result here.

I don’t post the code to draw the map here, because it would require some more tinkering by joining the COVID data. But you can find my raw script here (lines 51 to 61) or you could also take a look at the draw_map() function from the package I made, which you can find here.

I really like the end result, {echarts4r} is really a fantastic package! Stay tuned part 2 of the project, which will deal with machine learning.

Hope you enjoyed! If you found this blog post useful, you might want to follow me on twitter for blog post updates and buy me an espresso or paypal.me, or buy my ebook on Leanpub. You can also watch my videos on youtube. So much content for you to consoom!

Buy me an EspressoBuy me an Espresso