Premiers pas en cartographie avec R
La semaine dernière, j’ai fait mes premiers pas dans le domaine de la cartographie sous R. En réalité, c’était aussi un peu mes premiers pas en cartographie tout court, parce que mes connaissances étaient très basiques (niveau collège grand max), et qu’elles dataient de…..loin !
J’ai donc dû reprendre pas mal de choses. Et puis coté R, je me suis rendu compte qu’il existe plein de packages qui touchent aux objets spatiaux (sf, raster, sp, etc…) avec parfois des formats d’objet différents (un peu comme data frame et tibble) et plein de packages qui s’intéressent à la cartographie (ggmap, tmap, leaflet, cartography..etc). Sans compter qu’il existe aussi des formats de fichiers SIG (fichier de codage de l’information géographique) différents (shapefile, TIFF, ect…). J’ai vraiment eu du mal à m’y retrouver. Et même s’il y a encore plein de zones d’ombre, j’ai eu envie de partager mes avancées, en espérant aider au moins un peu, d’autres débutants.
Pour ceux qui maîtrisent le sujet, merci par avance d’être indulgent ! N’hésitez pas à contribuer à l’amélioration de cet article en laissant un commentaire !
Mon but
Si je me suis lancée dans la cartographie sous R, c’est parce que j’avais besoin de créer une carte avec les pays de l’Europe de l’Ouest, sur laquelle je pourrais afficher les valeurs de variables relatives à ce pays . Par exemple des statistiques de foot récupérées ici :
## country score
## 1 Austria 769
## 2 Belgium 1465
## 3 Cyprus 495
## 4 Denmark 419
## 5 Finland 18
## 6 France 3300
## 7 Germany 4748
## 8 Greece 1020
## 9 Iceland 0
## 10 Ireland 32
## 11 Italy 4775
## 12 Malta 0
## 13 Netherlands 1692
## 14 Norway 219
## 15 Portugal 3245
## 16 Spain 8457
## 17 Sweden 246
## 18 Switzerland 1023
## 19 United Kingdom 6952
Quelques notions de base de cartographie qui m'ont été utiles:
- La Terre est une sphère, autrement dit un objet en 3 dimensions.
- Sur cette sphère, un lieu est défini par des coordonnées géographiques qui sont la latitude et la longitude ; ce sont des mesures angulaires. Si vous avez besoin d’une piqûre de rappel, je vous
conseille cette vidéo. - Ces angles peuvent être exprimés sous différents formats : en degrés sexa-décimaux: 43°49′43″ ou en degrés décimaux: 43°49.7298′Nord.
- Une carte est un objet en deux dimensions.
- Représenter une sphère sur une carte s’appelle une projection, et il en existe de trois grands types (conique, cylindrique et azimutal). Pour plus de détails, je vous conseille cette vidéo.
- Sur une carte, les lieux sont aussi définis par des coordonnées, mais dans un environnement cartésien cette fois, c’est-à-dire en X et Y.
- Dans cet environnement cartésien, la latitude correspond à l’axe des Y et la longitude à l’axe de X.
- Il existe différentes unités pour exprimer la latitude et la longitude d’un lieux sur une carte :
- en degrés décimaux : par exemple, 43.8333° de latitude et 5.78306° de longitude dans ce cas là, on est dans un référentiel appelé WGS84 (utilisé par les GPS).
- en mètre, dans ce cas là, on est en projection Lambert93, par exemple X : 923825 Y : 6307755.
Mon point de départ concernant R pour la cartographie
- L’utilisation du package ggmap n’est pas envisageable car il faut avoir un compte google map qui nécessite d’entrer une carte bancaire : je n’ai pas envie !
- Le package leaflet permet d’avoir un fond de carte provenant d’Open Street Map : j’ai déjà essayé vite fait, il y a deux ou trois ans.
- La représentation d’un pays sur un fond de carte fait appel à la notion de polygons.
- Il existe plusieurs formats d’objets spatiaux et ils ont l’air assez compliqués !
- Il existe plein de package pour faire de la cartographie !
- Sébastien Rochette a écrit un article d’initiation à la cartographie, qui me sera sans doute utile.
Mon cheminement
Le fond de la carte avec leaflet
Pour obtenir ce fond de carte, je me suis appuyé sur la vignette de « leaflet » qui est vraiment très bien faite.
J’ai utilisé la fonction `fitBounds()` pour limiter le fond de carte. J’ai trouvé cette fonction dans l’onglet AdditionalFeatures. Les arguments à fournir sont long1, lat1, lng2, lat2, tels que définis dans la page d’aide :
C’est-à-dire les longitudes et les latitudes min et max de la fenêtre qu’on souhaite afficher.
Pour les déterminer :
- je suis allée sur Open Street Map
- je me suis positionné sur deux pays extrêmes : l’Islande et la Grèce, et j’ai recueilli leur coordonnées ( Island : 65, -20, Grèce :40,20).
library(leaflet)
leaflet() %>%
fitBounds(-20,65,20,40) %>%
addTiles()
C’était pas trop mal, mais je voulais les noms des pays en anglais ! J’ai donc essayé plusieurs fonds de carte avec la fonction `addProviderTiles()`(trouvé dans l’onglet BaseMap du tuto leaflet).
L’option `CartoDB.Positron` me convenait assez, même si j’aurais préféré voir les mers et océans en bleu, plutôt qu’en gris !
leaflet() %>%
fitBounds(-20,65,22,39) %>%
addProviderTiles(providers$CartoDB.Positron)
Pour vous amuser, vous pouvez essayer :
- `addProviderTiles(providers$Stamen.Toner)`
- `addProviderTiles(providers$Esri.NatGeoWorldMap)`
- `addProviderTiles(« Stamen.Watercolor »)`
- `addProviderTiles(« Stamen.TonerHybrid »)`
Il y en a d’autres de disponibles, vous trouverez une liste ici, certains nécessitent une inscription au préalable (pas testé !).
Ajouter un contour sur les pays
C’est là, que l’affaire s’est corsée ! Pour ajouter des contours sur une carte leaflet, il faut des données de contour ! Et ces données il faut aller les chercher dans un fichier de format shapefile, qu’il faut lui-même aller chercher quelle que part sur internet ! Ça n’a l’air de rien, mais comprendre ça c’est déjà une victoire ! Merci Sandrine Roux !
A la recherche d'un fichier shapefile
A cette étape, je me suis dit que je trouverais peut être ça sur le site d’Eurostats , puisque je l’avais déjà un peu exploré pour cet article « A la découverte des statistiques européennes d’Eurostat« et que j’avais vu des cartes. Bonne pioche !
Comme je ne savais pas trop quelle échelle choisir, j’ai pris celle du milieu !
Le ficher zip comportait de nombreux autres dossiers compressés:
J’ai choisi d’utiliser le dossier « CNTR_RG_10M_2016_4326.shp » car en lisant le fichier « release_notes.txt », j’ai vu que :
- RG correspond aux « regions (multipolygons) » (je savais que j’avais besoin de polygons )
- 4326 correspond au référentiel WGS84, avec des coordonnées en degrés décimal, et que ça me semblait « courant ».
Contenu du fichier shapefile
Au final j’ai décompressé le fichier « CNTR_RG_10M_2016_4326.shp » et j’ai placé les 5 fichiers qu’il contient dans un dossier « data_carto » lui même à la racine de mon projet R, comme ça :
Pour plus de détail sur ces différents fichiers, vous pouvez consulter cette page.
L'importation dans R
En lisant cette page, j’ai vu que le fichier .DBF pouvait être ouvert avec Excel. En le faisant (d’abord ouvrir Excel, puis aller chercher le fichier), j’ai vu que les données concernaient tous les pays du monde et pas que l’Europe. J’allais donc être obligé de sélectionner les pays de l’Europe de l’Ouest qui m’intéressaient.
Je me suis alors souvenu d’un article de blog de Sébastien Rochette (Initiation à la cartographie avec sf et compagnie) dans lequel il sélectionnait des départements à partir des données de tous les départements de la France :
Cet article m’a été d’une grande aide, car j’ai appris qu’en important mes données shapefile avec la fonction `st_read()` du package `sf` elles allaient devenir une table de données classiques et que je pourrais utiliser les fonctions du `tidyverse` pour filtrer les lignes des pays qui m’intéressaient !
library(tidyverse)
library(sf)
# importation des données shapefile
Monde <- st_read(here::here("data_carto","CNTR_RG_10M_2016_4326.shp"), quiet=TRUE)
head(Monde)
Simple feature collection with 6 features and 5 fields
geometry type: MULTIPOLYGON
dimension: XY
bbox: xmin: -63.1112 ymin: 16.99742 xmax: 74.88986 ymax: 42.65309
geographic CRS: WGS 84
CNTR_ID
1 AD
2 AE
3 AF
4 AG
5 AI
6 AL
CNTR_NAME
1 Andorra
2 <U+0627><U+0644><U+0625><U+0645><U+0627><U+0631><U+0627><U+062A> <U+0627><U+0644><U+0639><U+0631><U+0628><U+064A><U+0629> <U+0627><U+0644><U+0645><U+062A><U+062D><U+062F><U+0629>
3 <U+0627><U+0641><U+063A><U+0627><U+0646><U+0633><U+062A><U+0627><U+0646>-<U+0627><U+0641><U+063A><U+0627><U+0646><U+0633><U+062A><U+0627><U+0646>
4 Antigua and Barbuda
5 Anguilla
6 Shqipëria
NAME_ENGL ISO3_CODE FID
1 Andorra AND AD
2 United Arab Emirates ARE AE
3 Afghanistan AFG AF
4 Antigua and Barbuda ATG AG
5 Anguilla AIA AI
6 Albania ALB AL
geometry
1 MULTIPOLYGON (((1.7258 42.5...
2 MULTIPOLYGON (((56.26584 25...
3 MULTIPOLYGON (((74.88986 37...
4 MULTIPOLYGON (((-61.65852 1...
5 MULTIPOLYGON (((-63.1112 18...
6 MULTIPOLYGON (((20.0763 42....
Sélection des pays d'intérêt
Pour cela, j’ai récupéré la liste des pays qui m’intéressaient dans le fichier data_foot, et j’ai filtré les lignes correspondante dans le fichier « Monde »,(variable NAME_ENGL) en utilisant la fonction filter()
de dplyr
:
# pays d'intérêt
my_countries<-data_foot$country
# selection des données shapefile pour les pays d'interet
Europe_Ouest <- Monde %>%
dplyr::filter(NAME_ENGL %in% my_countries)
Ajout sur la carte leaflet
Pour cela, j’ai utilisé la fonction addPolygons()
:
leaflet() %>%
fitBounds(-20,65,20,40) %>%
addProviderTiles(providers$CartoDB.Positron) %>%
addPolygons(data=Europe_Ouest,weight = 2, color="orange",fillOpacity=0.35
C’était déjà pas mal, mais je me suis dit que je pourrais renforcer le blanc sur les pays qui ne m’intéressent pas. Pour cela, j’ai filtré comme précédemment leurs lignes à partir du fichier Monde et j’ai ajouté l’option `fillOpacity=0.65` dans une seconde fonction `addPolygons()` que j’ai
placé en premier pour que les polygons orange des pays d’intérêt recouvrent le blanc :
Autre <- Monde %>%
dplyr::filter(! NAME_ENGL %in% my_countries )
leaflet() %>%
fitBounds(-20,65,20,40) %>%
addProviderTiles(providers$CartoDB.Positron) %>%
addPolygons(data=Autre,weight = 2, color="white",fillOpacity=0.65) %>%
addPolygons(data=Europe_Ouest,weight = 2, color="orange",fillOpacity=0.35)
Ajout de valeurs sur la carte
Collecte des coordonnées gps du centre des pays
Pour ajouter mes scores de foot sur la carte, il a fallu que je récupère les coordonnées des pays. Pour cela, j’ai utilisé les packages `rworldmap` et `rgeos` qui permettent d’obtenir les coordonnées des centroides de tous les pays du monde :
library(rworldmap)
library(rgeos)
# get world map
wmap <- getMap(resolution="high")
# get centroids
centroids <- gCentroid(wmap, byid=TRUE)
# get a data.frame with centroids
centroid_df <- as.data.frame(centroids)
# affichage des premières lignes
head(centroid_df)
## x y
## Aruba -69.98267 12.52089
## Afghanistan 66.00473 33.83523
## Angola 17.53736 -12.29336
## Anguilla -63.06498 18.22397
## Albania 20.04983 41.14245
## Aland 19.95325 60.21490
J’ai ensuite modifié les noms « x » et « y » en « long » et « lat ».
centroid_df <- centroid_df %>%
mutate(country=rownames(.)) %>%
rename(lat=y, long=x)
head(centroid_df)
## long lat country
## 1 -69.98267 12.52089 Aruba
## 2 66.00473 33.83523 Afghanistan
## 3 17.53736 -12.29336 Angola
## 4 -63.06498 18.22397 Anguilla
## 5 20.04983 41.14245 Albania
## 6 19.95325 60.21490 Aland
Si vous avez besoin de collecter d’autres types de coordonnées gps (par exemple celles d’une gare), je vous conseille de consulter l’article de Marie Vaugoyeau : ‘Visualiser des zones géographiques autour de points d’intérêt avec leaflet » . A la fin de celui-ci, Marie donne une astuce pour le faire avec Open Cage Data !
Ajout des coordonnées aux données
J’ai ensuite sélectionné uniquement les pays de l’Europe de l’Ouest qui m’intéressaient :
centroid_europe <- centroid_df %>%
filter(country %in% my_countries)
Et j’ai ajouté leur coordonnées dans la table des données de foot, en utilisant la fonction left_join()
. Pour plus d’infos sur les jointures, vous pouvez consulter cet article , et celui là.
data_foot<- left_join(data_foot, centroid_europe)
head(data_foot)
## country score long lat
## 1 Austria 769 14.126478 47.58550
## 2 Belgium 1465 4.640646 50.63981
## 3 Cyprus 495 33.006004 34.91667
## 4 Denmark 419 10.027994 55.98126
## 5 Finland 18 26.274670 64.49885
## 6 France 3300 2.536185 46.18701
Gestion de leaflet
Pour ajouter les scores sur la carte, j’ai utilisé la fonction addLabelOnlyMarkers()
leaflet() %>%
fitBounds(-20,65,20,40) %>%
addProviderTiles(providers$CartoDB.Positron) %>%
addPolygons(data=Autre,weight = 2, color="white",fillOpacity=0.65) %>%
addPolygons(data=Europe_Ouest,weight = 2, color="orange",fillOpacity=0.35) %>%
addLabelOnlyMarkers(data=data_foot,
label=~as.character(score),
labelOptions = labelOptions(noHide = T, direction = 'center', textOnly = T,textsize="13px"))
Là, j’ai trouvé que ça manquait un peu de visibilité, et je me suis dit que ça serait mieux avec des cercles de couleurs qui seraient d’autant plus gros que la valeur du score est importante. Pour ajouter cela, l’article « Les bases de la cartographie dynamique avec R Leaflet » d’Aline Deschamps m’a été très utile. J’ai alors utilisé la fonction`addCircle()`, et j’ai un peu tâtonné pour régler la dimension des rayons des cercles.
leaflet() %>%
fitBounds(-20,65,20,40) %>%
addProviderTiles(providers$CartoDB.Positron) %>%
addPolygons(data=Autre,weight = 2, color="white",fillOpacity=0.65) %>%
addPolygons(data=Europe_Ouest,weight = 2, color="orange",fillOpacity=0.35) %>%
addLabelOnlyMarkers(data=data_foot,
label=~as.character(score),
labelOptions = labelOptions(noHide = T, direction = 'center', textOnly = T,textsize="12px")) %>%
addCircleMarkers(data=data_foot, radius=~sqrt(score)/4,weight = 1, color = "#a500a5", fillOpacity = 0.5)
Le rendu final, me convient assez. Néanmoins, j’aurais bien voulu avoir les mers et océans en bleu plutôt qu’en gris, j’ai essayé plein de chose et je n’ai pas réussi. Donc si vous savez comment faire, dites le moi en commentaire !
Si cet article vous a plu, ou vous a été utile, et si vous le souhaitez, vous pouvez soutenir ce blog en faisant un don sur sa page Tipeee 🙏
Bonjour Claire,
Merci pour ce nouvel article.
Je me permet de signaler en complément le package R adegraphics : https://cran.r-project.org/web/packages/adegraphics/index.html. Il permet aussi de faire de très jolies cartes.
Sandrine
Merci encore Claire pour cet article qui vient renforcer encore nos connaissances.
Merci Claire pour cet article. je me suis essayé, sauf que je me suis heurté à la fonction « st_read » qui n’a pas fonctionné chez moi. Donc je n’ai pas pu paramétrer à ma convenance. Peut-on contourner le problème?
Avez-vous une idée de l’écriture des opérateurs de la physique (divergence, rotationel, gradient…) en langage r ?
merci encore pour tout.
Bonjour Claire
Merci pour ce tutoriel ! Je suis vraiment un débutant sur R et cet article tombe bien, car j’aimerai faire une carte. J’espère y arriver
Merci bcp
Bonjour Claire,
Merci beaucoup pour ce tutoriel, très clair.
Je suis étudiante en cartographie et cela m’a permis de me remettre
en tête des éléments abordés trop rapidement en cours.
Je rencontre cependant un problème que vous ne semblez pas avoir sur vos captures d’écran. Lors de l’affichage des Labels, celui de la France
est attiré vers le Sud, au niveau de l’Espagne ; je crois comprendre que cela vient du calcul du centroïde , qui prend en compte les outre-mer et donc qui se décale forcément.
Avez vous rencontré cette difficulté ?
Bien cordialement
Merci beaucoup pour ce tuto !
Bonsoir,
Je rencontre un problème à l’étape ajout sur la carte leaflet : Don’t know how to get path data from object of class data.frame.
Je pense que j’ai loupé l’étape importation dans R du fichier shp. En fait j’ai ouvert comme vous disiez le fichier dans Excel et je l’ai enregistré avec le nom Monde. Ensuite je l’ai enregistré dans R avec le code suivant:
Monde<-read.csv2("Monde.csv",h=T,sep=";")
Je vous remercie par avance pour votre aide.
Bien cordialement
Bonjour,
votre commentaire m’a permis de me rendre compte que les lignes de code de l’importation étaient passées à la trappe…c’est rectifié !
Merci
Bonne continuation
Bonjour Claire,
Tout d’abord merci Claire pour cet article.
Je suis étudiante en statistique et j’essaye de construire ma première carte avec R.
Je me trouve face à une problématique, où j’ai des coordonnées géographiques en degrés qui ressemblent à ceci : 48°08’57 »78.
Y’a t-il un moyen de faire une carte avec ces coordonnées sans passer par la conversion en décimaux ?
En vous remerciant par avance.
Bonjour,
je ne sais pas bien je me perds tout le temps dans ces conversions….
Bon courage, et n’hésitez pas à partager votre solution avec un nouveau commentaire.
Bonjour,
Avec le package sf, il y a une fonction qui s’appelle st_centroid(objet sf) qui permet de calculer directement le centroide d’une géométrie. Quant aux labels, on peut les insérer directement dans les addCircleMarkers. Je ne sais plus par contre si il y a encore la possibilité de ne pas cacher les labels comme vous l’avez fait avec l’argument noHide = TRUE. Cela permettrait d’économiser quelques lignes
Bien cordialement
Bonjour Yoann,
merci pour votre commentaire.
Je connais vraiment mal ce package alors c’est vraiment utile de partager ces informations.
Bien à vous