Playing around with geo mapping: combining demographic data with spatial data

In this post, we will play around with some basic geo mapping. More preciseyl, we will explore some easy ways to plot a choropleth map.

First, let’s load some geo data from Bundeswahlleiter, and combine it with some socio demographic data from the same source.

Preparation

Let’s load some packages:

library(tidyverse)
## Warning: package 'dplyr' was built under R version 3.5.1
library(sf)
library(viridis)
suppressPackageStartupMessages(library(googleVis))

Geo data:

my_path_wahlkreise <- "~/Documents/datasets/geo_maps/btw17_geometrie_wahlkreise_shp/Geometrie_Wahlkreise_19DBT.shp"
file.exists(my_path_wahlkreise)
## [1] TRUE

socio demographic data:

unemp_file <- "~/Documents/datasets/Strukturdaten_De/btw17_Strukturdaten-utf8.csv"
file.exists(unemp_file)
## [1] TRUE
unemp_de_raw <- read_delim(unemp_file,
                           ";", escape_double = FALSE,
                           locale = locale(decimal_mark = ",",
                                           grouping_mark = "."),
                           trim_ws = TRUE,
                           skip = 8)
wahlkreise_shp <- st_read(my_path_wahlkreise)
## Reading layer `Geometrie_Wahlkreise_19DBT' from data source `/Users/sebastiansaueruser/Documents/datasets/geo_maps/btw17_geometrie_wahlkreise_shp/Geometrie_Wahlkreise_19DBT.shp' using driver `ESRI Shapefile'
## Simple feature collection with 299 features and 4 fields
## geometry type:  MULTIPOLYGON
## dimension:      XY
## bbox:           xmin: 280387.7 ymin: 5235855 xmax: 921025.5 ymax: 6101444
## epsg (SRID):    NA
## proj4string:    +proj=utm +zone=32 +ellps=GRS80 +units=m +no_defs

Some data cleansing:

