Cartographier pour le web avec la bibliothèque JavaScript bertin

SAGEO, 2023 - Québec, Canada

Nicolas Lambert, Timothée Giraud, Matthieu Viry, Ronan Ysebaert

07 Jun 2023

Introduction



bertin est une bibliothèque écrite en JavaScript qui permet de réaliser des cartes thématiques pour le web.


Sa conception vise à permettre aux utilisateurs de créer rapidement des cartes thématiques interactives sans forcement connaître le langage JavaScript

Le développemement de bertin est intimement lié au développement de la plateforme de notebooks Observable.

Introduction

Observable est aussi une startup fondée par Mike Bostock et Melody Meckfessel, qui propose une plateforme 100% en ligne pour concevoir, partager et diffuser des visualisations de données.

L’Observable javascript (ojs) est un ensemble d’améliorations apportées à vanilla JavaScript créé par Mike Bostock (également auteur de D3). Observable JS se distingue par son exécution réactive, qui convient particulièrement bien à l’exploration et à l’analyse interactives des données. Objectif : faire collaborer une communauté autour de la visualisation de données.

Observable, c’est aussi une plateforme web qui héberge des notebooks computationnels sur la visualisation de données.

NB : Cette présentation est réalisée avec Quarto (qui implémente l’ojs)

Introduction

Introduction

La bibliothèque bertin 🗺️

Une bibliothèque JavaScript pour la cartographie thématique

Principes

Le développement de la bibliothèque bertin s’appuie en grande partie sur le librairie javascript d3.js développée par Mike Bostock depuis 10 ans. Le développement a débuté en novembre 2021. Il y a 8 contributeurs. 256 ⭐ sur Github.

Pour charger la bibliothèque :

<script src="https://cdn.jsdelivr.net/npm/bertin" charset="utf-8"></script>

Dans Observable, on utilise require

bertin = require("bertin@1.7.3")

Principes


Elle permet de réaliser
de nombreux types de cartes thématiques.

Parti pris :

👉 cartographie vectorielle

👉 cartographie interactive pour le web

👉 une recherche esthétique

👉 plutôt à partir de maillages administratifs

👉 plutôt avec des données pas trop volumineuses

👉 forte intégration avec l’écosystème d’Observable

Principes

Le principe de la bibliothèque bertin est de proposer un outil permettant de réaliser rapidement des cartes thématiques variées sans faire appel à la programmation en JavaScript ni directement à la bibliothèque D3.js.

Les données en entrée

La bibliothèque bertin prend en entrée des données JSON, GeoJSON ou topoJSON.

Les données


Le fond de carte


La fonction match() permet de tester la compatibilité entre les données et le fonde de carte.

bertin.match(world, "id", stats, "iso3c")

La fonction merge() permet d’effectuer la jointure

world2019 = bertin.merge(world, "id", stats, "iso3c")

La fonction quickdraw()

La fonction quickdraw() permet de visualiser la carte dans la projection d3.geoEquirectangular().

bertin.quickdraw(world2019)


La fonction draw()

On utilise la fonction draw() pour dessiner tous les types de cartes. La fonction prend en entrée un objet JavaScript contenant toutes les informations nécéssaires.

L’ordre des couches définit l’ordre d’affichage. Ce qui est écrit au dessus s’affiche au dessus.

La fonction draw()

Polygones (syntaxe minimale)

bertin.draw({ layers: [ {geojson: world2019} ] })


La fonction draw()

Points (syntaxe minimale)

bertin.draw({ layers: [ {geojson: cities} ] })


La fonction draw()

Lignes (syntaxe minimale)

bertin.draw({ layers: [ {geojson: cables} ] })


Habillage et mise en page️

Définir les styles

Le rendu peut être très largement paramétré.

bertin.draw({ 
  layers: [
          { 
      geojson: cities,
      symbol: "square",
     }, 
      { 
      geojson: cables,
      strokeWidth: 2
    }, 
    { 
      geojson: world2,
      fill: "#F6836F",
    }
  ]
})

