GÉO-VISUALISATION AVEC R

Action nationale de formation
MATE SHS

Cette formation de 3 heures 30 porte sur la visualisation de données géographiques sous R. Y sont abordées les traitements SIG de base, la cartographie thématique (cartes en figurés proportionnels, cartes choroplèthes, cartes de typologie, etc) et des cartes reposant sur des techniques plus avancées comme les cartes sur grille ou les cartes de discontinuités.

Sont ici principalement utilisés les packages sf (manipulation de données spatiales) et cartography (cartographie thématique). Chaque exemple propose une chaîne de traitements depuis le chargement des données, leur mise en forme, jusqu’à la mobilisation de méthodes adaptées permettant de répondre à des questions spatiales.

Les exemples proposés sont réalisés à différentes échelles, du local (région Occitanie) au Monde, en passant par l’Europe.

Pourquoi faire de la cartographie avec R ?

“La science est infaillible, mais les savants se trompent toujours.” (Anatole France, 1889). Ce principe peut également être appliqué à la cartographie. En effet, toute carte est issue d’un processus complexe de choix, de selections, d’opérations statistiques ou géomatiques. Certains auteurs énoncent que les cartes sont subjectives (Brunet). D’autres auteurs disent carrément que les cartes mentent (Monmonnier). Quoi qu’il en soit, toute carte résulte de l’acte créateur des choix de son auteur. Lorsque l’on se situe dans une démarche scientifique, ces choix doivent être traçables, partageables et soumis à la discussion scientifique (ce qui est difficilement faisable quand ces cartes sont réalisées dans un environnement “clic-bouton”).

La réalisation des cartes dans le langage R permet de tracer toutes les opérations nécessaires à une réalisation cartographique de qualité. Réaliser des cartes dans ce langage unique permet, en diffusant le code source en même temps que les cartes, de jouer “cartes sur table”. Cela permet de détailler les choix qui ont été faits et s’exposer à la controverse scientifique. Cela permet aussi de travailler à plusieurs sur une carte, en associant des compétences complémentaires (sémiologie graphique, statistique, géomatique, etc.) et de faciliter la mise à jour de documents déjà rélisés (en rééxecutant un code préalablement réalisé, par exemple).

Au final, l’utilisation de R nécessite un effort non négligeable pour ceux qui ne sont pas habitués à l’univers de la programmation informatique. Mais définitivement, l’investissement n’a que des avantages.

Packages & données

Environnement de travail

Pour exécuter les programmes proposés par la formation, installez / mettez à jour R (version 3.4.4 minimum), R Studio. Lancez ensuite R studio et installez les packages au moyen des commandes suivantes (prévoir au moins 10 minutes).

Les packages

Installation des packages utilisés pendant la formation. Ouvrez R-Studio et tapez :

install.packages("sf")
install.packages("cartography")
install.packages("cartogram")
install.packages("readxl")
install.packages("countrycode")

Optionnel

install.packages("rmapshaper")
install.packages("osmdata")
install.packages("reshape2")
install.packages("eurostat")
install.packages("rnaturalearth")

Version des packages utilisés dans ce document

## [1] "sf (version 0.6.3), cartography (version 2.1.2), countrycode (version 1.0.0), readxl (version 1.1.0), rnaturalearth (version 0.1.0), cartogram (version 0.1.0), reshape2 (version 1.4.3), eurostat (version 3.2.9), rmapshaper (version 0.4.0), osmdata (version 0.0.7.1)"

Packages dédiés à visualisation de données géographiques

  • Le package cartography permet de créer et intégrer des cartes thématiques dans sa chaîne de traitements en R. Il permet des représentations cartographiques tels que les cartes en symboles proportionnels, des cartes choroplèthes, des typologies, des cartes de flux ou des cartes de discontinuités. Il offre également des fonctions qui permettent d’améliorer la réalisation de la carte, comme des palettes de couleur, des éléments d’habillage (échelle, flèche du nord, titre, légende…), d’y rattacher des labels ou d’accéder à des APIs cartographiques.
  • Le package cartogram comme son nom l’indique permet de construire des cartogrames continus ou discontinus.

Packages dédiés à la manipulation de données (spatiales ou non)

  • Le package sf est un package qui permet d’importer, gérer et transformer des données géographiques (gestion des projections, opérations SIG).
  • Le package readxl permet d’importer des fichiers Excel sous R.
  • Le package reshape2 permet de transformer et mettre en forme des données sous R.
  • Le package rmapshaper permet de généraliser le contours d’un fond de carte

Packages fournisseurs de données

  • Le package eurostat permet d’importer des données d’Eurostat, fournisseur de référence pour les territoires européens.
  • Le package rnaturalearth permet d’importer les fonds de carte vectoriels de référence pour le Monde (niveaux État ou infra-nationaux) ainsi que des éléments d’habillage (graticules, traits de côte, etc.)
  • Le package osmdata permet d’importer des données d’OpenStreetMap.

Exo 1 - Bienvenue à Sète

Objectifs

  • Espace d’étude : Hérault, communes
  • Prise en main des fonctions spatiales de R

Téléchargement des données

Téléchargez les données ici : Télécharger

Décompressez le dossier et cliquez sur proj.Rproj. Le fichier exo1.R s’ouvre dans R-Studio.

Commandes de base

Vérifiez votre répertoire de travail courant.

getwd()

Consulter le contenu. Regarder ce qu’il y a dans le répertoire “data”

list.files()
list.files("data")

Import d’une couche SIG dans R avec le package sf. Pacakge basé sur GEOS (Geometry Engine Open Source) et GDAL (Geospatial Data Abstraction Library).

library("sf")
## Linking to GEOS 3.6.2, GDAL 2.2.3, proj.4 4.9.3
communes <- st_read(dsn = "data/communes.shp", stringsAsFactors = F)
## Reading layer `communes' from data source `/home/nlambert/ownCloud/ANF2018 - R geoviz/data/communes.shp' using driver `ESRI Shapefile'
## Simple feature collection with 343 features and 5 fields
## geometry type:  POLYGON
## dimension:      XY
## bbox:           xmin: 662675 ymin: 6234874 xmax: 796333 ymax: 6319348
## epsg (SRID):    NA
## proj4string:    +proj=lcc +lat_1=49 +lat_2=44 +lat_0=46.5 +lon_0=3 +x_0=700000 +y_0=6600000 +ellps=GRS80 +units=m +no_defs

Voir la table atributaire

communes
## Simple feature collection with 343 features and 5 fields
## geometry type:  POLYGON
## dimension:      XY
## bbox:           xmin: 662675 ymin: 6234874 xmax: 796333 ymax: 6319348
## epsg (SRID):    NA
## proj4string:    +proj=lcc +lat_1=49 +lat_2=44 +lat_0=46.5 +lon_0=3 +x_0=700000 +y_0=6600000 +ellps=GRS80 +units=m +no_defs
## First 10 features:
##    INSEE_COM                       NOM_COMM           STATUT SUPERFICIE
## 1      34029                        BELARGA   Commune simple        415
## 2      34290 SAINT-VINCENT-DE-BARBEYRARGUES   Commune simple        222
## 3      34032                        BEZIERS   Sous-prfecture       9567
## 4      34082                    COMBAILLAUX   Commune simple        902
## 5      34108                     FRONTIGNAN Chef-lieu canton       3984
## 6      34166                      MONTBLANC   Commune simple       2716
## 7      34066                    CAZEVIEILLE   Commune simple       1619
## 8      34296                      SAUSSINES   Commune simple        630
## 9      34269        SAINT-JEAN-DE-MINERVOIS   Commune simple       3277
## 10     34012                     ARGELLIERS   Commune simple       5065
##    NOM_DEPT                       geometry
## 1   HERAULT POLYGON ((742075 6272005, 7...
## 2   HERAULT POLYGON ((770896 6289405, 7...
## 3   HERAULT POLYGON ((718759 6244261, 7...
## 4   HERAULT POLYGON ((761606 6284489, 7...
## 5   HERAULT POLYGON ((758738 6257679, 7...
## 6   HERAULT POLYGON ((728067 6248191, 7...
## 7   HERAULT POLYGON ((762395 6294296, 7...
## 8   HERAULT POLYGON ((784582 6294234, 7...
## 9   HERAULT POLYGON ((686897 6252592, 6...
## 10  HERAULT POLYGON ((756922 6287661, 7...
head(communes,3)
## Simple feature collection with 3 features and 5 fields
## geometry type:  POLYGON
## dimension:      XY
## bbox:           xmin: 710431 ymin: 6244261 xmax: 771300 ymax: 6292043
## epsg (SRID):    NA
## proj4string:    +proj=lcc +lat_1=49 +lat_2=44 +lat_0=46.5 +lon_0=3 +x_0=700000 +y_0=6600000 +ellps=GRS80 +units=m +no_defs
##   INSEE_COM                       NOM_COMM         STATUT SUPERFICIE
## 1     34029                        BELARGA Commune simple        415
## 2     34290 SAINT-VINCENT-DE-BARBEYRARGUES Commune simple        222
## 3     34032                        BEZIERS Sous-prfecture       9567
##   NOM_DEPT                       geometry
## 1  HERAULT POLYGON ((742075 6272005, 7...
## 2  HERAULT POLYGON ((770896 6289405, 7...
## 3  HERAULT POLYGON ((718759 6244261, 7...
View(communes)

