Produire des cartes avec

Author

Lino Galiana

Onyxia

Dérouler les slides ci-dessous ou cliquer ici pour afficher les slides en plein écran.

Dans ce TP, nous allons apprendre à créer des cartes avec . A mesure que devient incontournable auprès des personnes manipulant des données spatiales, les solutions pour produire des cartes de qualité deviennent de plus en plus nombreuses. a de moins en moins à envier aux logiciels spécialisés comme QGIS.

Si vous êtes intéressés par Python , une version très proche de ce TP est disponible dans mon cours de l’ENSAE.

Note

Produire de belles cartes demande du temps mais aussi du bon sens. Comme toute représentation graphique, il est important de réfléchir au message à faire passer et aux moyens appropriés. La sémiologie cartographique, une discipline scientifique qui s’intéresse aux messages transmis par les cartes, propose certaines règles pour éviter de transmettre des messages faussés, volontairement ou involontairement.

Certaines peuvent être retrouvées à travers des conseils pratiques dans ce guide de sémiologie cartographique de l’Insee. Celles-ci sont reprises dans ce guide.

Cette présentation de Nicolas Lambert présente, à partir de nombreux exemples, quelques principes de la dataviz cartographique.

Ce TP vise à initier:

Dans ce chapitre, nous allons utiliser les packages suivants:

library(dplyr)
library(sf)
library(stringr)
library(archive)
library(ggplot2)
library(glue)
library(ggtext)
library(scales)
library(units)
library(leaflet)
library(cartiflette)

1 Données

Au cours de ce chapitre, nous allons utiliser plusieurs jeux de données pour illustrer différents types de cartes:

  • Des comptages de population ;
  • Les limites départementales de la France métropolitaine ;
  • Les limites communales du Finistère ;
  • Le couvert forestier du département des Landes ;

2 Import des données

Ce TD va proposer un certain nombre de jeux de données intéressants pour la cartographie. Comme l’import de ceux-ci n’est pas le coeur du chapitre, nous proposons directement le code d’import des données.

2.1 Populations légales au niveau départemental

library(readr)
library(dplyr)

# download et unzip pour avoir les fichiers
url_pop_legales = "https://www.insee.fr/fr/statistiques/fichier/6683035/ensemble.zip"
download.file(url_pop_legales, "pop_legales.zip")
unzip("pop_legales.zip")

pop_legales_departements = read_csv2("donnees_departements.csv")
pop_legales_finistere = read_csv2("donnees_communes.csv") %>%
  filter(CODDEP == "29") %>%
  mutate(code_insee = paste0(CODDEP, CODCOM))

2.2 Limites communales et départementales

Nous allons utiliser cartiflette qui facilite la récupération des fonds de carte administratifs de l’IGN.

remotes::install_github("linogaliana/cartiflette-r")

En premier lieu, nous allons récupérer les limites des départements:

library(cartiflette)
departement_borders <- download_vectorfile_url_all(
    crs = 4326,
    values = "metropole",
    borders="DEPARTEMENT",
    vectorfile_format="geojson",
    filter_by="FRANCE_ENTIERE",
    source="EXPRESS-COG-CARTO-TERRITOIRE",
    year=2022)

Pour s’en assurer, une carte peut rapidement être produite:

ggplot(departement_borders) +
  geom_sf(fill = "transparent") +
  theme_void()

On va également récupérer les limites des communes du Finistère avec cartiflette. Voici le code pour ne garder que les communes du Finistère (département 29):

finistere <- download_vectorfile_url_all(
    crs = 4326,
    values = "29",
    borders="COMMUNE",
    vectorfile_format="geojson",
    filter_by="DEPARTEMENT",
    source="EXPRESS-COG-CARTO-TERRITOIRE",
    year=2022)


finistere <- finistere %>% left_join(pop_legales_finistere, by = c("INSEE_COM" = "code_insee") )
Exercice 1: représenter rapidement les frontières pour se placer dans l’espace

On va d’abord faire une carte simple, avec ggplot, des limites communales

  1. En s’inspirant du code précédent, faire la carte du Finistère