unemp_names <- names(unemp_de_raw)
unemp_names
##  [1] "Land"                                                                                                 
##  [2] "Wahlkreis-Nr."                                                                                        
##  [3] "Wahlkreis-Name"                                                                                       
##  [4] "Gemeinden am 31.12.2015 (Anzahl)"                                                                     
##  [5] "Fläche am 31.12.2015 (km²)"                                                                           
##  [6] "Bevölkerung am 31.12.2015 - Insgesamt (in 1000)"                                                      
##  [7] "Bevölkerung am 31.12.2015 - Deutsche (in 1000)"                                                       
##  [8] "Bevölkerung am 31.12.2015 - Ausländer (%)"                                                            
##  [9] "Bevölkerungsdichte am 31.12.2015 (Einwohner je km²)"                                                  
## [10] "Zu- (+) bzw. Abnahme (-) der Bevölkerung 2015 - Geburtensaldo (je 1000 Einwohner)"                    
## [11] "Zu- (+) bzw. Abnahme (-) der Bevölkerung 2015 - Wanderungssaldo (je 1000 Einwohner)"                  
## [12] "Alter von ... bis ... Jahren am 31.12.2015 - unter 18 (%)"                                            
## [13] "Alter von ... bis ... Jahren am 31.12.2015 - 18-24 (%)"                                               
## [14] "Alter von ... bis ... Jahren am 31.12.2015 - 25-34 (%)"                                               
## [15] "Alter von ... bis ... Jahren am 31.12.2015 - 35-59 (%)"                                               
## [16] "Alter von ... bis ... Jahren am 31.12.2015 - 60-74 (%)"                                               
## [17] "Alter von ... bis ... Jahren am 31.12.2015 - 75 und mehr (%)"                                         
## [18] "Zensus 2011, Bevölkerung nach Migrationshintergrund am 09.05.2011 - ohne Migrationshintergrund (%)"   
## [19] "Zensus 2011, Bevölkerung nach Migrationshintergrund am 09.05.2011 - mit Migrationshintergrund (%)"    
## [20] "Zensus 2011, Bevölkerung nach Religionszugehörigkeit am 09.05.2011 - Römisch-katholische Kirche (%)"  
## [21] "Zensus 2011, Bevölkerung nach Religionszugehörigkeit am 09.05.2011 - Evangelische Kirche (%)"         
## [22] "Zensus 2011, Bevölkerung nach Religionszugehörigkeit am 09.05.2011 - Sonstige, keine, ohne Angabe (%)"
## [23] "Zensus 2011, Wohnungen in Wohngebäuden am 09.05.2011 - Eigentümerquote"                               
## [24] "Bautätigkeit und Wohnungswesen - Fertiggestellte Wohnungen 2014 (je 1000 Einwohner)"                  
## [25] "Bautätigkeit und Wohnungswesen - Bestand an Wohnungen am 31.12.2015 (je 1000 Einwohner)"              
## [26] "Verfügbares Einkommen der privaten Haushalte 2014 (€ je Einwohner)"                                   
## [27] "Bruttoinlandsprodukt 2014 (€ je Einwohner)"                                                           
## [28] "Kraftfahrzeugbestand am 01.01.2016 (je 1000 Einwohner)"                                               
## [29] "Absolventen/Abgänger beruflicher Schulen 2015"                                                        
## [30] "Absolventen/Abgänger allgemeinbildender Schulen 2015 - insgesamt ohne Externe (je 1000 Einwohner)"    
## [31] "Absolventen/Abgänger allgemeinbildender Schulen 2015 - ohne Hauptschulabschluss (%)"                  
## [32] "Absolventen/Abgänger allgemeinbildender Schulen 2015 - mit Hauptschulabschluss (%)"                   
## [33] "Absolventen/Abgänger allgemeinbildender Schulen 2015 - mit mittlerem Schulabschluss (%)"              
## [34] "Absolventen/Abgänger allgemeinbildender Schulen 2015 - mit allgemeiner und Fachhochschulreife (%)"    
## [35] "Kindertagesbetreuung: Betreute Kinder am 01.03.2016 (je 1000 Einwohner)"                              
## [36] "Unternehmensregister 2014 - Unternehmen insgesamt (je 1000 Einwohner)"                                
## [37] "Unternehmensregister 2014 - Handwerksunternehmen (je 1000 Einwohner)"                                 
## [38] "Sozialversicherungspflichtig Beschäftigte am 30.06.2016 - insgesamt (je 1000 Einwohner)"              
## [39] "Sozialversicherungspflichtig Beschäftigte am 30.06.2016 - Land- und Forstwirtschaft, Fischerei (%)"   
## [40] "Sozialversicherungspflichtig Beschäftigte am 30.06.2016 - Produzierendes Gewerbe (%)"                 
## [41] "Sozialversicherungspflichtig Beschäftigte am 30.06.2016 - Handel, Gastgewerbe, Verkehr (%)"           
## [42] "Sozialversicherungspflichtig Beschäftigte am 30.06.2016 - Öffentliche und private Dienstleister (%)"  
## [43] "Sozialversicherungspflichtig Beschäftigte am 30.06.2016 - Übrige Dienstleister und 'ohne Angabe' (%)" 
## [44] "Empfänger(innen) von Leistungen nach SGB II am 31.12.2016 -  insgesamt (je 1000 Einwohner)"           
## [45] "Empfänger(innen) von Leistungen nach SGB II am 31.12.2016 - nicht erwerbsfähige Hilfebedürftige (%)"  
## [46] "Empfänger(innen) von Leistungen nach SGB II am 31.12.2016 - Ausländer (%)"                            
## [47] "Arbeitslosenquote März 2017 - insgesamt"                                                              
## [48] "Arbeitslosenquote März 2017 - Männer"                                                                 
## [49] "Arbeitslosenquote März 2017 - Frauen"                                                                 
## [50] "Arbeitslosenquote März 2017 - 15 bis unter 20 Jahre"                                                  
## [51] "Arbeitslosenquote März 2017 - 55 bis unter 65 Jahre"                                                  
## [52] "Fußnoten"
unemp_de <- unemp_de_raw
names(unemp_de) <- paste0("V",1:ncol(unemp_de))

unemp_de <- unemp_de %>%
  rename(state = V1,
         area_nr = V2,
         area_name = V3,
         for_prop = V8,
         pop_move = V11,
         pop_migr_background = V19,
         income = V26,
         unemp = V47)  # total, as to March 2017

Join the two data files:

wahlkreise_shp %>%
  left_join(unemp_de, by = c("WKR_NR" = "area_nr"))  -> choro_data

Some choropleth maps

Some choropleth maps, such as of

… German income as per administrative area:

choro_data %>%
  ggplot +
  geom_sf(aes(fill = income)) +
  theme_void() +
  scale_fill_viridis()

… unemployment rate with legend suppressed:

choro_data %>%
  ggplot +
  geom_sf(aes(fill = unemp)) +
  theme_void() +
  scale_fill_viridis()  +
  theme(legend.position = "none")

… Proportion of foreigners with legend name set:

choro_data %>%
  ggplot +
  geom_sf(aes(fill = for_prop)) +
  theme_void() +
  scale_fill_viridis() +
  labs(fill = "Foreigners") +
  theme(legend.direction = "horizontal",
        legend.position = "bottom")

Let’s get some statistics out of the data:

choro_data %>% 
  select(area_name, for_prop) %>% 
  top_n(for_prop, n =3) %>% 
  ggplot(aes(x = reorder(area_name, for_prop), y = for_prop, fill = for_prop)) +
  geom_col() +
 # scale_fill_viridis_c() +
  coord_flip()