L’instruction plot permet d’afficher la couche. L’instruction st_geometry permet d’accéder à la variable définissant les géométries.

plot(st_geometry(communes))

Afficher la couche avec des parametres graphiques

plot(st_geometry(communes), col="#aec8f2", border="darkblue", lwd=1)

Ajuster les marges

par(mar = c(0.5,0.5,1.5,0.5)) 
plot(st_geometry(communes), col="#aec8f2", border="darkblue", lwd=1)

Introduction au SIG avec R / Manipuler les informations spatiales

Nous cherchons à identifier les communes qui ont une partie de leur territoire situé à moins de 20 km du centre de Sète.

Nous commençons par extraire la commune de Sète du fond de carte communal de référence.

macommune <- "SETE"
monpoly <- communes[communes$NOM_COMM == macommune,]
par(mar = c(0.5,0.5,1.5,0.5)) 
plot(st_geometry(communes), col="#aec8f2", border="darkblue", lwd=1)
plot(st_geometry(monpoly), col="red", border="purple", lwd=1, add=T)

Calculer le centroïde de la commune de Sète.

moncentre <- st_centroid(x = monpoly)
## Warning in st_centroid.sf(x = monpoly): st_centroid assumes attributes are
## constant over geometries of x
par(mar = c(0.5,0.5,1.5,0.5)) 
plot(st_geometry(communes), col="#aec8f2", border="darkblue", lwd=1)
plot(st_geometry(monpoly), col="red", border="purple", lwd=1, add=T)
plot(st_geometry(moncentre), pch=20, col="black", cex=2, add=T)

Calculer une zone tampon

mydist <- 20000
buff <- st_buffer(x = st_geometry(moncentre), dist=mydist)
par(mar = c(0.5,0.5,1.5,0.5)) 
plot(st_geometry(communes), col="#aec8f2", border="darkblue", lwd=1)
plot(st_geometry(monpoly), col="red", border="purple", lwd=1, add=T)
plot(st_geometry(moncentre), pch=20, col="black", cex=2, add=T)
plot(buff, col=NA, border="black", lty=2,add=T)

Récupérer la liste des communes

communes$buff <- st_intersects(st_geometry(communes), st_geometry(buff), sparse = FALSE)
head(communes)
## Simple feature collection with 6 features and 6 fields
## geometry type:  POLYGON
## dimension:      XY
## bbox:           xmin: 710431 ymin: 6244261 xmax: 771300 ymax: 6292043
## epsg (SRID):    NA
## proj4string:    +proj=lcc +lat_1=49 +lat_2=44 +lat_0=46.5 +lon_0=3 +x_0=700000 +y_0=6600000 +ellps=GRS80 +units=m +no_defs
##   INSEE_COM                       NOM_COMM           STATUT SUPERFICIE
## 1     34029                        BELARGA   Commune simple        415
## 2     34290 SAINT-VINCENT-DE-BARBEYRARGUES   Commune simple        222
## 3     34032                        BEZIERS   Sous-prfecture       9567
## 4     34082                    COMBAILLAUX   Commune simple        902
## 5     34108                     FRONTIGNAN Chef-lieu canton       3984
## 6     34166                      MONTBLANC   Commune simple       2716
##   NOM_DEPT                       geometry  buff
## 1  HERAULT POLYGON ((742075 6272005, 7...  TRUE
## 2  HERAULT POLYGON ((770896 6289405, 7... FALSE
## 3  HERAULT POLYGON ((718759 6244261, 7... FALSE
## 4  HERAULT POLYGON ((761606 6284489, 7... FALSE
## 5  HERAULT POLYGON ((758738 6257679, 7...  TRUE
## 6  HERAULT POLYGON ((728067 6248191, 7... FALSE

Récupérer le nombre de communes situées à moins de 20 km de Sète.

nb <- dim(communes[communes$buff == T,])
nb[1]
## [1] 40

Extraction et affichage des communes

communes20km <- communes[communes$buff == TRUE,]
par(mar = c(0.5,0.5,1.5,0.5)) 
plot(st_geometry(communes), col="#aec8f2", border="darkblue", lwd=1)
plot(st_geometry(monpoly), col="red", border="purple", lwd=1, add=T)
plot(st_geometry(moncentre), pch=20, col="black", cex=2, add=T)
plot(buff, col=NA, border="black", lty=2,add=T)
plot(st_geometry(communes20km), col=NA, lwd=2, border="red", add=T)

Nouvelle carte avec un titre (NB : La première couche affichée détermine l’emprise de la carte)

par(mar = c(0.5,0.5,1.5,0.5)) 
plot(st_geometry(communes20km), col="#aec8f2", border="darkblue", lwd=1)
plot(st_geometry(monpoly), col="red", border="purple", lwd=1, add=T)
plot(buff, col=NA, border="black", lty=2,add=T)
montitre <- paste0("Il y a ", nb[1], " communes situées à moins de ", mydist/1000, "km de ",tolower(macommune))
title(montitre)

Export (si besoin)

st_write(obj = communes20km, dsn = "outputs/resultat.shp")

A vous de jouer !

Reproduisez cette procédure avec la commune et la distance de votre choix.

Pour accéder au listing des communes d’Hérault

communes$NOM_COMM

Exo 2 - Cartographier l’Occitanie

Objectifs

  • Thématique : Réaliser une carte des catégories socio-professionnelles.
  • Espace d’étude : Occitanie, communes
  • Visualisation associée : carte en figurés proportionnels (+ cartogrammes de Dorling)
  • packages utilisés : sf, cartography, cartogram, readxl

Téléchargement des données

Téléchargez les données ici : Télécharger

Décompressez le dossier et cliquez sur proj.Rproj. Le fichier exo2.R s’ouvre dans R-Studio.

Préparation des données

Pour bien commencer, il est fondamental de jeter un oeil au fichier d’entrée pour comprendre son organisation et savoir comment l’importer sous R.

Ouvrez le fichier data/INSEE/pop-act2554-csp-cd-6814.xls Nous nous intéressons ici à l’onglet “COM_2014”.

Tableau communal- Population des 25 à
54 ans par CSP et activité au lieu de résidence (INSEE)

library("sf")
library("readxl")

Importez correctement cette feuille du tableau Excel dans R. Les commandes de base ci-dessous permettent de visualiser le nom des colonnes, de filtrer le contenu de la table (par région) et de visualiser finalement le tableau de données dans R.

sheet <- "COM_2014"
data <- data.frame(read_excel("data/INSEE/pop-act2554-csp-cd-6814.xlsx", skip = 15, sheet = sheet)) 
colnames(data)
##  [1] "RR"                            "DR"                           
##  [3] "CR"                            "STABLE"                       
##  [5] "DR16"                          "LIBELLE"                      
##  [7] "csx_rec1taxtypac_rec1rpop2014" "csx_rec1taxtypac_rec2rpop2014"
##  [9] "csx_rec2taxtypac_rec1rpop2014" "csx_rec2taxtypac_rec2rpop2014"
## [11] "csx_rec3taxtypac_rec1rpop2014" "csx_rec3taxtypac_rec2rpop2014"
## [13] "csx_rec4taxtypac_rec1rpop2014" "csx_rec4taxtypac_rec2rpop2014"
## [15] "csx_rec5taxtypac_rec1rpop2014" "csx_rec5taxtypac_rec2rpop2014"
## [17] "csx_rec6taxtypac_rec1rpop2014" "csx_rec6taxtypac_rec2rpop2014"
data <- data[data$RR == "76",] # Ne prendre que les communes d'Occitanie (code 76)
View(data) # vOIR Si le fichier a correctement été importé. 

