Oefenen met R en FME: over fietsnetwerken en fietsknooppunten. Deel 2

In deel 1 van deze serie (van 2) werd een aantal vragen geformuleerd, werden de relevante bronnen verzameld en de data voorbewerkt. In dit deel gaan we naar de output via een tweetrapsraket.Genereer de output

1. De output bestaat uit een tweetal CSV bestanden met getallen over fietsknooppunten, fietsknooppuntnetwerken en horeca langs de weg. De CSV bestanden zijn met een FME workflow aangemaakt.

2. De gegenereerde getallen uit het CSV bestand worden met een achtergrondkaart gecombineerd tot een grafische weergave, een choropleet. Dat is in R gedaan.

Fietsknooppunten en fietsknoopuntennetwerken

De FME workflow voor het genereren van de data van de fietsknooppunten en -netwerken wordt hieronder weergegeven.

FME

De middelste reader verwijst naar ofwel de ‘gewone’ provinciekaart, ofwel naar de ‘provinciekaart met gaten’, dus zonder de grote steden.

De writer verwijst ook naar ofwel de ‘gewone’ aantallen, ofwel de ‘aantallen op basis van de kaart met gaten’.

In allebei de gevallen doorlopen ze dezelfde workflow:

  • Van de provincies wordt de oppervlakte weggeschreven naar een attribuut.
  • Voor alle readers wordt dezelfde projectie ingezet
  • Twee Samplers werden tijdens debuggen gebruikt om de doorlooptijd te beperken
  • Dan wordt middels een PointonAreaOverlayer het aantal fietsknooppunten per provincie bepaald en middels een LineonAreaOverlayer en een LengthCalculator het aantal (kilo)meters per provincie
  • De gebieden worden weer tot 12 provincies geaggregeerd en samengevoegd via een Attributemerger
  • Na nog wat – o.a. dichtheids – berekeningen in een Attributemanager, worden de aantallen weggeschreven naar een CSV file

De 2 resulterende CSV bestanden (een op basis van een gewone kaart en de andere op basis van de kaart zonder grote steden) worden in R gecombineerd met een achtergrondkaart. Het R script is als volgt

library(ggplot2)
library(maptools)
library(rgeos)
library(Cairo)
library(ggmap)
library(scales)
library(RColorBrewer)

multiplot <- function(..., plotlist = NULL, cols) {
  require(grid)
  
  # Make a list from the ... arguments and plotlist
  plots <- c(list(...), plotlist)
  
  numPlots = length(plots)
  
  # Make the panel
  plotCols = cols                          # Number of columns of plots
  plotRows = ceiling(numPlots / plotCols) # Number of rows needed, calculated from # of cols
  
  # Set up the page
  grid.newpage()
  pushViewport(viewport(layout = grid.layout(plotRows, plotCols)))
  vplayout <- function(x, y)
    viewport(layout.pos.row = x, layout.pos.col = y)
  
  # Make each plot, in the correct location
  for (i in 1:numPlots) {
    curRow = ceiling(i / plotCols)
    curCol = (i - 1) %% plotCols + 1
    print(plots[[i]], vp = vplayout(curRow, curCol))
  }
  
}

