Maps - Leaflet Map - Carte choroplèthe

Utilisation d'une couche de données geoJSON pour construire une carte choroplèthe avec informations dynamiques et légende des couleurs utilisées
Sources :

Introduction

Cette carte représente les données de la population des pays d'Afrique en 2017. Pour la construire nous avons utilisé uniquement la librairie Leaflet. Dans ce tutoriel nous allons étudier les sujets suivants :

  • Construction de la carte
  • Ajout d'une couche de données (Layer)
  • Gestion des évènements de la souris (interaction)
  • Ajout d'une légende

Construction de la carte

La construction d'une carte Leaflet a déjà été décrite dans un tutoriel précédent. Voici le code javascript utilisé pour cette cartographie. Notez que la page doit contenir un div HTML dont l'id est map.

let map = L.map('map').setView([1.2, 17], 4);
	
let OpenStreetMap_France = L.tileLayer('https://{s}.tile.openstreetmap.fr/osmfr/{z}/{x}/{y}.png', {
	maxZoom: 20,
	attribution: '© Openstreetmap France | © OpenStreetMap contributors'
});
	
map.addLayer(OpenStreetMap_France);

La carte est centrée sur l'Afrique avec un niveau de zoom adapté (4). Nous utilisons un fournisseur de Tiles qui permet d'avoir les libellés des pays en français sur la carte. Si vous souhaitez utiliser un autre fond de carte vous pouvez regarder le site Leaflet Providers qui fournit une longue liste de fonds de carte, cette liste est souvent mise à jour. Comme la carte est directement ajoutée dans cette page nous avons dû ajouter du CSS pour en définir les dimensions.

#map {
	width: 100%;
	height: 900px;
	margin-bottom: 10px;
}

Ajout d'une légende dynamique

Pour ajouter la légende qui apparait en haut à droite nous utilisons la classe L.control de Leaflet. Nous créons donc une variable info qui possède deux fonctions.

  • onAdd: C'est la fonction d'initialisation qui est appelée lorsqu'on ajoute cet objet à la carte. Elle permet de construire le div HTML qui contiendra la légende. Ce div est associé à la classe CSS info.
  • update: C'est la fonction qui est appelée pour chaque pays. Elle prend en entrée les propriétés du pays et permet de définir le contenu dynamiquement en HTML. On peut noter que si la variable props n'est pas fournie la légende affiche l'indication : Passer la souris sur un pays.

var info = L.control();

info.onAdd = function (map) {
	this._div = L.DomUtil.create('div', 'info');
	this.update();
	return this._div;
};

info.update = function (props) {
	this._div.innerHTML = '<h5>Population des pays d\'Afrique</h5>' +  (props ?
		'<b>' + props.name + '</b><br />' + props.population.toLocaleString()  + ' habitants'
		: 'Passer la souris sur un pays');
};

info.addTo(map);

Nous devons également définir du CSS afin d'obtenir le panneau d'information voulu.

.info {
	padding: 6px 8px;
	font: 14px/16px Arial, Helvetica, sans-serif;
	background: white;
	background: rgba(255,255,255,0.8);
	box-shadow: 0 0 15px rgba(0,0,0,0.2);
	border-radius: 5px;
}

.info h5 {
	margin: 0 0 5px;
	color: #777;
}

Il faut bien voir que vous pouvez faire ce que vous voulez ici, le contenu de ces légendes étant de l'HTML on peut y mettre tout ce qu'on veut. Voir par exemple notre tutoriel dédié à la manipulation de cette classe L.control.

Ajout d'une légende statique sur les couleurs

De la même manière nous définissons un autre objet L.control pour la légende qui apparait en bas à droite. Le tableau grades définit l'échelle associée à nos données. Ici la population de chaque pays va de 0 à plus de 150 millions d'habitants. Notez que le div créé possède à la fois la classe info et la classe legend.

var legend = L.control({position: 'bottomright'});

legend.onAdd = function (map) {

	var div = L.DomUtil.create('div', 'info legend'),
		grades = [0, 10, 20, 40, 60, 80, 100, 150];

	div.innerHTML += '<h6>En millions</h6>';
	for (var i = 0; i < grades.length; i++) {
		div.innerHTML +=
			'<i style="background:' + getColor((grades[i] + 1) * 1000000) + '"></i> ' +
			grades[i] + (grades[i + 1] ? 'M – ' + grades[i + 1] + 'M <br>' : '+');
	}

	return div;
};

legend.addTo(map);

Il y a également une partie CSS pour cette légende afin d'avoir des carrés de couleurs verticaux d'une taille précise.

.legend {
	line-height: 18px;
	color: #555;
}
	
.legend i {
   	width: 18px;
   	height: 18px;
   	float: left;
   	margin-right: 8px;
   	opacity: 0.7;
}

Ajout d'une couche de données

Pour matérialiser les limites de chaque pays nous devons utiliser un fichier geoJSON qui décrit les contours de chaque pays d'Afrique. Nous avons récupéré le nôtre sur ce dépôt Github. Leaflet sait interpréter ce format et ajouter une couche (Layer) à partir de ces données. Nous avons ensuite récupéré les données de population de chaque pays qu'on a ajouté directement dans le fichier geoJSON au niveau des propriétés. Voici par exemple le contenu correspondant aux Comores.