Pour notre analyse nous avons besoin de regrouper plusieurs colonnes. Créez de nouveaux champs en aggrégeant emploi + chômage par CSP. Renommez ces champs de façon explicite. Cela facilitera leur traitement par la suite. Agrégez également le code départemental au code communal afin de créer un identifiant (id) compatible avec le fond de carte IGN.

data$id <- paste0(data$DR, data$CR) # Creation du code commune
data[,"agr"]<- round(data[7] + data[8],0) # Actifs + chomeurs par CSP
data[,"art"] <- round(data[9] + data[10],0)
data[,"sup"] <- round(data[11] + data[12],0)
data[,"int"] <- round(data[13] + data[14],0)
data[,"emp"] <- round(data[15] + data[16],0)
data[,"ouv"] <- round(data[17] + data[18],0)
data[,"ouv_chom"] <- round(data[18],0)
data$total <- data$agr + data$art + data$sup + data$int + data$emp + data$ouv

Importez et visualisez le fond de carte (extrait IGN Geofla communes).

communes <- st_read(dsn = "data/IGN/occitanie.shp", stringsAsFactors = F)
## Reading layer `occitanie' from data source `/home/nlambert/ownCloud/ANF2018 - R geoviz/data/IGN/occitanie.shp' using driver `ESRI Shapefile'
## Simple feature collection with 4516 features and 17 fields
## geometry type:  MULTIPOLYGON
## dimension:      XY
## bbox:           xmin: 428145.7 ymin: 6137116 xmax: 848019.7 ymax: 6439628
## epsg (SRID):    NA
## proj4string:    +proj=lcc +lat_1=49 +lat_2=44 +lat_0=46.5 +lon_0=3 +x_0=700000 +y_0=6600000 +ellps=GRS80 +units=m +no_defs
par(mar = c(0.5,0.5,1.5,0.5)) 
plot(st_geometry(communes),col="white", border="black", lwd=0.1)

La Jointure est une étape cruciale qui permet de lier un fond de carte avec des données par un même identifiant. Il faut que les identifiants entre ces deux ressources soient exactement les mêmes.

Lier un fond de carte avec des données :
 la jointure

Réalisez la jointure entre données et fond de carte avec l’instruction merge. Cela présuppose en amont que les identifiants géographiques entre ces deux ressources sont les mêmes (ça tombe bien, c’est le cas !). Identifiez bien le nom des champs sur lesquel doit porter la jointure.

communes <- merge(x = communes, y = data, by.x = "INSEE_COM", by.y = "id", all.x=T)

Pour finir, nettoyez le tableau. On ne garde que les colonnes utiles pour la suite…

colnames(communes)
##  [1] "INSEE_COM"                     "ID_GEOFLA"                    
##  [3] "CODE_COM"                      "NOM_COM"                      
##  [5] "STATUT"                        "X_CHF_LIEU"                   
##  [7] "Y_CHF_LIEU"                    "X_CENTROID"                   
##  [9] "Y_CENTROID"                    "Z_MOYEN"                      
## [11] "SUPERFICIE"                    "POPULATION"                   
## [13] "CODE_ARR"                      "CODE_DEPT"                    
## [15] "NOM_DEPT"                      "CODE_REG"                     
## [17] "NOM_REG"                       "RR"                           
## [19] "DR"                            "CR"                           
## [21] "STABLE"                        "DR16"                         
## [23] "LIBELLE"                       "csx_rec1taxtypac_rec1rpop2014"
## [25] "csx_rec1taxtypac_rec2rpop2014" "csx_rec2taxtypac_rec1rpop2014"
## [27] "csx_rec2taxtypac_rec2rpop2014" "csx_rec3taxtypac_rec1rpop2014"
## [29] "csx_rec3taxtypac_rec2rpop2014" "csx_rec4taxtypac_rec1rpop2014"
## [31] "csx_rec4taxtypac_rec2rpop2014" "csx_rec5taxtypac_rec1rpop2014"
## [33] "csx_rec5taxtypac_rec2rpop2014" "csx_rec6taxtypac_rec1rpop2014"
## [35] "csx_rec6taxtypac_rec2rpop2014" "agr"                          
## [37] "art"                           "sup"                          
## [39] "int"                           "emp"                          
## [41] "ouv"                           "ouv_chom"                     
## [43] "total"                         "geometry"
fields <- c("INSEE_COM", "LIBELLE", "agr", "art", "sup", "int", "emp", "ouv","ouv_chom", "total",  "geometry")
communes <- communes[,fields]
colnames(communes) <-  c("id", "name", "agr", "art", "sup", "int", "emp", "ouv","ouv_chom", "total",  "geometry")
head(communes)
## Simple feature collection with 6 features and 10 fields
## geometry type:  MULTIPOLYGON
## dimension:      XY
## bbox:           xmin: 556068.9 ymin: 6180702 xmax: 612006.7 ymax: 6219884
## epsg (SRID):    NA
## proj4string:    +proj=lcc +lat_1=49 +lat_2=44 +lat_0=46.5 +lon_0=3 +x_0=700000 +y_0=6600000 +ellps=GRS80 +units=m +no_defs
##      id          name agr art sup int emp ouv ouv_chom total
## 1 09001 Aigues-Juntes   5   5   5   9   5   5        0    34
## 2 09002  Aigues-Vives   0  19  24  58  73  63       15   237
## 3 09003     Aiguillon   0   0   5  19  44  44       10   112
## 4 09004        Albiès   5  11  11  11  11  16       11    65
## 5 09005          Aleu   4   0   0   4   8   4        4    20
## 6 09006        Alliat   0   0   0  10   5   5        0    20
##                         geometry
## 1 MULTIPOLYGON (((572559.1 62...
## 2 MULTIPOLYGON (((607979.2 62...
## 3 MULTIPOLYGON (((612006.7 62...
## 4 MULTIPOLYGON (((594651 6188...
## 5 MULTIPOLYGON (((557843.5 61...
## 6 MULTIPOLYGON (((584509.3 61...

Le package cartography

Le package et sa documentation

Chargez le package cartography.

library("cartography")

Ce package permet de créer et intégrer des cartes thématiques dans sa chaîne de traitement en R. Il permet des représentations cartographiques telles que les cartes en symboles proportionnels, des cartes choroplèthes, des typologies, des cartes de flux ou des cartes de discontinuités. Il offre également des fonctions qui permettent d’améliorer la réalisation de la carte, comme des palettes de couleur, des éléments d’habillage (échelle, flèche du nord, titre, légende…), d’y rattacher des labels ou d’accéder à des APIs cartographiques.

Pour utiliser aisément ce package, plusieurs sources d’intérêts peuvent être consultées :

  • La documentation du package qui documente toutes les fonctions du package, accessible directement dans R Studio. Pour cela, vous pouvez taper simplement :
?cartography
  • La cheat sheet de cartography, qui résume les principales fonctions du package de façon synthétique.
  • La vignette associée au package, qui présente des réalisations issues de ce package, elle aussi accessible directement dans R studio.
  • La vignette Faire des cartes - Introduction au package sf qui présente les packages sf et cartography, à partir d’un cas d’utilisation centré sur Mexico.
  • Le blog R Géomatique, maintenu par l’auteur de cartography qui met à disposition ressources et exemples d’intérêt liés au package et à la représentation d’information spatiale sous R.

Éléments théoriques

Savoir représenter correctement de l’information dans des cartes thématiques, c’est d’abord savoir caractériser la nature statistique des données.

Comment caractériser les données

Jacques Bertin a notamment théorisé dans son ouvrage de référence “Sémiogie Graphique” (1967) les méthodes visuelles qui permettent de retranscrire efficacement une information statistique sous forme cartographique.

Il identifie des variables visuelles (ou rétiniennes) dont l’utilisation dépend de l’implantation (point, ligne, surface) et la nature statistique de l’information à représenter (association, sélection, ordre, quantité).

Bertin, 1967, niveau des variables rétiniennes

