Cartographie sous R

Cartographie avec R : Cartes statiques et

dynamiques de une ou plusieurs variables avec R.

Introduction

Un beau graphique vaut mieux qu’un long discours

Carte dans un navigateur

Le package utilisé ici, leaflet, va servir d’interface entre R et la bibliothèque de programmes javascript leaflet. Le principe est de construire la carte grâce à des couches (« layers ») qui se superposent. Commençons par l’affichage de la carte du monde

library(leaflet)
m<-leaflet()
m<-addTiles(m)
print(m)

Après le chargement du package, la fonction leaflet permet de créer un widget de type « map » stocké dans l’objet m. Ce widget contiendra toutes les couches à afficher. Les «tuiles» formant le fond de carte sont ajoutées à l’objet m avec la fonc tion addTiles et forment ainsi une couche. Par défaut, les tuiles sont téléchargées depuis un serveur de tuiles OpenStreetMap. Enfin, l’affichage permet de générer la page html complète (avec le code javascript leaflet) qui est ensuite affichée dans le navigateur par défaut (voir getOption(“browser”)). Une syntaxe plus lisible uti lisant le pipe %>% du package dplyr (voir section 5.2.1) permet d’obtenir la même carte :

m<-leaflet()%>%addTiles()
print(m)

Afin d’initialiser la carte autour de la région d’intérêt, nous pouvons utiliser la fonction setView en utilisant les longitude et latitude de Rochebrune et un zoom de 13

m<-leaflet()%>%
  setView(lng=6.62,lat=45.85,zoom=13)%>%
  addTiles()
m

Ensuite, nous pouvons ajouter des couches d’annotations sur ces fonds de cartes. Ces annotations peuvent être de différentes formes : des cercles, des marqueurs (avec du texte apparaissant quand la souris les pointe), etc. Il s’agit d’un exemple des séismes des Tonga et ajoutons des cercles avec une couleur fonction de la profondeur. Pour cela, nous créons donc le fond de carte selon les étapes classiques : création du widget, centrage dans la zone, spécification du zoom d’intérêt et ajout des tuiles du fond de carte

m <- leaflet(data=quakes) %>%
setView(lng=6.62,lat=45.85,zoom=13) %>%
addTiles()
m

À ce fond de carte à une couche, nous ajoutons les annotations sous forme de cercles (fonction addCircles) positionnés avec les variables long et lat de quakes pour la longitude et la latitude respectivement

m %>% addCircles(~long, ~lat)

Si nous souhaitons colorier les cercles en fonction de la profondeur (variable depth de quakes), il est nécessaire de créer un vecteur de couleurs en RGB. La fonction colorNumeric du package leaflet permet de créer facilement un tel vecteur avec une syntaxe proche de celle utilisée dans ggplot2

pal <- colorNumeric(palette=c(low="yellow2",high="red4"),
domain = quakes$depth)

Cette fonction colorNumeric renvoie comme résultat une fonction (que nous avons nommée ici pal) qui prend comme argument une profondeur et qui renvoie un code couleur linéairement réparti entre le minimum et le maximum de la profondeur observée. Ainsi, cette fonction résultat appliquée aux trois premières profondeurs renvoie bien les couleurs en code RGB

pal(quakes$depth[1:3]) 
[1] "#A03F01" "#911901" "#EEED00"

La carte finale est obtenue en donnant l’argument color aux marqueurs de type cercle

m %>% addTiles() %>%
addCircles(~long,~lat,popup=~mag,color=~pal(depth))

Le caractère dynamique proposé par leaflet permet de construire des cartes sur les quelles des informations pourront être proposées à l’utilisateur lorsqu’il cliquera à certains endroits de la carte.

Nous allons utiliser les données les station Velib à Paris