Les styles (couleurs, transparence, épaisseur, etc) reprennent les noms des attributs SVG.

Mise en page

En plus des couches, la fonction draw prend en entrée des paramètres généraux.

bertin.draw({ 
  params: {background: "red", width: 500, margin:[10, 0, 0, 10]},
  layers: []
})


Les projections

La bibliothèque bertin s’appuie sur l’écosystème de d3. Elle bénificie donc des projections disponible dans d3.geo et d3.geoprojection.



bertin.draw({ 
  params: {projection: ""},
  layers: []
})


Si on choisit la projection “globe”, on obtient un globe interactif.


La librairie bertin permet également d’utiliser des projections au format proj4 ou epsg.

Couches d’habillage

Outline

Le type outline permet d’afficher l’espace terrestre.

{type: "outline" }


Couches d’habillage

Geolines

Le type geolines permet d’afficher l’équateur, les tropiques et les cercles polaires

{type: "geolines"}


Couches d’habillage

Graticule

Le type graticule permet d’afficher les lignes de latitude et de longitude.

{type: "graticule", step: [10,20]}


Couches d’habillage

Waterlines

Le type waterlines permet d’afficher des lignes autour des terres, comme sur les cartes anciennes

{type: "waterlines", geojson: world, nb: 5}


Couches d’habillage

Rhumbs

Le type rhumbs crée des pseudo lignes de rhumbs pour reproduire des styles de cartes anciennes (portulans)

{type: "rhumbs", position: [200, 100], nb: 25}


Couches d’habillage

Hatch

Le type hatch permet d’ajouter des hachures et une texture à la carte. C’est uniquement esthétique.

{type: "Hatch", angle: 45, spacing: 4 }


Couches d’habillage

Shadow

Le type shadow permet d’ajouter une ombre sous une couche

{type: "shadow" }


Couches d’habillage

Inner

Le type inner permet d’ajouter un effet de dégradé sur les contours. C’est très utilisé en cartographie d’édition.

{type: "inner" }


Couches d’habillage

Tissot

Le type tissot permet d’afficher l’indicatrice de Tissot et visualiser les déformations induites par l’usage d’une projection cartographique.

{type: "tissot" }


Couches d’habillage

Echelle

Le type scalebar permet d’afficher l’échelle.

{type: "scalebar" }


Couches d’habillage

Carte de localisation

Le type minimap permet d’afficher une carte de localisation

{type: "minimap" }


Couches d’habillage

tiles

Le type tiles permet d’afficher des tuiles raster, mais uniquement dans la projection Web Mercator.

{type: "tiles", style: "worldimagery" }


Couches d’habillage

Le type logo vous permet d’afficher une image sur la carte.

{type : "logo", url: "http://myimage.png", position: "left"}


Textes

Le type header permet d’ajouter un titre

{type: "header", text:"" }


Textes

Le type footer permet d’ajouter une note de bas de page (source, auteur…)

{type: "footer", text:"" }


Textes

text

le type text parmet d’ajouter du texte n’importe où sur la carte

{type: "text", position : [100,200], text: "Mon texte ici" }


Textes

Labels

Le type label permet d’afficher du texte lié au fond de carte.

{type : "label", geojson : regions, values: "id"}


Textes

Infobulles

Chaque couche basée sur des données parmet l’affichage d’infobulles

{geojson : world , tooltip:["$name", "$continent", "$subregiond"] }


Symbologie

Symboles proportionnels

Cercles

Pour réprésenter des données quantitatives absolues, on utilise la variable visuelle TAILLE. En pratique, cela revient la plupart du temps à utiliser des cercles proportionnels. Dans bertin, on utilisera alors le type bubble.

{type "bubble", geojson : world, values: "pop", dorling: false}


Symboles proportionnels