Visualisation : carte en figurés proportionnels

Pour les caractères quantitatifs absolus la variable visuelle adaptée est la taille afin de préserver graphiquement les rapports de proportionnalité existant entre les différentes valeurs du tableau de données. Il n’est pas nécessaire de discrétiser les valeurs (cf exemple sur l’Europe).

Visualisation !

Cartographiez le nombre d’actifs par commune grâce à la fonction propSymbolsLayer

# Ajuster les marges
par(mar = c(0.5,0.5,1.5,0.5)) 

# Cartographie
plot(st_geometry(communes), col="lightblue",border="white", lwd=0.2) # Fond de carte de la région Occitanie
propSymbolsLayer(x = communes, var = "total",  # Carte en figurés proportionnels 
                 symbols = "circle", col =  "red",
                 legend.pos = "right", border = "grey",
                 legend.title.txt = "Les actifs",
                 legend.style = "c")

top <- sort(data.frame(communes)[,"total"], decreasing = TRUE) 
labelLayer(x = communes[data.frame(communes)[,"total"] %in% top[1:15],], txt = "name", halo=TRUE, cex = 0.6, col= "#000000", bg = "#FFFFFF50", overlap = FALSE) # Nommer les 15 premières villes d'Occitanie en nombre d'actifs
title("Région Occitanie")

Visualisation : carte combinant figurés proportionnels et typologie

Il est possible d’associer à ces figurés proportionnels la représentation d’un caractère qualitatif de différenciation.

La variable visuelle adaptée pour ce type de données est la couleur différentielle.

Exécutez le code ci-dessous, qui propose le calcul d’une typologie sur la surreprésentation d’ouvriers ou de cadres. Cette typologie peut être représentée simplement avec la fonction typoLayer.

Pour le choix des couleurs, vous pouvez utiliser color picker pour obtenir les couleurs que vous désirez, au format hexadécimal présenté ci-dessous.

# Typologie (plus d'ouvriers que de cadres ?)
communes$typo <- "Indéterminé"
communes$r <- communes$ouv / communes$sup
communes$r[is.na(communes$r)] <- 0
communes[communes$r > 1.1,"typo"] <- "Plus d'ouvriers que de cadres"
communes[communes$r < 0.91,"typo"] <- "Plus de cadres que d'ouvriers"

# Choix des couleurs
colouv <- "#dd4e44" # tonalité rouge
colsup <- "#63b269" # tonalité verte

# Ajuster les marges
par(mar = c(0.5,0.5,1.5,0.5)) 

# Cartographie
typoLayer(communes, var="typo", 
          legend.values.order = c("Plus d'ouvriers que de cadres", 
                                  "Plus de cadres que d'ouvriers",
                                  "Indéterminé" ),
          col = c(colouv, colsup, 'grey'), 
          border = NA, legend.title.txt = "Type dominant") 

On peut aussi décider d’associer cette représentation à la carte précédente en figurés proportionnels, grâce à la fonction propSymbolsTypoLayer :

# Ajuster les marges
par(mar = c(0.5,0.5,1.5,0.5)) 

# Combiner avec la carte précédente
plot(st_geometry(communes), col="lightblue",border=NA)
propSymbolsTypoLayer(x = communes, var = "total", var2 = "typo",
                     symbols = "circle",
                     inches = 0.4,
                     col = c(colouv, colsup, 'grey'),
                     border = "white", lwd = 0.1,
                     legend.var2.values.order = c("Plus d'ouvriers que de cadres", 
                                             "Plus de cadres que d'ouvriers",
                                             "Indéterminé" ),
                     legend.var.pos = "right", 
                     legend.var.title.txt = "Nombre d'actifs",
                     legend.var2.title.txt = "Type dominant")

labelLayer(x = communes[data.frame(communes)[,"total"] %in% top[1:15],], txt = "name", halo=TRUE, cex = 0.6, col= "#000000", bg = "#FFFFFF50", overlap = FALSE) 
title("Cadres et ouvriers en région Occitanie")

Une astuce cartographique : le “cartogramme” de Dorling

A cette échelle géographique on remarque que les cercles se superposent les uns sur les autres. Cela ne nuit pas à la compréhension globale de l’organisation spatiale du phénomène, mais ne permet pas d’en avoir une lecture précise (à cette échelle de visualisation et pour cet espace d’étude). On peut aussi décider d’utiliser un package et une fonction qui permet d’éviter cela.

Pour ce faire, lancez la librairie cartogram et la fonction cartogram_dorling. Le cartogramme de Dorling replace la localisation des cercles en conservant leurs positions relatives et permet d’éviter leurs chevauchements.

library("cartogram")
# Ajuster les marges
par(mar = c(0.5,0.5,1.5,0.5)) 

# cartogram de Dorling
actifs <- cartogram_dorling(communes, "total", k = 1, m_weight = 1, itermax = 20)

plot(st_geometry(communes), col="lightblue",border=NA)

typoLayer(actifs, var="typo", 
          legend.values.order = c("Plus d'ouvriers que de cadres", 
                                  "Plus de cadres que d'ouvriers",
                                  "Indéterminé" ),
          col = c(colouv, colsup, 'grey'), 
          border = "white", lwd=0.2, legend.title.txt = "Type dominant",
          add = T) 
labelLayer(x = actifs[data.frame(actifs)[,"total"] %in% top[1:15],], txt = "name", halo=TRUE, cex = 0.6, col= "#000000", bg = "#FFFFFF50", overlap = FALSE) 
title("Ouvriers et cadres en Occitanie, 2014")

A vous de jouer !

On souhaite réaliser une carte avec une autre catégorie socio-professionnelle : les agriculteurs (ou une autre CSP de votre choix). Pourquoi ne pas choisir des carrés à la place des cercles ?

Voici le code à compléter pour réaliser la carte :

plot(st_geometry(communes), col="",border="", lwd="")

propSymbolsLayer(...)

Exo 3 - Cartographier l’Europe

Objectifs

  • Thématique : Réaliser des cartes de densité de population et de PIB par habitant pour les régions européennes.
  • Espace d’étude : Europe, NUTS3
  • Visualisation associée : cartes choroplèthes et cartes en grilles
  • packages utilisés : sf, cartography, eurostat, reshape2

Téléchargement des données

Téléchargez les données ici : Télécharger

Décompressez le dossier et cliquez sur proj.Rproj. Le fichier exo3.R s’ouvre dans R-Studio.

Préparation des données

Chargez les géométries qui seront utilisées pour visualiser vos résultats. Il s’agit des géométries de référence des territoires européens adaptées à la cartographie thématique et proposées par l’UMS RIATE.

# Charger la librairie sf
library(sf)

# Fond de carte principal
regions <- st_read(dsn = "data/GREAT/nuts2013-level3.shp", stringsAsFactors = F) 
## Reading layer `nuts2013-level3' from data source `/home/nlambert/ownCloud/ANF2018 - R geoviz/data/GREAT/nuts2013-level3.shp' using driver `ESRI Shapefile'
## Simple feature collection with 1538 features and 2 fields
## geometry type:  MULTIPOLYGON
## dimension:      XY
## bbox:           xmin: -28.82873 ymin: 27.64158 xmax: 44.78307 ymax: 71.141
## epsg (SRID):    4326
## proj4string:    +proj=longlat +datum=WGS84 +no_defs
# Couche d'habillage
countries <- st_read("data/GREAT/world.shp",stringsAsFactors = F)
## Reading layer `world' from data source `/home/nlambert/ownCloud/ANF2018 - R geoviz/data/GREAT/world.shp' using driver `ESRI Shapefile'
## Simple feature collection with 199 features and 1 field
## geometry type:  MULTIPOLYGON
## dimension:      XY
## bbox:           xmin: -180 ymin: -54.92918 xmax: 180 ymax: 83.57445
## epsg (SRID):    4326
## proj4string:    +proj=longlat +datum=WGS84 +no_defs

Astuce ! Le package eurostat permet d’accéder à la base de données de référence européenne directement dans l’environnement de R. Cela permet d’avoir des données à jour et d’éviter des potentielles erreurs de manipulation de données.

Le code ci-dessous (à ne pas exécuter) est un exemple de procédure d’extraction de données (population, surface, PIB).

library("eurostat")
library("reshape2") 

