La cartographie automatisée de flux n’est pas une chose facile à réaliser, et ce quelque soit le logiciel utilisé.
L’objectif de ce billet est de proposer un exemple de cartographie de flux avec R.
[MAJ] J’ai déplacé les données et ajouté le code sur GitHub. [/MAJ]
Les données utilisées sont des données de migration résidentielles issues de l’Insee et un fond de carte des départements français diffusé par l’IGN. Le tout est à télécharger ici sous forme de RData
.
Cet exemple s’appuie sur le package igraph
dédié à l’analyse et à la représentation de graphs. Les fonctionnalités de représentation de graphs orientés sont mobilisés pour représenter les migrations résidentielles entre les 6 départements les plus attractifs (hors Ile de France) entre 2003 et 2008.
# chargement des packages nécessaires library(igraph) library(maptools) # chargement des données # téléchargeables ici : http://wukan.ums-riate.fr/flow/dep.RData load("dep.RData") # extraction des coordonnées des centroides des departements centres <- cbind(depGeom@data[,"CODE_DEPT"], as.data.frame(coordinates(depGeom))) names(centres)<-c("id","X","Y") # création de la variable d'attractivité des départements : # le nombre d'arrivées attract <- aggregate(depMig$fij, by = list(depMig$dest), sum) names(attract) <- c("id", "nbarrivee") # Sélection flux entre les 6 départements recevant le plus de # migrations résidentielles à l'exeption des département # de l'IDF, de l'étranger (99) et des DOM (97) # liste des départements à exclure listExcl <- c("75", "92", "77", "78", "93", "94", "95", "97", "99") # exclusion de ces départements mig <- depMig[!depMig$dest %in% listExcl & !depMig$orig %in% listExcl,] # liste des départements à sélectionner listDep <- attract[order(attract$nbarrivee[!attract$id %in% listExcl], decreasing = T),][1:6,"id"] # sélection de ces départements mig <- mig[mig$orig %in% listDep & mig$dest %in% listDep, ] # transformation des flux sélectionnés en graph g <- data.frame(mig[,c("orig", "dest")]) g <- as.matrix(g) g <- graph.edgelist(g, directed=TRUE) # création de la liste des noeuds (vertex) vert <- data.frame(id = V(g)$name) # affectation des positions des coordonnées des centroides aux noeuds coords <- centres[match(vert$id, table = centres$id), ] coords <- as.matrix(coords[,2:3]) g$layout <- coords # ajout d'un attribut aux noeuds V(g)$weights <- attract[match(vert$id, table = attract$i), "nbarrivee"] # ajout d'un attribut d'épaisseur aux liens (edge) x <- get.edgelist(g) E(g)$fij <- mig[match(x = paste(x[,1],x[,2],sep="_"), table = paste(mig$orig,mig$dest,sep="_")),"fij"] # affichage du fond de carte plot(depGeom, col="pink") # affichage du graph #png("carte1.png", width = 415, height = 450) par(mar=c(0,0,0,0),oma = c(0,0,0,0) ) plot.igraph(g, add=T, rescale = F, vertex.size = (V(g)$weights)*100, edge.curved = 0.4, edge.width = E(g)$fij/250, edge.color = "red") #dev.off()
Cette première représentation pose un problème : la taille des pointes de flèches est la même pour toutes les flèches, le paramètre edge.arrow.size
n’accepte pas de vecteur en entrée.
Une solution est de faire autant de plots que de flèche et de les superposer (solution proposée ici).
# png("toto.png", width = 415, height = 450) par(mar=c(0,0,0,0),oma = c(0,0,0,0) ) # Affichage de la carte des départements plot(depGeom, col="black", bg = "grey", border = "#ffffff00") # Titre et légende mtext(text = " Migrations résidentielles majeures entre les \n départements les plus attractifs (hors IDF)\n", side = 3,adj=0, cex=1.5, line = -4.5) mtext(text = "Source : Insee, migrations résidentielles 2003-2008 ", side = 1,adj=1,cex=0.8, line = -2) mtext(text = " T. Giraud, 2014",side = 1,adj=0,cex=0.8, line = -2) # ajout des flèches une par une for (e in seq_len(ecount(g))) { graph2 = delete.edges(g, E(g)[(1:ecount(g))[-e]]) plot(graph2, vertex.size = (V(g)$weights)*250, edge.curved = 0.5, edge.width=E(graph2)$fij / 170, # nous limitons la taille des plus grosses flèches à 1.75 edge.arrow.size = if(E(graph2)$fij / 700 >= 1.75){ 1.75 } else { E(graph2)$fij/700 }, edge.color = "red", vertex.label=NA, add=TRUE, rescale = F ) } #dev.off()
Si le résultat est quand même très satisfaisant pour une cartographie automatique de flux, quelques problèmes subsistent :
- La pointe des flèches est moche (surtout pour les grandes flèches et on ne peut pas la changer.
- Le départ et les arrivées de flux ne “visent” pas les centres des cercles.
- L’ajout d’une belle légende concernant à la fois les cercles et les flux n’est vraiment pas évident.
- L’adaptation des tailles de cercles, des épaisseurs de flux et des tailles de pointes de flèches n’est pas gérée.
OpenEdition vous propose de citer ce billet de la manière suivante :
Timothée Giraud (11 décembre 2014). Cartographie de flux avec R. R Géomatique. Consulté le 9 décembre 2024 à l’adresse https://doi.org/10.58079/tp39
Bonjour,
merci beaucoup pour vos travaux partagés,
dans le cadre de mon stage je suis censé travailler sur l’analyse de l’accessibilité aux aménités urbaines,
pour l’instant je cherche une manière qui me permettrait de cartographier ( carte isochrone) la distance à la ressource la plus proche (D) depuis les centroides des communes (O),
Avec sf:: st_distance( x,y) j’ai réussi à avoir une matrice d’adjacence des distances, par la suite j’ai pu calculer la distance minimum pour chaque ligne ( ressource la plus proche pour chaque commune)
je cherche un moyen qui me permettrait de cartographie mes résultats de manière à monter la variation de l’accessibilité ( proximité à la ressource) une carte isochrone je me disais ,
si c’est possible, pouvez-vous m’indiquer, s’il vous plait, quel est ce moyen s’il existe de passer du calcul de distances ( matrice OD ) à la cartographie de celles-ci ?
dans un second temps, j’espère pouvoir le faire sur réseau routier ( accessibilité sur réseau ). Pour cela avez-vous, s’il vous plait, des pistes, des travaux , des méthodes ou même des conseils qui pourront m’aider ?
merci d’avance pour vos réponses
bien cordialement
Bonjour,
Je vous suggère de jeter un oeil au package `osrm`. Il permet de calculer des distances par la route et des isochrones en utilisant le service OSRM.
bonjour,
pourriez vous svp remettre en ligne les fichiers rdata
merci
ps/ merci pour votre article sur les flux!!
Bonjour,
En effet; le lien vers le fichier
dep.RData
n’était pas le bon. Je l’ai corrigé: http://wukan.ums-riate.fr/flow/dep.RDataBonjour,
merci beaucoup pour tous ces travaux partagés.
Plutôt que de créer la couche point à partir de centroides de la couche département, peut-on charger directement une couche polygone puis une couche point (à supposer que nos points ne soient pas des centroides) ?
Est-ce possible de cartographier des flux dont l’origine ou la destination serait toujours la même ?
Merci
On peut charger directement des centroides, si la couche depGeom est une couche points cette instruction fonctionne aussi:
centres <- cbind(depGeom@data[,"CODE_DEPT"], as.data.frame(coordinates(depGeom)))
Le dataframe
depMig
contient la table des origines/destinations, si les origines ou les destination sont toujours les mêmes alors vous cartographierez des flux dont l’origine ou la destination sont toujours les mêmes.Je pensais que l’instruction était différente selon si on chargeait un shape point polygone ou ligne. Mais je viens de découvrir la notion de slot et je comprends que c’est cet élément @ qui permet de voir ce qui les compose et différencie leur géomatrie. Bien évidemment pour les origines destinations…!
Merci beaucoup