Carrés

Pour réprésenter des données quantitatives absolues, on utilise la variable visuelle TAILLE. En pratique, On peut aussi utiliser des carrés proportionnels. Dans bertin, on utilisera alors le type square.

{type "square", geojson : world, values: "pop", demers: false}


Symboles proportionnels

Spikes

Pour réprésenter des données quantitatives absolues, on utilise la variable visuelle TAILLE. En pratique, On peut aussi utiliser la hauteur. Dans bertin, on utilisera alors le type spikes.

{type "spikes", geojson : world, values: "pop"}


Aplats de couleurs

Typologies

Pour réprésenter des données quanlitatvives absolues, on utilise la variable visuelle COULEUR. Dans bertin, on utilisera alors le type typo pour faire varier dynamiquement les couleurs.

{geojson: world, fill: { type: "typo", values: "regions", colors: "Tableau10" } }


Aplats de couleurs

Choroplèthes

Pour réprésenter des données quanlitatvives relatives, on utilise la variable visuelle VALEUR. Dans bertin, on utilisera alors le type choro pour faire varier dynamiquement les couleurs.

{geojson: world, fill: { type: "choro", values: "gdppc", colors: "BuPu" } }


Combinaisons

Par supperposition

Avec le système de couches, il est facile de combiner des variables dont la figuration est différente.


layers : [
  {
    type "bubble", 
    geojson: world,
    values: "pop",
    fill: "none"
  }, 
  {
    geojson: world,
    fill: {
          type:"typo",
          values: "continent"
          }
  }
]

Combinaisons

Symboles colorés (fill)

On peut aussi choisir de colorier des symboles en modifiant l’attribut fill.



layers : [
  {
    type "bubble", 
    geojson: world,
    values: "pop",
    fill: { type: "typo", values: "regions" }
  }
]

Combinaisons

Symboles colorés (stroke)

De la même façon, on peut colorier les contours.



layers : [
  {
    type "bubble", 
    geojson: world,
    values: "pop",
    stroke: { type: "typo", values: "regions" }
  }
]

Combinaisons

Combiner 2 données de stock

La méthode la plus simple est de réaliser 2 cartes en vis à vis


Combinaisons

Combiner 2 données de stock

Le type mushroom permet de représenter 2 variables quantitatives


{
  type: "mushroom",
  geojson: world02bis,
  top_values: "gdp_pct",
  bottom_values: "pop_pct"
}

Autres représentations

Cartes par points

La première carte de densité de points a été conçue par Armand Joseph Frère de Montizon en 1830. Elle consiste à déterminer la valeur d’un point et d’en placer autant que le nombre nécéssaire pour atteindre une quantité.

Avec le type dotdensity, on positionne les points de façon aléatoire dans les mailles adminstratives.

{
  type: "dotdensity", 
  geojson: world,
  values: "pop",
  dotvalue : 5000000
}


Autres représentations

Cartes par points

La première carte de densité de points a été conçue par Armand Joseph Frère de Montizon en 1830. Elle consiste à déterminer la valeur d’un point et d’en placer autant que le nombre nécéssaire pour atteindre une quantité.

Avec le type dotcartogram, on positionne les points au niveau des centroides

{
  type: "dotcartogram",
  geojson: world,
  values: "pop",
  onedot:5000000,
  radius: 5
}


Autres représentations


La bibliothèque bertin permet de passer de mailles irrégulières (maillage administratif) à des mailles régulières (carrés).

Cela permet de réaliser de nouveaux types de représentation.

Autres représentations

Carroyages

Le type regulargrid permet de passer d’un maillage administratif à une grille régulière.

{
  type : "regulargrid",
  geojson: world,
  values: ["gdp","pop"]
}


Autres représentations

“Points Bertin”

Le type regularbubble de répartir des cercles proportionnels régulièrement sur la carte


{
  type : "regularbubble",
  geojson: world,
  values: "pop",
  step:50,
  k:10
}

