Icoon vorm van Nederland

Cartografie OData v4

Let op: Deze handleiding is voor de bètaversie van OData v4

Veel datasets bevatten regionale cijfers. In deze handleiding wordt aan de hand van een voorbeeld over geboortecijfers uitgelegd hoe CBS-data gekoppeld kan worden aan geografische gegevens om een thematische kaart te maken met R of Python. De informatie uit de Snelstartgids wordt bekend verondersteld.

Het CBS publiceert haar geografische kaarten via PDOK (Publieke Dienstverlening Op de Kaart). De dataset "CBS Gebiedsindelingen" bevat de meest gebruikte gebiedsindelingen die het CBS hanteert. Deze geodata is te downloaden in verschillende bestandsformaten zoals Shapefile en GeoJSON, maar het is ook mogelijk om de bestanden geautomatiseerd op te halen met de API. In deze handleiding wordt gebruik gemaakt van de API zodat altijd de meest recente correcties in de kaarten doorgevoerd zijn. Meer informatie over de geo-API is te vinden in de documentatie. Let op: gebiedsindelingen veranderen regelmatig. Kies de juiste geografische informatie bij de data.

De codevoorbeelden kunnen eenvoudig naar het klembord worden gekopieerd door op de knop in het codeblok te klikken. De voorbeelden op deze pagina zijn ook gebundeld te vinden op GitHub.

Keuzemenu programmeertaal:

Voor het werken met geodata wordt in deze handleiding gebruik gemaakt van jsonline, geojsonio en sp. Om verschillende bewerkingen eenvoudiger te maken wordt tidyverse gebruikt, een verzameling van meerdere packages voor het verwerken van data.

library(jsonlite)
library(geojsonio)
library(tidyverse)
library(sp)

get_odata <- function(targetUrl) {
  response <- fromJSON(url(targetUrl))
  data <- response$value
  targetUrl <- response[["@odata.nextLink"]]
  
  while(!is.null(targetUrl)){
    response <- fromJSON(url(targetUrl))
    data <- bind_rows(data,response$value)
    targetUrl <- response[["@odata.nextLink"]]
  }
  return(data)
}

De geodata wordt via de API van het Nationaal Georegister van PDOK gedownload en vervolgens ingelezen met geojson_read.

# De geodata wordt via de API van het Nationaal Georegister van PDOK opgehaald.
# Een overzicht van beschikbare data staat op https://www.pdok.nl/datasets.
geoUrl <- "https://geodata.nationaalgeoregister.nl/cbsgebiedsindelingen/wfs?request=GetFeature&service=WFS&version=2.0.0&typeName=cbs_gemeente_2017_gegeneraliseerd&outputFormat=json"
fileName <- "gemeentegrenzen2017.geojson"
download.file(geoUrl, fileName)
gemeentegrenzen <- geojson_read(fileName, what = "sp")

Om de geboortecijfers te downloaden zoeken we eerst de bijbehorende MeasureCode op:

# Zoek op welke codes bij geboortecijfers horen
tableUrl <- "https://beta.opendata.cbs.nl/OData4/CBS/83765NED"
codes <- get_odata(paste0(tableUrl,"/MeasureCodes"))
codes %>% filter(str_detect(Title,"Geboorte"))

Het is gebruikelijk om in thematische kaarten alleen relatieve aantallen weer te geven zodat regio's van verschillende groottes alsnog vergeleken kunnen worden. De juiste data kan dus gedownload worden met de volgende url:

targetUrl <- paste0(tableUrl,"/Observations?$filter=Measure eq \'M0000173_2\' and startswith(WijkenEnBuurten,\'GM\')")

Om het koppelen mogelijk te maken is het nodig om spaties rond de gemeentecodes te verwijderen en voor leesbaarheid hernoemen we Value naar relatieve_geboorte.

geboorten_per_gemeente <- get_odata(targetUrl) %>% 
    mutate(WijkenEnBuurten = str_trim(WijkenEnBuurten)) %>%
    rename(relatieve_geboorte = Value)

Vervolgens kan de geografische data gekoppeld worden aan het relatieve geboortecijfer.

gemeentegrenzen@data <- gemeentegrenzen@data="" %="">%
  left_join(geboorten_per_gemeente,by=c("statcode"="WijkenEnBuurten"))

g <- fortify(gemeentegrenzen, region = "id")
gemeentegrenzenDF <- merge(g, gemeentegrenzen@data, by = "id")

De gekoppelde data kan nu worden weergegeven met bijvoorbeeld ggplot.

ggplot(data = gemeentegrenzenDF) +
  geom_polygon(aes(x=long, y=lat, group = group, fill = relatieve_geboorte)) +
  coord_equal()+
  ggtitle("Levend geborenen per 1000 inwoners, 2017") +
  theme_void()

Thematische kaart van geboortecijfers in Nederland.

Om de CBS-data op te halen kan het package requests worden gebruikt. Voor het werken met geodata wordt in deze handleiding gebruik gemaakt van geopandas.

import pandas as pd
import geopandas as gpd
import requests

def get_odata(target_url):
    data = pd.DataFrame()
    while target_url:
        r = requests.get(target_url).json()
        data = data.append(pd.DataFrame(r['value']))
        
        if '@odata.nextLink' in r:
            target_url = r['@odata.nextLink']
        else:
            target_url = None
            
    return data

De geodata wordt via de API van het Nationaal Georegister van PDOK gedownload en vervolgens ingelezen met geojson_read.

# De geodata wordt via de API van het Nationaal Georegister van PDOK opgehaald.
# Een overzicht van beschikbare data staat op https://www.pdok.nl/datasets.
geodata_url = "https://geodata.nationaalgeoregister.nl/cbsgebiedsindelingen/wfs?request=GetFeature&service=WFS&version=2.0.0&typeName=cbs_gemeente_2017_gegeneraliseerd&outputFormat=json"
gemeentegrenzen = gpd.read_file(geodata_url)

De naam van de kolom met geboortecijfers kan opgezocht worden in de metadata van de kerncijfers wijken en buurten.

# Zoek op welke codes bij geboortecijfers horen
table_url = "https://beta.opendata.cbs.nl/OData4/CBS/83765NED"
codes = get_odata(table_url + "/MeasureCodes")
geb = codes[codes['Title'].str.contains("Geboorte")]
print(geb[['Title','Unit','Identifier']])

Het is gebruikelijk om in thematische kaarten alleen relatieve aantallen weer te geven zodat regio's van verschillende groottes alsnog vergeleken kunnen worden. De juiste data kan dus gedownload worden met de volgende url:

target_url = table_url + "/Observations?$filter=Measure eq 'M0000173_2' and startswith(WijkenEnBuurten,'GM')"
geboorten_per_gemeente = get_odata(target_url)

Voor leesbaarheid wordt Value hernoemd naar relatieve_geboorte.

geboorten_per_gemeente = geboorten_per_gemeente.rename({'Value':'relatieve_geboorte'}, axis='columns')

Vervolgens kan de geografische data gekoppeld worden aan het relatieve geboortecijfer.

gemeentegrenzen = pd.merge(gemeentegrenzen, geboorten_per_gemeente, left_on = "GM_CODE", right_on = "WijkenEnBuurten")

De functie plot uit geopandas geeft nu een simpele thematische kaart:

p = gemeentegrenzen.plot(column='relatieve_geboorte', figsize = (10,8))
p.set_title("Levend geborenen per 1000 inwoners, 2017")

Thematische kaart van geboortecijfers in Nederland.