library(readxl)
# Ouvre un explorateur de fichiers pour choisir le fichier
sta.paris <- read.csv2(file.choose(), encoding = "UTF-8")
summary(sta.paris)
 Identifiant.station    Nom.station   Station.en.fonctionnement
 Min.   : 1001       Length   :1512   Length   :1512           
 1st Qu.:11040       N.unique :1509   N.unique :   2           
 Median :17016       N.blank  :   0   N.blank  :   0           
 Mean   :19179       Min.nchar:   6   Min.nchar:   3           
 3rd Qu.:22408       Max.nchar:  50   Max.nchar:   3           
 Max.   :92008                                                 
 Capacité.de.la.station Nombre.bornettes.libres Nombre.total.vélos.disponibles
 Min.   :  0.0          Min.   : 0.00           Min.   : 0.00                 
 1st Qu.: 23.0          1st Qu.:10.00           1st Qu.: 4.00                 
 Median : 30.0          Median :18.00           Median : 8.00                 
 Mean   : 32.2          Mean   :19.22           Mean   :11.66                 
 3rd Qu.: 38.0          3rd Qu.:27.00           3rd Qu.:16.00                 
 Max.   :105.0          Max.   :97.00           Max.   :70.00                 
 Vélos.mécaniques.disponibles Vélos.électriques.disponibles
 Min.   : 0.000               Min.   : 0.000               
 1st Qu.: 1.000               1st Qu.: 2.000               
 Median : 3.000               Median : 3.000               
 Mean   : 7.235               Mean   : 4.429               
 3rd Qu.:10.000               3rd Qu.: 6.000               
 Max.   :61.000               Max.   :35.000               
 Borne.de.paiement.disponible Retour.vélib.possible Actualisation.de.la.donnée
 Length   :1512               Length   :1512        Length   :1512            
 N.unique :   2               N.unique :   2        N.unique : 441            
 N.blank  :   0               N.blank  :   0        N.blank  :   0            
 Min.nchar:   3               Min.nchar:   3        Min.nchar:  25            
 Max.nchar:   3               Max.nchar:   3        Max.nchar:  25            
                                                                              
 Coordonnées.géographiques Nom.communes.équipées Code.INSEE.communes.équipées
 Length   :1512            Length   :1512        Min.   :75056               
 N.unique :1512            N.unique :  69        1st Qu.:75056               
 N.blank  :   0            N.blank  :   0        Median :75056               
 Min.nchar:  15            Min.nchar:   4        Mean   :81170               
 Max.nchar:  38            Max.nchar:  21        3rd Qu.:92044               
                                                 Max.   :95018               
 station_opening_hours
 Mode:logical         
 NAs :1512            
                      
                      
                      
                      

La fonction addCircleMarkers permetde localiser les stationsdevélos sur une carteleaflet en ajoutant un cercle aux longitudes et latitudes des stations de la basesta.paris

library(tidyr)
library(dplyr)

Attachement du package : 'dplyr'
Les objets suivants sont masqués depuis 'package:stats':

    filter, lag
Les objets suivants sont masqués depuis 'package:base':

    intersect, setdiff, setequal, union
# Étape 1 : Séparer "Coordonnées.géographiques" en lat et lon
sta.paris <- sta.paris %>%
  separate(`Coordonnées.géographiques`, 
           into = c("lat", "lon"), 
           sep = ",") %>%
  mutate(
    lat = as.numeric(lat),
    lon = as.numeric(lon)
  )
# Étape 2 : Vérifier
head(sta.paris[, c("lat", "lon")])
       lat      lon
1 48.87837 2.440524
2 48.83753 2.336035
3 48.81943 2.343335
4 48.93627 2.358867
5 48.85591 2.392571
6 48.87545 2.315508
leaflet(data=sta.paris)%>% addTiles()%>%
addCircleMarkers(~lon,~lat,radius=8,stroke=FALSE,
fillOpacity=0.5,color="blue")

On utilisera l’argument popupdeaddCircleMarkers pour ajouter des informations relatives aux stations sur lesquelles l’utilisateur cliquera. On peut par exemple obtenir le nombre de vélos disponibles de la station à l’aide de

