Rassemblons toutes les données des travaux routiers au Québec

Introduction

Dans ce billet, je vais consolider les différents fichiers au format GPX des travaux routiers publiés par Transports Québec en un seul fichier GeoJSON. On pourra utiliser ensuite ce fichier dans n’importe quel logiciel de système d’information géographique (GIS).

Téléchargement des données de travaux routiers

Je vais d’abord télécharger les données en utilisant le logiciel wget en ligne de commande bash et une boucle pour chacune des régions ayant des fichiers disponibles.

#!/bin/bash
for i in $(echo "for (i=1;i<=13;i++) i*1000"| bc)
do
wget "https://www.quebec511.info/fr/Diffusion/EtatReseau/TravauxGps.aspx?idreg=${i}&p=0&action=gps" \
--output-document="travaux_gps_${i}.gpx"
done

Un des principaux avantages d’avoir codé cette opération de téléchargement sous la forme d’un script en ligne de commande bash est que je peux l’exécuter à volonté pour automatiquement mettre à jour la liste de fichiers. De plus, il serait possible de l’exécuter périodiquement à l’aide d’un outil d’ordonnancement tel que cron.

Préparation de l’environnement de travail en R

Dans R, je charge d’abord les packages requis pour le traitement qui suit.

library(sf)
library(dplyr)
library(stringr)
library(lubridate)
library(ggplot2)
library(ggmap)

Je liste les fichiers GPX contenus dans le répertoire de travail:

gpxfiles <- list.files("~/Nextcloud/gpx/",
                       pattern = "*.gpx")
##  [1] "travaux_gps_1000.gpx"  "travaux_gps_10000.gpx" "travaux_gps_11000.gpx"
##  [4] "travaux_gps_12000.gpx" "travaux_gps_13000.gpx" "travaux_gps_2000.gpx" 
##  [7] "travaux_gps_3000.gpx"  "travaux_gps_4000.gpx"  "travaux_gps_5000.gpx" 
## [10] "travaux_gps_6000.gpx"  "travaux_gps_7000.gpx"  "travaux_gps_8000.gpx" 
## [13] "travaux_gps_9000.gpx"

Extraire les informations depuis les métadonnées avec une fonction

Comme les fichiers GPX ont une capacité limitée à contenir une variété d’attributs associés aux entités géospatiales, les informations telles que les dates de début et de fin des travaux ou le numéro de la route concernée sont concaténées dans le champs name et desc.

Je crée ici une fonction qui permet de lire un fichier GPX. Elle peut extraire les champs ainsi que la géométrie associée. Je vais retourner le tout sous la forme d’un data.frame. C’est la structure par défaut de traitement des données en R.

getwaypoint <- function(gpxfile)
{
  gpxfile %>%
    st_read(layer = "waypoints", quiet=TRUE) %>%
    select(name, desc, geometry) %>%
    as.data.frame()
}

La fonction lapply permet d’appliquer une fonction sur chacun des éléments d’une liste. Elle retourne ensuite une liste de même longueur. C’est l’équivalent de la list comprehension de Python.

Traitement des données

J’applique ici la fonction à la liste des chemins des fichiers créée précédemment.

J’ajoute aussi une clé synthétique à chaque rangée (rowkey) afin de ne pas avoir à effectuer de fusion de tables sur des champs texte complexes (conseil d’ami, ne fusionnez jamais des données sur un champ en texte libre).

J’ajoute la date du jour dans une colonne, afin d’identifier la journée où les données ont été téléchargées. Cette information n’apparaît pas dans le fichier d’origine.

mywaypoints <- lapply(gpxfiles, getwaypoint) %>%
  bind_rows() %>%
  mutate(rowkey = seq_along(name),
         record_date = today())

J’utilise ici une expression régulière afin d’extraire le type de travaux, la date de début et la date de fin depuis le champ name.

name_groups <- mywaypoints$name %>%
  str_match(pattern = "^([A-Za-z]+)\\s+([0-9]{1,2}/[0-9]{1,2}/[0-9]{1,2})\\s+([0-9]{1,2}/[0-9]{1,2}/[0-9]{1,2})$") %>%
  `colnames<-`(c("name", "type", "date_debut", "date_fin")) %>%
  as.data.frame %>%
  mutate(rowkey = mywaypoints$rowkey)