Pour en apprendre un peu plus sur les données, on va mettre en oeuvre une carte avec le package leaflet. Celui-ci permettra de créer des visualisations réactives, plus propices à l’exploration de données.

  1. Représenter les limites communales du Finistère avec le package leaflet en utilisant les fonctions suivantes:
    • Afficher un fonds de carte Open Street Map avec la fonction addTiles
    • Afficher les limites des polygones avec la fonction addPolylines
  2. Travailler un peu la couche Polylines en réduisant la taille des bordures et en utilisant le paramètre popup pour afficher le nom de la ville et la population communales

Carte obtenue à la question 1

Solution question 1
ggplot(finistere) +
  geom_sf(fill = "transparent") +
  theme_void()

Carte obtenue à la question 2

Solution question 2
leaflet(finistere) %>% 
  addTiles() %>%
  addPolylines()

Carte obtenue à la question 3

Solution question 3
leaflet(finistere) %>% 
  addTiles() %>%
  addPolylines(
    weight = 2,
    popup = ~paste0(NOM, ": ", PTOT, " habitants")
  )

Les exemples de code ci-dessus illustraient une situation où on ne désire représenter que les limites des polygones dans l’objet sf. C’est une carte utile pour rapidement placer son jeu de données dans l’espace mais ça n’apporte pas d’information supplémentaire. Pour cela, il va être nécessaire d’utiliser les données tabulaires associées à la dimension spatiale.

3 Une carte de couverture forestière

Pour cette partie, nous allons faire une carte du couvert forestier landais à partir de la BD Forêt produite par l’IGN. Cette dernière étant un petit peu volumineuse dans le format shapefile, nous proposons de la récupérer dans un format plus compressé: le geopackage.

Le code suivant peut être utilisé pour cela:

