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()