J’effectue un traitement similaire pour le champ desc qui contient le nom de la route, une date de début et de fin associée à la route ainsi que d’autres informations superflues.

desc_groups <- mywaypoints$desc %>%
  str_match(pattern = "^(.*)\\s+([0-9]{1,2}/[0-9]{1,2}/[0-9]{1,2})\\s+([0-9]{1,2}/[0-9]{1,2}/[0-9]{1,2})\\s+") %>%
  `colnames<-`(c("desc", "route", "date_debut_rte", "date_fin_rte")) %>%
  as.data.frame %>%
  mutate(rowkey = mywaypoints$rowkey)

Fusion des attributs

Je fusionne ici les données extraites aux données originales en utilisant la clé synthétique (rowkey) que j’ai générée plus tôt. Je conserve seulement les champs qui ont des informations pertinentes à l’aide d’un select.

mywaypoints2 <- mywaypoints %>%
  inner_join(name_groups, by = "rowkey") %>%
  inner_join(desc_groups, by = "rowkey") %>%
  select(
    record_date,
    type,
    date_debut,
    date_fin,
    route,
    date_debut_rte,
    date_fin_rte,
    geometry
  )

Exporter notre fichier GeoJSON

Pourquoi le GeoJSON ?

Le GeoJSON est un format de données ouvert (il n’appartient pas à une entreprise) et il est très polyvalent. Il permet de stocker des données géospatiales ainsi que des tables d’attributs. Il est lisible par l’humain et est facile à importer dans tous les systèmes d’information géographiques. Ce qui inclus les plus simples comme Leaflet et les plus complets comme ArcGIS.

Comme c’est aussi un fichier JSON, il peut être lu et interprété par tous les navigateurs web modernes.

Allons-y

Je me prépare ici à exporter les données. Comme la fonction utilisée ci-dessous ne permet pas d’écraser un fichier GeoJSON, je supprime ici le fichier s’il existe.

export_geojson_path <- "~/Nextcloud/gpx/all.geojson"
succes.supprimer <- if (file.exists(export_geojson_path)) {
  file.remove(export_geojson_path)
}

J’utilise la fonction st_write pour écrire un fichier GeoJSON aves les données finales.

Visualisation des données de travaux routiers

Enfin, avant de conclure ce billet, profitons-en pour visualiser les données à des fins de validation de qualité.

Note: Ce n’est pas ici que l’on sort nos talents de graphiste, on valide seulement si les données font du sens sur la carte !

mywaypoints2_df <- fortify(mywaypoints2)

Je calcule d’abord l’étendue des données pour télécharger le fond de carte correspondant.

mywaypoints2_bbox <- st_bbox(mywaypoints2_df$geometry) %>% as.list()

Je télécharge ensuite le fond de carte.

mapImage <- get_map(
  c(
    left = mywaypoints2_bbox$xmin,
    bottom = mywaypoints2_bbox$ymin,
    right = mywaypoints2_bbox$xmax,
    top = mywaypoints2_bbox$ymax
  ),
  maptype = "terrain",
  zoom = 7,
  source = "stamen"
)

Enfin, j’affiche les points des travaux routiers sur une carte

plot(st_transform(mywaypoints2_df$geometry, crs = 3857), 
     bgMap = mapImage, 
     pch = 3,
     main="Travaux routiers au Québec",
     axes = TRUE
     )
Carte des travaux routiers au Québec

Conclusion

Dans ce billet, j’ai présenté une méthode avec le langage R pour rassembler des fichiers de points GPX en un seul fichier GeoJSON enrichi d’informations telles que les dates de début et de fin des travaux routiers. J’ai ensuite effectué une validation de données à l’aide d’une visualisation simple.

Je vous souhaite bonne route et évitez les chantiers routiers si possible à l’aide de ces données !


Tu aimerais apprendre à découvrir et maîtriser les données autour de toi pour créer des outils pratiques qui te simplifient la vie ?

Abonnes-toi dès maintenant à ma liste de courriel mensuelle.