leaflet(data=sta.paris)%>% addTiles()%>%
addCircleMarkers(~lon,~lat,radius=8,stroke=FALSE,
fillOpacity=0.5,color="red",popup=~paste("<b>
Vélos dispos:</b>",as.character('Nombre.total.vélos.disponibles')))

Carte avec contours : le format shapefileHeading

Nous allons maintenant utiliser des fonds de cartes de type « shapefile »2 qui ne font figurer que les contours (donc des polygones), par exemple ceux des dé partements français. Ces fonds de cartes permettent de représenter une variable quantitative ou qualitative en coloriant à l’intérieur des contours.

En guise d’exemple, nous analysons graphiquement les différences de taux de chô mage par département en France

library(readr)

taux_chomage <- read_delim(
  "https://husson.github.io/livre_StatR/tauxchomage.csv",
  delim = ";"
)
Rows: 96 Columns: 5
── Column specification ────────────────────────────────────────────────────────
Delimiter: ";"
chr (2): CODE_DEPT, NOM_DPT
dbl (3): TCHOMB1T01, TCHOMB1T06, TCHOMB1T11

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.

Pour le fond de carte, nous nous servons de la carte GEOFLAR ⃝ proposée par l’Institut Géographique National et du package “sf”

library(sf)
Linking to GEOS 3.14.1, GDAL 3.12.1, PROJ 9.7.1; sf_use_s2() is TRUE
library(tidyverse)
── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
✔ forcats   1.0.1     ✔ purrr     1.2.2
✔ ggplot2   4.0.3     ✔ stringr   1.6.0
✔ lubridate 1.9.5     ✔ tibble    3.3.1
── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag()    masks stats::lag()
ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
# 1. Créer un dossier data s'il n'existe pas
dir.create("data", showWarnings = FALSE)

# 2. Télécharger le fond de carte des départements
download.file(
  url = "https://lrouviere.github.io/VISU/dpt.zip",
  destfile = "data/dpt.zip",
  mode = "wb"
)

# 3. Décompresser le fichier
unzip("data/dpt.zip", exdir = "data/dpt")

# 4. Importer le shapefile avec sf
dpt <- read_sf("data/dpt")

# 5. Afficher la carte
ggplot(dpt) +
  geom_sf() +
  theme_minimal()

L’importation via read_sf prend directement en compte le système de coordonnées utilisé par l’IGN

Si nous souhaitons analyser les taux de chômage par département et les représenter sur la carte, nous devons fusionner le tibble chomage (qui contient les deux taux de chômage par département) avec les données de dpt (qui contiennent la carte). Pour s’assurer que la fusion est faite par département, nous effectuons une jointure

dpt2 <- inner_join(dpt,taux_chomage,by="CODE_DEPT")
dpt2
Simple feature collection with 96 features and 15 fields
Geometry type: MULTIPOLYGON
Dimension:     XY
Bounding box:  xmin: 99226 ymin: 6049647 xmax: 1242375 ymax: 7110524
Projected CRS: RGF93 Lambert 93
# A tibble: 96 × 16
   ID_GEOFLA CODE_DEPT NOM_DEPT           CODE_CHF NOM_CHF X_CHF_LIEU Y_CHF_LIEU
       <dbl> <chr>     <chr>              <chr>    <chr>        <int>      <int>
 1         1 01        AIN                053      BOURG-…       8717      65696
 2         2 02        AISNE              408      LAON          7451      69406
 3         3 03        ALLIER             190      MOULINS       7254      66072
 4         4 04        ALPES-DE-HAUTE-PR… 070      DIGNE-…       9590      63379
 5         5 05        HAUTES-ALPES       061      GAP           9443      63891
 6         6 06        ALPES-MARITIMES    088      NICE         10439      62985
 7         7 07        ARDECHE            186      PRIVAS        8266      64052
 8         8 08        ARDENNES           105      CHARLE…       8239      69649
 9         9 09        ARIEGE             122      FOIX          5862      62083
10        10 10        AUBE               387      TROYES        7799      68003
# ℹ 86 more rows
# ℹ 9 more variables: X_CENTROID <int>, Y_CENTROID <int>, CODE_REG <chr>,
#   NOM_REGION <chr>, geometry <MULTIPOLYGON [m]>, NOM_DPT <chr>,
#   TCHOMB1T01 <dbl>, TCHOMB1T06 <dbl>, TCHOMB1T11 <dbl>

Enfin, pour utiliser le formalisme de ggplot2, il faut utiliser un jeu de données avec deux colonnes : l’une donnant l’année et l’autre le taux de chômage de l’année. Cette remise en forme est obtenue grâce à la fonction gather du package tidyr

library(tidyr)
dpt3<-dpt2%>% select(A2006=TCHOMB1T06,A2011=TCHOMB1T11,geometry)%>%
gather("Annee","TxChomage",-geometry)
class(dpt3)
[1] "sf"         "tbl_df"     "tbl"        "data.frame"

La représentationdes taux de chômage par département d’une ou de plusieurs années peut alors être obtenue grâce aux fonctions du packageggplot2

library(ggplot2)
ggplot()+ geom_sf(data=dpt3, aes(fill=TxChomage))+
facet_wrap(~Annee,nrow=1)+
scale_fill_gradient(low="white",high="brown")+theme_bw()

library(rnaturalearth)
library(rnaturalearthdata)

Attachement du package : 'rnaturalearthdata'
L'objet suivant est masqué depuis 'package:rnaturalearth':

    countries110
cameroun <- ne_states(country = "Cameroon", returnclass = "sf")
plot(st_geometry(cameroun))