genereatechart <- function(ffinal.plot,ppalette, ccnames, ccolumn, aaFPK, legendname, koptitle, ttrans) {
  
  ggplot() +
    
    geom_polygon(
      data = ffinal.plot,
      aes(
        x = long,
        y = lat,
        group = group,
        fill = ccolumn
      ),
      size = 0
    ) +
    scale_fill_distiller(
      name = legendname,
      palette = ppalette,
      breaks = pretty_breaks(n = 7),
      trans = ttrans
    ) +
    theme(
      legend.position = c(0.1, 0.8),
      legend.key.width = unit(1, \"cm\"),
      legend.key.height = unit(1, \"cm\"),
      axis.line = element_blank(),
      axis.text.x = element_blank(),
      axis.text.y = element_blank(),
      axis.ticks = element_blank(),
      axis.title.x = element_blank(),
      axis.title.y = element_blank(),
      panel.background = element_blank(),
      plot.background = element_rect(fill = \"lightgrey\"),
      panel.grid.major = element_blank(),
      panel.grid.minor = element_blank(),
      panel.border = element_blank(),
      plot.title = element_text(size=11, lineheight=.8, face=\"bold\")
    ) +
    geom_text(data=ccnames, aes(long, lat, label = aaFPK,
                           map_id =NULL), size=4) +
    ggtitle(koptitle)
}

# Samenstellen data.frames
map_provincies <-
  readShapePoly(
    \"D:/OneDrive - Travelingo/GIS/Reg_SourcProj/Nederland/Projecten/My FME Workspaces/Provincies_Oppervlakte/Provincie_Oppervlakte.shp\"
  )
map_provincies.fort <- fortify(map_provincies, region = \"Provincie\")
FKPLdata <-
  read.csv2(
    \"D:/OneDrive - Travelingo/GIS/Reg_SourcProj/Nederland/Projecten/My FME Workspaces/Provincies_Oppervlakte/FKPLen FKP_data_ex_BB.csv\",
    head = TRUE
  )
map_provincies_FKPLdata <-
  merge(map_provincies.fort,
        FKPLdata,
        by = \"id\",
        all.x = TRUE)
final.plot <-
  map_provincies_FKPLdata[order(map_provincies_FKPLdata$order), ]


#1e plot: aantal fietsknooppunten
#Data labels aanmaken
cnames1 <-aggregate(cbind(long, lat, AantalFKP) ~ id, data = final.plot, FUN = function(x) mean(range(x)))
#Map genereren
p1 <- genereatechart(final.plot, \"YlGn\", cnames1, final.plot$AantalFKP, cnames1$AantalFKP, \"Aantal\", \"Aantal fietsknooppunten\", \"reverse\")

#2e plot: aantal fietsknooppunten
cnames2 <-aggregate(cbind(long, lat, KmFKPL) ~ id, data = final.plot, FUN = function(x) mean(range(x)))
p2 <- genereatechart(final.plot, \"Oranges\", cnames2, final.plot$KmFKPL, cnames2$KmFKPL, \"Aantal\", \"Kilometers aan \\nfietsknooppuntennetwerk\", \"reverse\")

#3e plot: aantal fietsknooppunten
cnames3 <-aggregate(cbind(long, lat, FKPDichtheid) ~ id, data = final.plot, FUN = function(x) mean(range(x)))
p3 <- genereatechart(final.plot, \"YlGn\", cnames3, final.plot$FKPDichtheid/100, cnames3$FKPDichtheid/100, \"Aantal\", \"Fietsknooppunten \\nper km2\", \"reverse\")

#4e plot: aantal fietsknooppunten
cnames4 <-aggregate(cbind(long, lat, FKPLDichtheid) ~ id, data = final.plot, FUN = function(x) mean(range(x)))
p4 <- genereatechart(final.plot, \"Oranges\", cnames4, final.plot$FKPLDichtheid, cnames4$FKPLDichtheid, \"Aantal\", \"Meters fietsknoop- \\npuntennetwerk per km2\", \"reverse\")


multiplot(p1,p2, p3, p4, cols = 2)

De grafieken zie je hieronder. Als het goed is spreken ze voor zich. Zo niet, dan hoor ik het graag.

4 grafieken met de ‘gewone’ provincieskaart

Dan – hieronder – 4 grafieken met dezelfde data maar nu gerelateerd aan de provincieskaart zonder grote steden

Horeca

Dan de horeca-grafieken, volgens dezelfde opzet, met een iets andere workflow. Zie hieronder

  • De middelste reader is weer de ‘gewone’ of de ‘gatenkaart’.
  • De eerste en derde readers zijn aangemaakt middels een connectie met een lokale postgis-database. Daar zijn twee views aangemaakt: een met punten, de ander met ‘vlakken’ met restaurants gefilterd uit de algemene OSM tabellen d.m.v. een spatiale functie van postgis: St_DWithin
CREATE OR REPLACE VIEW osm_point_restaurants_fkpl AS 
 SELECT distinct r.osm_id, r.name, r.way, r.tourism, r.amenity
   FROM planet_osm_point r
     JOIN fietsknooppuntenlijnen f ON st_dwithin(r.way, f.way, 25::double precision)
  WHERE lower(r.tourism) ~~ '% restaurant%'::text OR r.amenity ~~ '%restaurant%'::text OR r.amenity = 'restaurant'::text OR r.amenity ~~ '%cafe%'::text;
  • Er is nog een tweede, vrijwel identiek script maar dan met restaurants als vlakken (polygonen)
  • De laatste reader haalt een csv file op met data die we willen gebruiken in de resultaten CSV file.
  • Verder lijkt de FME workflow erg op die zoals gebruikt bij de fietsknooppunten en fietsknooppuntennetwerken.

P.S. De horecagetallen die uit de workflows komen, zijn gecheckt in QGis.

De afbeelding hieronder laat een stuk van Noord-Holland zien bij Amsterdam. De fietsknooppuntnetwerken zijn zichtbaar, evenals de aan de netwerken gelegen restaurants (rode of paarse punten). Merk ook op dat de provincie Noord-Holland is weergegeven zonder grote steden. In QGis heb ik de restaurants geteld die vallen binnen een normale provincie en de ‘gatenkaas’ versie, zoals in de afbeelding zichtbaar. Voor de Points gebruik je dan de plugin Vector – Analysis Tools – Points in polygon, voor de Polygons heb ik de Clip-functie van de Processing Toolbox gebruikt.

De resulterende csv bestanden worden via een R script – dat alleen in parameters anders is dan het eerder vermelde R script voor de fietsknooppunten – in 2 x 2 grafieken weergegeven.

Onderstaande twee grafieken zijn aangemaakt met de gewone provincieskaart

Laatste twee zijn aangemaakt op basis van data gerelateerd aan de provincieskaart zonder grote steden

Conclusies

Het was voor mij vooral een kennismaking met R en verdere verdieping van FME, maar zijn er nog conclusies te trekken uit deze cijfers?

Enkele kanttekeningen.

  • Data van de fietsknooppunten en horeca zijn afkomstig uit Openstreetmap. De data hiervan heet heel betrouwbaar te zijn, maar kunnen we verder niet controleren.
  • De afstand van cafe’s en/of restarants van 25 m sluit horeca op 26 meter al uit. Op 27 meter ook, etc.

Maar dan nog: Gelderland scoort als fietsprovincie goed, zowel in absolute aantallen als gemiddeld per km2.  Zuid-Holland en Zeeland lijken relatief de meest beknooppunte provincies van ons land, Drenthe, Friesland en Groningen staan onderaan.

Als het gaat om horeca langs de fietsknooppuntennetwerken stomen Zuid-Limburg en Noord-Brabant op naar de voorste rijen. Een uitvloeisel van de Bourgondische levensstijl in de zuidelijke provincies?