# POPULATION
var <- "demo_r_pjangrp3" # Table Eurostat d'intérêt
data <- get_eurostat(var, time_format = "num") # Telecharger la table ESTAT
data <- subset(data, data$sex == "T") # Filtre des dimensions du tibble
data <- subset(data, data$age == "TOTAL") # Filtre des dimensions du tibble
data <- dcast(data, geo ~ time, value.var = "values") # Transformation en dataframe des dimensions restantes
colnames(data) <- c("geo","POP_2014","POP_2015","POP_2016","POP_2017") # Renommer les colonnes du dataframe de façon explicite

# SURFACE
var <- "reg_area3"
area <- get_eurostat(var, time_format = "num") # Telecharger la table ESTAT
area <- subset(area, area$landuse == "TOTAL") # Filtre des dimensions de la table
area <- dcast(area, geo ~ time, value.var = "values")
colnames(area) <- c("geo","AREA")

# PIB
var <- "nama_10r_3gdp"
gdp <- get_eurostat(var, time_format = "num")
gdp <- subset(gdp, gdp$unit == "MIO_EUR")
gdp <- dcast(gdp, geo ~ time, value.var = "values")
fields <- c("geo", "2014", "2015", "2016") # On ne garde que les valeurs de PIB correspondant aux valeurs de population disoponibles
gdp <- gdp[,fields]
colnames(gdp) <- c("geo","GDP_2014","GDP_2015","GDP_2016")

# Jointure avec les géométries
regions <- merge(x = regions, y = data, by.x = "id", by.y = "geo", all.x=T) # population
regions <- merge(x = regions, y = area, by.x = "id", by.y = "geo", all.x=T) # surface
regions <- merge(x = regions, y = gdp, by.x = "id", by.y = "geo", all.x=T) # surface

# Export du fichier contenant géométries et données
write_sf(obj = regions, dsn = "data/regions_data.shp")

Importez le jeu de données créé suite à cette étape de collecte de données, qui est maintenant associé aux géométries européennes de réference.

regions <- st_read("data/regions_data.shp", stringsAsFactors = F)
## Reading layer `regions_data' from data source `/home/nlambert/ownCloud/ANF2018 - R geoviz/data/regions_data.shp' using driver `ESRI Shapefile'
## Simple feature collection with 1538 features and 10 fields
## geometry type:  MULTIPOLYGON
## dimension:      XY
## bbox:           xmin: -28.82873 ymin: 27.64158 xmax: 44.78307 ymax: 71.141
## epsg (SRID):    4326
## proj4string:    +proj=longlat +datum=WGS84 +no_defs
par(mar = c(0.5,0.5,1.5,0.5)) 
plot(st_geometry(regions))

head(regions)
## Simple feature collection with 6 features and 10 fields
## geometry type:  MULTIPOLYGON
## dimension:      XY
## bbox:           xmin: 19.37065 ymin: 40.73386 xmax: 20.62819 ymax: 42.71386
## epsg (SRID):    4326
## proj4string:    +proj=longlat +datum=WGS84 +no_defs
##      id    name POP_2014 POP_2015 POP_2016 POP_2017 AREA GDP_2014 GDP_2015
## 1 AL011   Diber   134332   131054   129056   125579   NA      315       NA
## 2 AL012  Durres   276058   277989   280205   284823   NA      923       NA
## 3 AL013   Kukes    84306    82428    81294    79559   NA      194       NA
## 4 AL014   Lezha   133748   131829   130258   129019   NA      334       NA
## 5 AL015 Shkodra   216477   213148   210168   207924   NA      526       NA
## 6 AL021 Elbasan   294938   290666   287606   283822   NA      739       NA
##   GDP_2016                       geometry
## 1       NA MULTIPOLYGON (((20.31134 41...
## 2       NA MULTIPOLYGON (((19.92766 41...
## 3       NA MULTIPOLYGON (((20.42293 42...
## 4       NA MULTIPOLYGON (((20.23201 41...
## 5       NA MULTIPOLYGON (((20.01829 42...
## 6       NA MULTIPOLYGON (((20.33483 40...

Pour choisir l’année de référence sur laquelle portera la visualisation, regardez le nombre de valeurs manquantes…

apply(regions,2,function(x) sum(is.na(x)))
##       id     name POP_2014 POP_2015 POP_2016 POP_2017     AREA GDP_2014 
##        0        0       51       51       51       51       63      162 
## GDP_2015 GDP_2016 geometry 
##      176     1219        0

… Et calculez le ratio sur lequel va porter la visualisation.

regions$DENS_2017 <- regions$POP_2017 / regions$AREA

Tout est prêt pour la visualisation !

Visualisation : cartes choroplèthes

La variable visuelle adaptée pour représenter des données quantitatives relatives est la couleur ordonnée (ou niveaux de gris). Le traitement de ce type de données implique au prélable de définir le nombre de classes, une méthode de discrétisation et une palette de couleurs sur laquelle portera la représentation.

La discrétisation consiste à découper une série statistique en classes de valeurs. Il n’existe pas de méthode optimum. Chaque méthode donnera une carte différente, plus ou moins conforme à la distribution de départ. L’agrégation de données en classes introduit de fait une erreur ou une distorsion dans la perception de cette distribution. Le choix d’une méthode de discrétisation dépend donc des propriétés de la distribution mais aussi des objectifs cartographiques que l’on s’est fixés.

Étape 1 : Déterminer la forme de la distribution

Quelle est la forme de la distribution de la variable de densité de population 2017 ?

var <- regions$DENS_2017

hist(var, probability = TRUE, nclass = 30)
rug(var)
moy <- mean(var)
med <- median(var)
abline(v = moy, na.rm = T, col = "red", lwd = 3)
## Warning in int_abline(a = a, b = b, h = h, v = v, untf = untf, ...):
## "na.rm" is not a graphical parameter
abline(v = med, na.rm = T, col = "blue", lwd = 3)
## Warning in int_abline(a = a, b = b, h = h, v = v, untf = untf, ...):
## "na.rm" is not a graphical parameter

summary(regions$DENS_2017)
##      Min.   1st Qu.    Median      Mean   3rd Qu.      Max.      NA's 
##     1.195    64.788   132.206   549.643   351.530 20779.676        63

On constate qu’il y a beaucoup de régions à faible densité et très peu de région à forte densité; la série est donc fortement dyssimétrique “à gauche”.

On choisit alors la méthode des quantiles qui permet de préserver la dissymétrie des valeurs.

NB / Dans cartography, plusieurs méthodes de discrétisation sont proposées. Jetez un oeil à la documentation de la fonction getBreaks pour en savoir plus.

Étape 2 : Combien de classes ?

Le nombre de classes dépend du nombre d’unités spatiales prises en compte (plus il y a d’unités spatiales plus on peut faire de classes) et dépend des capacités de perception de l’oeil humain (distinguer 10 nuances de couleur est un grand maximum).

On souhaite mettre en évidence les 10 % des valeurs les plus élevées (régions métropolitaines) et les 10 % des valeurs les plus faibles. Autrement dit, on choisit 10 classes pour découper notre série statistique (déciles).

Étape 3 : Quelles couleurs ?

Explorez la documentation de la fonction carto.pal de cartography pour choisir votre palette. Utilisez l’instruction display.carto.all pour visualiser les palettes disponibles. Nous choisissons ici la palette “red.pal”

# Choix de la palette
display.carto.all(10)

cols <- carto.pal(pal1 = "red.pal", n1 = 10)

Tout est défini pour lancer la cartographie !

Visualisation de la discrétisation choisie

library(cartography)

par(mfrow=c(1,1))

# Methode discretisation (quantiles)
breaks <- getBreaks(v = regions$DENS_2017, nclass = 10, method = "quantile")
hist(regions$DENS_2017, probability = TRUE, xlim = c(0,3000), breaks = breaks, col = cols,
     main = "Quantiles")
abline(v = median(regions$DENS_2017, na.rm = T), col = "blue", lwd = 3)

Cartographie

On utilise la projection officielle pour l’Union Européenne

countries <- st_transform(countries,3035)
regions <- st_transform(regions,3035)

La carte choroplèthe est réalisée avec la fonction choroLayer.

# Mise en page
par(mar = c(0.5,0.5,1.5,0.5)) # Ajuster les marges

plot(st_geometry(regions), col = NA, border = NA)
plot(st_geometry(countries), col = "#c6c4c4", border = NA, add =TRUE)