{
    "type": "Feature",
    "properties": {
        "name": "Comores",
        "cartodb_id": 11,
        "created_at": "2013-11-12T16:15:59+0100",
        "updated_at": "2013-11-12T16:15:59+0100",
		"population": 813912
    },
    "geometry": {
        "type": "MultiPolygon",
        "coordinates": [
          [
            [
              [
                43.453971,
                -11.936572
              ],
              [
                43.220752,
                -11.765725
              ],
              [
                43.250582,
                -11.440304
              ],
              [
                43.369903,
                -11.371151
              ],
              [
                43.453971,
                -11.936572
              ]
            ]
          ]
        ]
    }
	<
}

Le fichier produit peut être récupéré ici. Comme nous ne voulons pas utiliser d'autres librairies que Leaflet et parce que Leaflet ne sait pas charger un fichier nous avons créé le fichier africa.js qui définit la variable data avec comme contenu le geoJSON. Ce fichier doit être importé dans la page ou la carte est représentée. Avec JQuery ou tout autre framework javascript vous pourrez charger le fichier geoJSON directement depuis votre serveur. Nous ajoutons donc notre couche de données à la carte avec le code suivant.

let geoJSONLayer = L.geoJson(data, { 
    style: style,
    onEachFeature: onEachFeature
}).addTo(map);

Nous avons fourni deux paramètres supplémentaires au constructeur, ils correspondent à deux fonctions permettant de rendre la carte dynamique.

  • style: Premet d'associer un style CSS à chaque feature (chaque pays) de nos données. C'est elle qui définit la couleur du pays en fonction du nombre d'habitants.
  • onEachFeature: Permet de gérer la souris et de montrer le chiffre de la population ainsi que le nom du pays dans la fenêtre d'information en haut à droite.
La fonction style retourne un objet qui définit les paramètres d'affichage du pays. Elle est associée à la fonction getColor qui fournit la couleur à utiliser en fonction de la population du pays. La liste des couleurs provient du site Color Brewer qui permet d'obtenir des palettes de couleurs dédiées à la cartographie.

function style(feature) {
	return {
		fillColor: getColor(feature.properties.population),
		weight: 2,
		opacity: 1,
		color: 'white',
		dashArray: '3',
		fillOpacity: 0.7
	};
}

function getColor(d) {
	return d > 150000000 ? '#800026' :
		d > 1000000000  ? '#BD0026' :
		d > 80000000  ? '#E31A1C' :
		d > 60000000  ? '#FC4E2A' :
		d > 40000000   ? '#FD8D3C' :
		d > 20000000   ? '#FEB24C' :
		d > 10000000   ? '#FED976' :
		'#FFEDA0';
}

Finalement il nous reste à définir la fonction onEachFeature avec le code ci-dessous. Cette fonction va associer deux évènements de la souris (mouseover et mouseout) à chaque feature de notre couche de données. Ainsi lorsque l'on passe la souris sur un pays la fonction highlightFeature est appelée. Elle modifie les contours du pays pour le mettre en évidence et appelle la fonction update de notre fenêtre d'information pour afficher les données du pays. A l'inverse la fonction resetHighlight permet de revenir au style d'origine et de réinitialiser les informations lorsque l'on quitte le pays avec la souris.

function onEachFeature(feature, layer) {
	layer.on({
		mouseover: highlightFeature,
		mouseout: resetHighlight
	});
}

function highlightFeature(e) {
	var layer = e.target;

	layer.setStyle({
		weight: 5,
		color: '#666',
		dashArray: '',
		fillOpacity: 0.7
	});

	if (!L.Browser.ie && !L.Browser.opera && !L.Browser.edge) {
		layer.bringToFront(); // Permet de garantir que le pays est au-dessus des autres couches de données
	}

	info.update(layer.feature.properties);
}

function resetHighlight(e) {
	geoJSONLayer.resetStyle(e.target);
	info.update();
}

Conclusion

Nous avons pu voir dans ce tutoriel comment construire une carte choroplèthe uniquement grâce à la librairie Leaflet. Néanmoins cette librairie montre aussi ses limites : impossible de charger un fichier et le fait de devoir construire manuellement la légende de couleurs. Sur ce site vous pouvez également voir des tutoriels sur la librairie D3JS, celui sur la population française montre tout l'intérêt de cette librairie avec un chargement natif des fichiers geoJSON et surtout la possibilité de construire dynamiquement des échelles de valeurs ou de couleurs. Mais cet exemple ne possède pas de fond de carte. Il est néanmoins possible de combiner les deux comme le montre le tutoriel sur le diagramme de Voronoï qui ajoute au-dessus de la carte un Layer dont le contenu est construit avec D3JS.

COMMENTAIRES

Tom Moneghetti


Bonjour,

Pour ma part, j'ai dû rajouter un i dans le code de la légende pour voir apparaître les carrés de couleur (voir photo)

https://uploads.disquscdn.c...

ericfrigot


Bonjour et merci de laisser un commentaire pour remonter cette coquille ! C'est corrigé. Bonne journée, Eric