foret <- sf::st_read(
  "https://minio.lab.sspcloud.fr/projet-formation/diffusion/r-geographie/landes.gpkg"
)
Reading layer `landes' from data source 
  `https://minio.lab.sspcloud.fr/projet-formation/diffusion/r-geographie/landes.gpkg' 
  using driver `GPKG'
Simple feature collection with 43094 features and 5 fields
Geometry type: MULTIPOLYGON
Dimension:     XY
Bounding box:  xmin: 334878 ymin: 6274073 xmax: 470942.7 ymax: 6389966
Projected CRS: RGF93 v1 / Lambert-93
Tip
  1. Créer une carte du couvert forestier des Landes à partir des données importées précédemment depuis la BD Forêt
Question 1
ggplot(foret) + geom_sf(fill = "forestgreen", lwd = 0) +
  geom_sf(
    data = departement_borders %>% filter(INSEE_DEP == 40) %>% st_transform(2154),
    color = "black", lwd = 1, fill = "transparent") +
  theme_void() +
  labs(title = "Couvert forestier dans les Landes")

4 Découverte des cartes choroplèthes

La carte par aplat de couleur, dite carte choroplèthes, est l’une des représentations de données géographiques les plus traditionnelles.

D’après Chen et al. (2008), la première représentation de ce type a été proposée par Charles Dupin en 1926 pour représenter les niveaux d’instruction sur le territoire français. L’émergence des cartes choroplèthes est en effet indissociable de l’organisation du pouvoir sous forme d’entités pensées politiques supposées unitaires: les cartes du monde représentent souvent des aplats de couleurs à partir des nations, les cartes nationales à partir d’échelons administratifs (régions, départements, communes, mais aussi Etats ou landers).

La première carte choroplèthes par Dupin (1826).

On peut voir l’émergence pendant le XIXe siècle de la carte choroplèthe comme un moment important de la cartographie, un glissement de l’usage militaire vers l’usage politique. Il ne s’agissait plus exclusivement de représenter le territoire physique mais aussi la réalité socioéconomique, dans des bornes administratives connues de tous.

Malgré toutes ces limites, sur lesquelles nous reviendrons, la carte choroplèthe est tout de même instructive. Savoir en produire une rapidement, pour saisir les principaux faits structurants d’un jeu de données, est particulièrement utile.

Exercice 3: une première carte de la population

L’objectif de cet exercice va être d’enrichir les informations présentées sur la carte des départements.

  1. Utiliser le code ci-dessous pour enrichir notre objet sf des départements d’une variable de population:
population_dep <- departement_borders %>%
  left_join(pop_legales_departements, by = c("INSEE_DEP" = "CODDEP"))
  
population_dep <- population_dep %>%
  mutate(densite = as.numeric(PTOT / set_units(st_area(.), "km2") )) %>%
  mutate(pop_4 = cut(PTOT/1000, breaks = 4)) %>%
  mutate(pop = PTOT)

head(population_dep, 3)
Simple feature collection with 3 features and 18 fields
Geometry type: MULTIPOLYGON
Dimension:     XY
Bounding box:  xmin: 2.958036 ymin: 41.33356 xmax: 9.40804 ymax: 50.0695
Geodetic CRS:  WGS 84
                        ID        NOM_M          NOM INSEE_DEP INSEE_REG
1 DEPARTEM_FXX_00000000001          AIN          Ain        01        84
2 DEPARTEM_FXX_00000000002        AISNE        Aisne        02        32
3 DEPARTEM_FXX_00000000003 CORSE-DU-SUD Corse-du-Sud        2A        94
                            source territoire CODREG                  REG
1 IGN:EXPRESS-COG-CARTO-TERRITOIRE  metropole     84 Auvergne-Rhône-Alpes
2 IGN:EXPRESS-COG-CARTO-TERRITOIRE  metropole     32      Hauts-de-France
3 IGN:EXPRESS-COG-CARTO-TERRITOIRE  metropole     94                Corse
           DEP NBARR NBCAN NBCOM   PMUN   PTOT                       geometry
1          Ain     4    23   393 657856 673801 MULTIPOLYGON (((4.795393 46...
2        Aisne     5    21   799 529374 541176 MULTIPOLYGON (((3.120799 49...
3 Corse-du-Sud     2    11   124 160814 163182 MULTIPOLYGON (((8.597976 41...
    densite      pop_4    pop
1 116.76601 (77.7,720] 673801
2  73.26169 (77.7,720] 541176
3  40.70050 (77.7,720] 163182
  1. En utilisant votre connaissance de ggplot et le modèle ci-dessous, représenter une première carte par aplat de couleur (choropleth map) de la variable pop
# Modèle
ggplot(departement_borders) + geom_sf(fill = "white") + theme_void()

Cette carte étant peu lisible, on propose, en premier lieu, de discrétiser ses couleurs.

  1. Utiliser la variable pop_4 pour voir un petit peu à quoi ressemble une version discrétisée de notre carte de population.

Cela apparaît mieux mais la discrétisation n’est sans doute pas idéale, les catégories étant plutôt hasardeuses. Il vaut mieux utiliser scale_fill_steps qui construit de manière plus pertinente les catégories de couleurs.

  1. Reprendre la carte de la question 2 construite avec la variable continue pop. Appliquer l’échelle de couleur de scale_fill_steps

  2. Il existe aussi la fonction scale_fill_fermenter qui permet de discrétiser une échelle continue. A partir de la palette RdPu, construire une carte discrétisée.

  3. Choisir une des deux approches et travailler cette carte pour la rendre plus esthétique. Par exemple, avec scale_fill_steps, travailler la carte pour la faire ressembler à la chloroplèthe de Dupin. Ce site est pratique pour explorer les palettes de couleurs.

# Question 2
plot_q2_exo1 <- ggplot(population_dep) + geom_sf(aes(fill = pop)) + theme_void()
# Question 3
plot_q3_exo1 <- ggplot(population_dep) + geom_sf(aes(fill = pop_4)) + theme_void()
# Question 4
plot_q4_exo1 <- ggplot(
  population_dep
) + geom_sf(aes(fill = pop)) +
  scale_fill_steps() +
  theme_void()
# Question 5
plot_q5_exo1 <- ggplot(
  population_dep
) + geom_sf(aes(fill = pop)) +
  scale_fill_fermenter(
    n.breaks = 5,
    palette = "RdPu",
    direction = 1,
    labels = label_number(scale_cut = cut_short_scale())
    ) +
  theme_void()
# Question 6
plot_q6_exo1 <- ggplot(
    population_dep
) + geom_sf(aes(fill = pop), color = "white") +
    scale_fill_steps(
        n.breaks = 5, trans = "log",
        low = "white", high = "black",
        labels = label_number(scale_cut = cut_short_scale())
    ) +
    theme_void() +
  labs(fill = "Population")

plot_q6_exo1_bis <- ggplot(
    population_dep
) + geom_sf(aes(fill = densite), color = "white") +
    scale_fill_steps(
        n.breaks = 5, trans = "log",
        low = "white", high = "black",
        labels = label_number(scale_cut = cut_short_scale())
    ) +
    theme_void() +
  labs(fill = "Habitants\n(par km²)")
Carte obtenue à la question 2

Carte obtenue à la question 3

Carte obtenue à la question 4

Carte obtenue à la question 5

Cartes obtenue à la question 6

Avec ggplot2, avec peu de travail sur le style, on obtient déjà une carte déjà intéressante. On voit bien dessus la “diagonale du vide”. Par exemple, les deux cartes dans le style de Dupin (1826):

Carte de la population française

Carte de densité de la population française

La carte de densité est plus représentative de la réalité démographique que la carte ne tenant pas compte des surfaces. Néanmoins elle reste imparfaite pour décrire la très forte concentration de la population dans l’aire parisienne. Pour mieux représenter les phénomènes en présence de zonages de dimension hétérogène, il sera nécessaire d’utiliser une autre représentation cartographique, comme les ronds proportionnels ou les cartogrammes.

Exercice supplémentaire: déplacer les DROM, zoomer sur l’Île de France

Un exercice illustratif à venir

5 D’autres cartes avec mapsf

En soi, il est possible de faire des cartes autres que les aplats de couleurs avec ggplot. Néanmoins, c’est un peu complexe à mettre en oeuvre pour contrôler de manière fine l’étendue des cercles. Heureusement, il existe un package adapté pour cela, construit par des géographes pour des géographes: le package mapsf !

L’exercice suivant va illustrer comment créer ce type de carte.

Exercice 4: représentations alternatives avec mapsf
  1. Recréer une carte choroplèthe avec mapsf en utilisant 4 couleurs dont les valeurs proviennent des quantiles de la distribution des densités

  2. Pour se rendre compte de la nature hautement non-linéaire de notre variable de densité, représenter la même carte avec l’argument breaks égal à equal ou pretty.

  3. Pour s’abstraire du problème de biais visuel lié aux chrolepthes, on peut tester la représentation par ronds proportionnels. Représenter la même information mais en utilisant cette fois des ronds proportionnels.

  4. Cette page propose de nombreuses représentations de données. Reproduire la figure ci-dessous avec notre jeu de données du Finistère

# code-fold: true
# code-summary: Question 1
library(mapsf)
mf_map(
  population_dep, var = "densite", type = "choro", nbreaks = 4,
  pal = "Dark Mint",
  leg_val_rnd = -2,
  breaks = "arith")

# code-fold: true
# code-summary: Question 2
mf_map(
  population_dep, var = "densite", type = "choro", nbreaks = 4,
  pal = "Dark Mint",
  leg_val_rnd = -2,
  breaks = "quantile")

# code-fold: true
# code-summary: Question 3
population_dep_lambert <- population_dep %>% st_transform(2154)
mf_map(population_dep_lambert)
mf_map(population_dep_lambert, var = "densite", type = "prop")
mf_layout(
    title = "Densité en France"
)

# code-fold: true
# code-summary: Question 4
finistere <- finistere %>% st_transform(2154)

mf_map(
  finistere,
  col = "#CCCCCC",
  border = "white",
  lwd = 0.5
)
mf_map(
  finistere, var = "PTOT",
  type = "prop",
  col = "#c291bc",
  border = "#6b4266",
  lwd = 0.5,
  add = TRUE
)
mf_title("Population du Finistère", bg = "#6b4266")
mf_annotation(
      x = c(132040, 6826675),
      txt = "Finistère (29)",
      pos = "bottomleft",
      col_txt = "#6b4266",
      cex = 1.2,
      font = 2,
      halo = TRUE,
      s = 1.5
    )

References

Chen, Chun-houh, Wolfgang Härdle, Antony Unwin, and Michael Friendly. 2008. “A Brief History of Data Visualization.” Handbook of Data Visualization, 15–56.