# Cartographie (ratio)
choroLayer(x = regions, 
           var = "DENS_2017",
           method ="quantile",
           nclass = 10,
           col = cols,
           border = NA,
           add = TRUE,
           legend.pos = "left",
           legend.title.txt = "Densité de population \n 2017 (hab/km²)",
           legend.values.rnd = 0)

plot(st_geometry(countries), col = NA, border = "#ffffff", lwd = 1, add =TRUE)

# Sources + elements d'habillage
layoutLayer(title = "Densité de population - Méthode des quantiles",
            author = "Serial Mappers, 2018", sources = "Eurostat, 2018",
            scale = 200, tabtitle = FALSE,
            frame = FALSE,theme = "red.pal",
            south = TRUE)

Si on avait choisi une autre méthode de discrétisation le résultat aurait été tout autre !

A vous de jouer !

Créez une carte choroplèthe avec les paramètres suivants : * Indicateur : PIB / habitant 2014 * Discrétisation : quantiles (8 classes) * Palette de couleurs : Double palette (green.pal/red.pal)

Avant de passer à la cartographie, pensez à créer la variable PIB par habitant.

par(mfrow=c(1,1)) # On revient à un affichage pleine page
choroLayer(...)

Visualisation : cartes carroyées

Sur les cartes précédentes on a pu constater que la taille des entités territoriales est très différente d’un pays à l’autre. Pour certains pays (Allemagne, Pologne) les unités territoriales sont très petites et permettent de distinguer villes et périphéries. Dans d’autres cas, comme en France, celles-sont agrégées et rendent les résutats difficilement comparables.

Ces difficultés liées aux hétérogénéités de maillage renvoient à une série de travaux connus sous l’acronyme MAUP (Modifiable Area Unit Problem)(voir), souvent illustré de la façon suivante :

Plusieurs méthodes existent pour apporter des solutions à ces problèmes en cartographie.

La méthode du carroyage, par exemple, consiste à découper l’espace géographique en un maillage formé de carrés réguliers dans une projection donnée. La donnée est répartie sur ce quadrillage régulier au prorata de la surface représentée. Le quadrillage permet ainsi de s’affranchir des mailles administratives.

Comment faire ? La fonction getGridLayer du package cartography permet de construire ces grilles régulières. Expolorez la documentation pour vous sensibiliser aux arguments de la fonction.

La procédure est la suivante :

  1. Définir le pas de grille (en mètres), son type et les variables qui seront transformées.
  2. Pour les calculs de densité, convertir la surface en km².
  3. Pour les autres indicateurs, combiner les données de la façon suivante : ratio = stock1/stock2.
  4. Choisir sa palette, son nombre de classes et sa méthode de discrétisation.
  5. Représenter la grille avec la fonction choroLayer de cartography.
# Transformation des donnees dans une grille reguliere de 50 km
mygrid50k <- getGridLayer(x = regions, cellsize = 50000 * 50000, 
                       type = "regular", var = c("POP_2017","POP_2014","GDP_2014"))

# Transformation des donnees dans une grille reguliere de 100 km
mygrid100k <- getGridLayer(x = regions, cellsize = 100000 * 100000, 
                          type = "regular", var = c("POP_2017","POP_2014","GDP_2014"))

# Conversion en km²
mygrid50k$densitykm <- mygrid50k$POP_2017 * 1000 * 1000 / mygrid50k$gridarea 
mygrid100k$densitykm <- mygrid100k$POP_2017 * 1000 * 1000 / mygrid100k$gridarea 


# Carte 1
par(mfrow=c(1,1))
par(mar = c(0.5,0.5,1.5,0.5)) # Ajuster les marges

cols <- carto.pal(pal1 = "blue.pal", pal2 = "red.pal",  n1 = 5, n2 = 5)  

plot(st_geometry(regions), col = NA, border = NA)
plot(st_geometry(countries), col = "#c6c4c4", border = NA, add =TRUE)

choroLayer(x = mygrid50k, var = "densitykm", 
           border = "grey80",col = cols, method ="quantile",
           nclass = 10, legend.pos = "topleft", legend.values.rnd = 1,
           lwd=0.5, add = T,
           legend.title.txt = "Densité de population, 2017")

layoutLayer(title = "Densité de population dans une grille régulière de 50km",
            author = "Serial Mappers, 2018", sources = "Eurostat, 2018",
            scale = 200,
            frame = TRUE,
            col = "red",
            coltitle = "white",
            south = TRUE)

# Carte 2

plot(st_geometry(regions), col = NA, border = NA)
plot(st_geometry(countries), col = "#c6c4c4", border = NA, add =TRUE)

choroLayer(x = mygrid100k, var = "densitykm", 
           border = "grey80",col = cols, method ="quantile",
           nclass = 10, legend.pos = "topleft", legend.values.rnd = 1,
           lwd=0.5, add = T,
           legend.title.txt = "Densité de population, 2017")

layoutLayer(title = "Densité de population dans une grille régulière de 100km",
            author = "Serial Mappers, 2018", sources = "Eurostat, 2018",
            scale = 200,
            frame = TRUE,
            col = "red",
            coltitle = "white",
            south = TRUE)

Aller plus loin…

Remarque : D’autres méthodes existent pour résoudre les problèmes du MAUP, comme les cartes lissées (ou de potentiel) qui consistent à s’affranchir complètement du maillage administratif sous-jacent et qui se basent sur la prise en compte du voisinage géographique selon une fonction mathématique (généralement gaussienne).

par(mar = c(0.5,0.5,1.5,0.5)) # Ajuster les marges
regions$GDPM_2014 <- regions$GDP_2014 * 1000000
ratio <- regions$GDPM_2014 / regions$POP_2014
summary(ratio)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max.    NA's 
##    1907   17047   25646   26921   32685  428302     162
bks <- c(500, 5000, 10000, 15000, 20000, 26921, 30000, 35000, 40000, 428302)
cols <- c(rev(carto.pal("green.pal", 5)), carto.pal("orange.pal", 4))

plot(st_geometry(regions), border = NA, col = NA)
plot(st_geometry(countries), col = "#E3DEBF", border = NA, add = TRUE)

r <- regions[substr(regions$id,1,2) != "TR",]
r <- r[substr(r$id,1,2) != "IS",]
r <- r[substr(r$id,1,2) != "CH",]

smoothLayer(x = regions,
            var = 'GDPM_2014', var2 = 'POP_2014',
            span = 75000, beta = 2,
            resolution = 50000,
            legend.title.txt = "Potentiel de PIB par habitant, 2014\n(span = 75km)",
            col = cols, breaks = bks,
            lwd=0.2,
            mask = st_buffer(r,1),
            legend.pos = "topleft", legend.values.rnd = -2,
            add = T)

layoutLayer(title = "PIB par habitant, 2014", author = "Les serial mappers, 2018", 
            sources = "Source: Eurostat, 2018", frame = TRUE, scale = 500, north = FALSE, 
            theme = "sand.pal")

Exo 4 - Cartographier le Monde

Objectifs

  • Thématique : Les inégalités d’IDH et/ou d’espérance de vie.
  • Espace d’étude : Le Monde, pays.
  • Visualisation associée : carte chorplèthe, discontinuités.
  • packages utilisés : sf, cartography, rnaturalearth, readxl, countrycode.

Téléchargement des données

Téléchargez les données ici : Télécharger

Décompressez le dossier et cliquez sur proj.Rproj. Le fichier exo4.R s’ouvre dans R-Studio.

Préparation des données

Import du fond de carte

méthode 1 : à la main (après téléchargement sur le site Natural Earth)

library("sf")
countries <- st_read(dsn = "data/naturalearth/ne_110m_admin_0_countries.shp", stringsAsFactors = F)  

Méthode 2 : en ligne

url <- "https://www.naturalearthdata.com/http//www.naturalearthdata.com/download/110m/cultural/ne_110m_admin_0_countries.zip"
download.file(url = url, destfile = "data/countries.zip")
unzip("data/countries.zip", exdir = "data", unzip = "internal")
file.remove("data/countries.zip")
countries <- st_read(dsn = "data/ne_110m_admin_0_countries.shp", stringsAsFactors = F)

Méthode 3 : directement via R