Autres représentations

“Carrés réguliers”

Sur le même principe, on peut utiliser le type regularsquare


{
  type : "regularsquare",
  geojson: world,
  values: "pop",
  step:50,
  k:10
}

Autres représentations

“Ridgelines”

Avec le type Ridgelines, on peut représenter ces données sur grilles sous la forme d’une fausse 3D.


{
  type : "ridge",
  geojson: world,
  values: "pop",
  step: 30, // espacement
  blur: 0.4, // flou
  k: 50 // hauteur
}

Autres représentations

Cartes de chaleur

Avec le type smooth, on peut représenter ces données de façon continue dans l’espace.


{
  type: "smooth",
  values: "pop",
  bandwidth: 30,
  thresholds: 20
}

Autres représentations

Cartes de chaleur

Même chose en répartissant les masses sur une grille régulière


{
  type: "smooth",
  values: "pop",
  grid_step: 10,
  bandwidth: 30,
  thresholds: 20
}

Interactivité

Viewof

la bibliothèque bertin a été pensée pour être utilisée dans l’écosystème Observable. Ainsi, dans cet environnement, on peut utiliser l’instruction viewof pour transformer n’importe quelle carte en Input.

viewof map = bertin.draw({
  layers: [{geojson: world}]
})

map

Par défaut, ce sont les latitudes et les longitudes qui sont renvoyées.

Viewof

Mais on peut aussi utiliser l’instruction viewof sur n’importe quelle couche.

map = bertin.draw({
  layers: [
    { 
      geojson: world,
      viewof: true
    }
  ]
})

map

Ainsi, les données liées à cette couche sont renvoyées

Viewof

Cela permet de faire dialoguer la carte avec d’autres éléments graphiques

La fonction update

Sur chaque type de couche, une fonction update() permet de mettre à jour certains éléments de la carte sans avoir besoin de tout redessiner. Pour cela, il est nécessaire d’affecter un identifiant à chaque couche qu’on souhaite modifier.


Input
viewof color = Inputs.color({ value: "#487294" })



Carte
map = bertin.draw({
  layers: [
    {
      id: "mylayer",
      geojson: world,
      fill: "#487294"
    },
    { type: "graticule" },
    { type: "outline" }
  ]
})


Fonction update

map.update({
  id: "mylayer",
  attr: "fill",
  value: color,
  duration: 500
})

La fonction update

On peut utiliser la fonction update() pour masquer/afficher des couches.


{
  layers.forEach((d) => {
    map.update({
      id: d,
      attr: "visibility",
      value:
        checkboxes.includes(d),
      duration: duration
    });
  });
}

La fonction update




map.update({
  id: "bub",
  attr: "k",
  value: k,
  duration: 500
})
map.update({
  id: "bub",
  attr: "values",
  value: val,
  duration: 500
})
map.update({
  id: "bub",
  attr: "dorling",
  value: toggle,
  duration: 500
})

La fonction update




La but est de pouvoir faire ce type de visualisations en quelques lignes de code



Choisissez un indicateur


Faites varier la hauteur

Conclusion

Documentation

Exemples

Bertin dans R

library(bertin)
world <- st_read(system.file("gpkg/world.gpkg", package = "bertin"),
                 layer = "world", quiet = TRUE)
bt_param(width = 800)|>
  bt_layer(data = world, fill = "#808080") |>
  bt_bubble(data = world, values = "pop", k = 20) |>
  bt_draw() |> 
  bt_save("map.svg")

Merci


Nicolas Lambert, Timothée Giraud, Matthieu Viry et Ronan Ysebaert

👉 Code et documentation : github.com/neocarto/bertin
👉 Exemples : observablehq.com/collection/@neocartocnrs/bertin
👉 Issues : github.com/neocarto/bertin/issues


Cette présentation est disponible ici : neocarto.github.io/bertin-sageo2023