library("rnaturalearth")
countries <- ne_countries(scale = 50, type = "countries", continent = NULL,
                          country = NULL, geounit = NULL, sovereignty = NULL,
                          returnclass = "sf")

Le fond de carte peut être visualisé avec l’instruction plot.

par(mar = c(0.5,0.5,1.5,0.5))
plot(st_geometry(countries))

On ne conserve que les champs utiles. On les renomme.

countries <- countries[,c("adm0_a3", "admin", "geometry")]
colnames(countries) <- c("id","name","geometry")

On Supprime l’Antarctique.

countries <- countries[countries$id != "ATA",]

On supprime les lignes vides.

countries <- countries[!is.na(countries$id),]
par(mar = c(0.5,0.5,1.5,0.5))
plot(st_geometry(countries))

Import des données atributaires

Import des données sur l’éspérance de vie (source : Banque mondiale)

library("readxl")
file <-"data/worldbank/API_SP.DYN.LE00.IN_DS2_en_excel_v2_10081535.xls"
sheet <- "Data"
lifexp <- data.frame(read_excel(file, skip = 3, sheet = sheet))
lifexp <- lifexp[,c("Country.Code","Country.Name","X2016")]
colnames(lifexp) <- c("id","name","lifexp2016")
lifexp$lifexp2016 <- as.numeric(as.character(lifexp$lifexp2016))

Import des données sur l’indice de developpement humain (source : Human Development Report)

file <-"data/hdr/Human Development Index (HDI).csv"
hdi <- read.csv2(file = file, sep = ",",skip = 1)
hdi <- hdi[,c("Country","X2016")]
head(hdi,4)
##        Country X2016
## 1  Afghanistan 0.494
## 2      Albania 0.782
## 3      Algeria 0.753
## 4      Andorra 0.856

Le tableau de données sur l’IDH ne possède pas de codes géographiques, mais uniquement le nom des pays. Cela rend la jointure avec le fond de carte compliquée. Une solution : le package countrycode

library("countrycode")
hdi$id <- countrycode(hdi$Country, 'country.name', 'iso3c')
## Warning in countrycode(hdi$Country, "country.name", "iso3c"): Some values were not matched unambiguously:  Eswatini (Kingdom of)

Un peu de mise en forme. Les codes sont bien là. C’est presque magique… Mais attention, dans la pratique, une vérification manuelle s’impose.

hdi <- hdi[,c("id","Country","X2016")]
colnames(hdi) <- c("id","name","hdi2016")
hdi$hdi2016 <- as.numeric(as.character(hdi$hdi2016))  
head(hdi,4)
##    id         name hdi2016
## 1 AFG  Afghanistan   0.494
## 2 ALB      Albania   0.782
## 3 DZA      Algeria   0.753
## 4 AND      Andorra   0.856

Visualisation : carte choroplèthe

Chargement du package

library("cartography")

Changer la projection du fond de carte (voir le site spatialreference

countries <- st_transform(countries, "+proj=cea +lon_0=0 +lat_ts=45 +x_0=0 +y_0=0 +ellps=WGS84 +units=m +no_defs ")
plot(st_geometry(countries))

Jointures des deux fichiers de données.

countries <- merge(countries, lifexp, by="id", all.x=TRUE)
countries <- merge(countries, hdi, by="id", all.x=TRUE)
countries <- countries[,c("id","name.x","lifexp2016","hdi2016","geometry")]
colnames(countries)[2] <- "name"

On travaille sur l’indice de développement humain

Analyse de la distribution.

var <- countries$hdi2016
hist(countries$hdi2016, probability = TRUE, nclass = 30)

On choisit une discretisation par la méthode des quantiles sans classe centrale.

breaks <- getBreaks(v = var, nclass = 6, method = "quantile")
cols <- carto.pal(pal1="blue.pal", n1 = 3, pal2 = "orange.pal", n2 = 3, middle = FALSE, transparency = FALSE)

Réalisation de la carte.

par(mar = c(0.5,0.5,1.5,0.5))
layoutLayer(extent = countries,
            bg="#EEEEEE",
            title = "Indice de développement humain en 2016",
            scale = NULL,
            sources = "Human development Report, 2018",
            author = "les serial mappers"
            )
choroLayer(x = countries, 
           var = "hdi2016",
           breaks = breaks,
           col = cols,
           border = "white",
           lwd=0.2,
           add = TRUE,
           legend.pos = "topleft",
           legend.title.txt = "IDH, 2016",
           legend.values.rnd = 2)

Et si on ajoutait des lignes de discontinuités à cette carte?

L’instruction getBorders (du package cartography) permet d’extraire les frontières entre les unités spatiales.

borders <- getBorders(countries)
plot(st_geometry(borders), col="black", lwd=1)

Quid des discontinuités maritimes ? Par exemple entre l’Italie et la Tunisie ? Ou entre le Maroc et l’Espagne ? L’instruction getOuterBorders (package cartography) permet de les générer. Cette instruction peut prendre un peu de temps.

outer <- getOuterBorders(x = countries, res = 100000, width=500000)
plot(st_geometry(borders), col="#CCCCCC", lwd=1)
plot(st_geometry(outer), col="red", lwd=1, add=T)

On assemble les deux couches avec rbind.

b <- rbind(borders,outer)

Tout est prêt pour réaliser une carte de discontinuités.

# 1 - la carte choroplèthe
par(mar = c(0.5,0.5,1.5,0.5))
layoutLayer(extent = countries,
            bg="#EEEEEE",
            title = "Indice de développement humain en 2016",
            scale = NULL,
            sources = "Human development Report, 2018",
            author = "les serial mappers"
            )

choroLayer(x = countries, 
           var = "hdi2016",
           breaks = breaks,
           col = cols,
           border = "white",
           lwd=0.2,
           add = TRUE,
           legend.pos = "topleft",
           legend.title.txt = "IDH, 2016",
           legend.values.rnd = 2)

# 2 - les discontinuités

discLayer(x = b, df = countries,
          var = "hdi2016", col="black", nclass=4,
          method="quantile", threshold = 0.25, sizemin = 0.2,
          sizemax = 8, type = "abs", 
          legend.title.txt = "Discontinuities\nabsolues",
          legend.pos = "bottomleft", add=TRUE)

A vous de jouer

Réaliser une carte de discontinuités sur l’espérance de vie

layoutLayer(...)
choroLayer(...)
discLayer(...

BONUS

Objectifs

  • Utiliser des données Open Street Map
  • Généraliser un fond de carte

Téléchargement des données

Téléchargez les données ici : Télécharger

Décompressez le dossier et cliquez sur proj.Rproj. Le fichier bonus.R s’ouvre dans R-Studio.

Dé-Googliser la carto !

OpenStreetMap (OSM) est un projet de cartographie participative qui a pour but de constituer une base de données géographiques libre à l’échelle mondiale. OpenStreetMap vous permet de voir, modifier et utiliser des données géographiques dans le Monde entier. En résumé, c’est comme Google Maps, mais en mieux…

library("sf")
library("cartography")

depts <- st_read(dsn = "data/IGN/DEPARTEMENT.shp", stringsAsFactors = F)
## Reading layer `DEPARTEMENT' from data source `/home/nlambert/ownCloud/ANF2018 - R geoviz/data/IGN/DEPARTEMENT.shp' using driver `ESRI Shapefile'
## Simple feature collection with 96 features and 11 fields
## geometry type:  MULTIPOLYGON
## dimension:      XY
## bbox:           xmin: 99217.1 ymin: 6049646 xmax: 1242417 ymax: 7110480
## epsg (SRID):    NA
## proj4string:    +proj=lcc +lat_1=44 +lat_2=49 +lat_0=46.5 +lon_0=3 +x_0=700000 +y_0=6600000 +ellps=GRS80 +units=m +no_defs
colnames(depts)
##  [1] "ID_GEOFLA"  "CODE_DEPT"  "NOM_DEPT"   "CODE_CHF"   "NOM_CHF"   
##  [6] "X_CHF_LIEU" "Y_CHF_LIEU" "X_CENTROID" "Y_CENTROID" "CODE_REG"  
## [11] "NOM_REG"    "geometry"
Paris <- depts[depts$CODE_DEPT == 75,]
par(mar = c(0.5,0.5,1.5,0.5))
plot(st_geometry(Paris))

Paname <- getTiles(x = Paris, type = "osm", crop = TRUE)
Paname <- getTiles(x = Paris, type ="opencycle", crop = TRUE)
tilesLayer(Paname)

plot(st_geometry(Paris), lwd=4, add=T)

library("osmdata")
## Data (c) OpenStreetMap contributors, ODbL 1.0. http://www.openstreetmap.org/copyright
prj <- st_crs(Paris)

bbox <- st_bbox(st_transform(Paris,4326))

q <- opq(bbox = bbox , timeout = 2000) %>% add_osm_feature(key = 'man_made', value = 'surveillance')
cameras <- osmdata_sf(q)$osm_points
cameras <- st_transform(cameras, prj)

cameras$ok <- st_intersects(st_geometry(cameras), st_geometry(Paris), sparse = FALSE)
cameras <- cameras[cameras$ok == T,]

Paname <- getTiles(x = Paris, type ="cartodark", crop = TRUE)
tilesLayer(Paname)
par(mar = c(0.5,0.5,1.5,0.5))
plot(st_geometry(Paris), lwd=1, border="white", lty=2, add=T)
plot(st_geometry(cameras), pch=20, col="red", add=T)

Généraliser un fond de carte

Toute carte est une reproduction réduite d’une portion de l’espace. Elle suppose donc une simplification des tracés, une réduction de la précision géométrique pour favoriser la lisibilité. C’est ce qu’on appelle la généralisation.

library("rmapshaper")

Import et affichage d’un fond de carte.

countries <- st_read(dsn = "data/naturalearth/ne_110m_admin_0_countries.shp", stringsAsFactors = F)
## Reading layer `ne_110m_admin_0_countries' from data source `/home/nlambert/ownCloud/ANF2018 - R geoviz/data/naturalearth/ne_110m_admin_0_countries.shp' using driver `ESRI Shapefile'
## Simple feature collection with 177 features and 94 fields
## geometry type:  MULTIPOLYGON
## dimension:      XY
## bbox:           xmin: -180 ymin: -90 xmax: 180 ymax: 83.64513
## epsg (SRID):    4326
## proj4string:    +proj=longlat +datum=WGS84 +no_defs
par(mar = c(0.5,0.5,1.5,0.5))
plot(st_geometry(countries), col="#d1a2d3")

Généralisation avec sf (ça ne marche pas très bien… Pour l’instant ! ).

countries2 <- st_simplify(x = countries, preserveTopology = TRUE, dTolerance = 2)
## Warning in st_simplify.sfc(st_geometry(x), preserveTopology, dTolerance):
## st_simplify does not correctly simplify longitude/latitude data, dTolerance
## needs to be in decimal degrees
par(mar = c(0.5,0.5,1.5,0.5))
plot(st_geometry(countries2), col="#d1a2d3")

Généralisation avec rmapshaper (Youpie !!!)

countries2 <- ms_simplify(countries, keep = 0.1)
par(mar = c(0.5,0.5,1.5,0.5))
plot(st_geometry(countries2), col="#d1a2d3")

BIBLIO

  • BEGUIN Michèle, PUMAIN Denise, La représentation des données géographiques, Statistique et cartographie, coll. Cursus, Armand Colin, nouvelle édition 2000, 192p.
  • BERTIN Jacques, Sémiologie graphique, Monton-Gauthier-Villars, 1967, 1973, 432 p. Disponible à ce jour dans la collection Réimpression de l’EHESS, 1998.
  • BERTIN Jacques, La graphique et le traitement graphique de l’information, Flammarion, 1977, 280 p.
  • BRUNET Roger, La carte mode d’emploi, Fayard-Reclus, 1987, 270p.
  • ElementR (Groupe), R et espace, traitement de l’information géographique, 2014, Framabook.
  • GIRAUD Timothée : Carnet de recherche rgeomatic
  • LAMBERT Nicolas : Carnet de recherche neocarto
  • LAMBERT Nicolas, ZANIN Christine : « Manuel de cartographie. Principes, méthodes, applications », cursus, Armand Colin, 18 mai 2016, 224p.
  • MONMONNIER Mark, Comment faire mentir les cartes ou du mauvais usage de la géographie, University of Chicago Press, 1991, 256 p.
  • ZANIN Christine, TREMELO Marie-Laure, Savoir faire une carte, Aide à la conception et à la réalisation d’une carte thématique univariée, coll. Sup géographie, Belin, 2003, 200p.

— R infos —

Version de R

R.version
##                _                           
## platform       x86_64-pc-linux-gnu         
## arch           x86_64                      
## os             linux-gnu                   
## system         x86_64, linux-gnu           
## status                                     
## major          3                           
## minor          4.4                         
## year           2018                        
## month          03                          
## day            15                          
## svn rev        74408                       
## language       R                           
## version.string R version 3.4.4 (2018-03-15)
## nickname       Someone to Lean On

Session

sessionInfo()
## R version 3.4.4 (2018-03-15)
## Platform: x86_64-pc-linux-gnu (64-bit)
## Running under: Ubuntu 18.04.1 LTS
## 
## Matrix products: default
## BLAS: /usr/lib/x86_64-linux-gnu/blas/libblas.so.3.7.1
## LAPACK: /usr/lib/x86_64-linux-gnu/lapack/liblapack.so.3.7.1
## 
## locale:
##  [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C              
##  [3] LC_TIME=fr_FR.UTF-8        LC_COLLATE=en_US.UTF-8    
##  [5] LC_MONETARY=fr_FR.UTF-8    LC_MESSAGES=en_US.UTF-8   
##  [7] LC_PAPER=fr_FR.UTF-8       LC_NAME=C                 
##  [9] LC_ADDRESS=C               LC_TELEPHONE=C            
## [11] LC_MEASUREMENT=fr_FR.UTF-8 LC_IDENTIFICATION=C       
## 
## attached base packages:
## [1] stats     graphics  grDevices utils     datasets  methods   base     
## 
## other attached packages:
## [1] rmapshaper_0.4.0      osmdata_0.0.7.001     countrycode_1.00.0   
## [4] rnaturalearth_0.1.0   SpatialPosition_1.2.0 cartogram_0.1.0      
## [7] cartography_2.1.2     readxl_1.1.0          sf_0.6-3             
## 
## loaded via a namespace (and not attached):
##  [1] Rcpp_0.12.19            lubridate_1.7.4        
##  [3] lattice_0.20-35         png_0.1-7              
##  [5] class_7.3-14            rprojroot_1.3-2        
##  [7] digest_0.6.18           V8_1.5                 
##  [9] mime_0.6                R6_2.3.0               
## [11] cellranger_1.1.0        plyr_1.8.4             
## [13] backports_1.1.2         rnaturalearthdata_0.1.0
## [15] evaluate_0.12           e1071_1.7-0            
## [17] geojson_0.2.0           httr_1.3.1             
## [19] highr_0.7               pillar_1.3.0           
## [21] rlang_0.2.2             lazyeval_0.2.1         
## [23] geojsonlint_0.2.0       curl_3.2               
## [25] rstudioapi_0.8          miniUI_0.1.1.1         
## [27] raster_2.6-7            geojsonio_0.6.0        
## [29] rmarkdown_1.10          rgdal_1.3-4            
## [31] foreign_0.8-69          jqr_1.0.0              
## [33] stringr_1.3.1           questionr_0.6.3        
## [35] shiny_1.1.0             rosm_0.2.2             
## [37] compiler_3.4.4          httpuv_1.4.5           
## [39] xfun_0.3                rgeos_0.3-28           
## [41] htmltools_0.3.6         tibble_1.4.2           
## [43] bookdown_0.7            jsonvalidate_1.0.0     
## [45] crayon_1.3.4            later_0.7.5            
## [47] grid_3.4.4              spData_0.2.9.4         
## [49] jsonlite_1.5            xtable_1.8-3           
## [51] DBI_1.0.0               magrittr_1.5           
## [53] units_0.6-1             rmdformats_0.3.3       
## [55] stringi_1.2.4           promises_1.0.1         
## [57] sp_1.3-1                xml2_1.2.0             
## [59] packcircles_0.3.3       tools_3.4.4            
## [61] abind_1.4-5             yaml_2.2.0             
## [63] maptools_0.9-4          classInt_0.2-3         
## [65] rvest_0.3.2             knitr_1.20

Nicolas Lambert, Ronan Ysebaert

Sète, 16 nov. 2018