Les lignes de force du vote RN en 2024 : une cartographie lissée avec la grille H3

Les résultats des dernières élections françaises sont maintenant disponibles à un niveau fin, à la commune et même jusqu’au bureau de vote. Mais comment produire une cartographie lisible et synthétique à partir de données si détaillées ?

Ce travail récent de Karim Douïeb, largement repris, illustre bien le dilemme : il dénonce le caractère trompeur de la carte (choroplèthe) de gauche et propose à la place la variante (à symboles) de droite.

Les cartes choroplèthes sont faciles à lire avec leur coloration continue de tout le territoire. Mais l’œil voit seulement des surfaces, il ne peut faire le tri entre les territoires plus peuplés et les moins peuplés.

Les cartes à pastilles proportionnelles rendent mieux compte des populations en présence, mais les petits ronds se voient peu, ou alors coagulent en amas artificiels là où le maillage communal est très serré (par exemple dans les Hautes-Pyrénées, voisines des Landes où c’est l’inverse). Les cartogrammes qui distordent la géographie pour prévenir les superpositions accentuent souvent ces artefacts.

Une autre voie respecte la géographie, préserve la continuité de l’image et prend en compte les différences de population : celle où le résultat d’un candidat (part en %) est lissé par disques mobiles.

Les spécialistes des études locales la connaissent depuis longtemps – je la pratique depuis 35 ans. Certes, les calculs requis par le lissage en limitent l’usage, même avec des librairies spécialisées. Il est toutefois possible en 2024 de construire simplement de solides cartes lisséessans logiciel lourd.

Voyons comment faire avec 3 petits bijoux d’efficacité : un moteur SQL autonome (DBeaver/DuckDB), une grille hexagonale (H3) et un outil de cartographie web (Mapshaper).

A - Lissage appliqué aux résultats communaux des européennes de 2024

Comparons ci-dessous les résultats bruts des élections européennes et la représentation lissée par disque mobile. Le lissage améliore spectaculairement la lisibilité de l’image.

Européennes 2024 – Part des votes RN et Reconquête (%)

Lissé
Brut

Les grandes agglomérations éloignent le vote RNR, mais cet effet est moins visible dans un grand Nord-Est ou sur le littoral méditerranéen. Quelques contrastes locaux sont frappants, par exemple entre le Lot et Tarn-et-Garonne, ou l’agglomération bordelaise et sa frange nord.
Note : les petits points gris signalent les capitales régionales.

Comme le pinceau de l’archéologue dépoussière un bas-relief, ou la restauratrice révèle sous les vernis et les taches le tableau originel, le lissage dégage les lignes de force qui traversent les territoires – et bien souvent celles qui résistent au temps et aux soubresauts politiques.

Je vais décrire la méthode, car en saisir le principe, c’est mieux comprendre les limites et les avantages de cette technique. Le lissage n’est pas une moyenne locale des valeurs communales (ici la part de telle liste). Il repose sur une agrégation de deux grandeurs que l’on va ensuite diviser pour recalculer le taux « ambiant ». Cette agrégation se fait sur une étendue plus ou moins large, le rayon du disque de lissage.

En un endroit donné, on additionne par exemple le nombre de votants RNR au sein d’un rayon de 20 km, et l’on procède de même pour l’ensemble des votants ;  le nouveau taux se calcule sur ces deux grandeurs étendues. Ainsi, d’une commune à sa voisine, les taux ambiants vont faiblement varier. Les aléas locaux sont lissés, et les territoires localement plus peuplés contribuent davantage à la représentation.

B - La méthode en images

Considérons les deux cartographies traditionnelles du résultat d’une liste, dans notre exemple la part du vote RN et Reconquête (en abrégé, RNR). Sur une carte zoomée, la technique des ronds coloriés a bien des avantages, car les symboles sont tous visibles, leur couleur aussi. Ce mode présente à la fois une grandeur absolue (les votants), et la part du vote RNR. 

Ronds
Choro

Comme on le constate dans cette vue de la périphérie toulousaine, les communes sont de taille fort variable. Le découpage communal influence fortement la morphologie de l’image. C’est la raison pour laquelle certains politiques s’échinent à redéfinir les maillages électoraux, pour tourner l’addition locale des votes à leur avantage.

Passer d’un maillage hétérogène à une grille régulière donnera une assise plus solide à la méthode de lissage.

La grille H3, conçue d’abord pour les besoins d’Uber, maille l’ensemble de la planète avec des hexagones. En voici une représentation au niveau de précision 7 (sur une échelle allant de 0 à 15). 

38 hexagones de niveau 7 recouvrent la commune de Toulouse. Une première idée consiste à répartir le total des votants à Toulouse de façon égale sur ces 38 hexagones. Je pourrais affiner cette répartition sur les hexagones frontières, par un prorata de la surface intersectée. Mais ce serait me compliquer la vie inutilement, car en définitive, je vais lisser !

Toulouse et les hexagones H3

Grille H3 de niveau 7, intersectant Toulouse
Votants à Toulouse répartis fictivement en 38 points

Les hexagones sur les frontières communales vont ainsi recevoir des votants venus de deux, parfois trois communes limitrophes. Cela produit déjà, de fait, un premier microlissage. 

En voici le résultat cartographié, après recalcul du taux pour chaque hexagone.

H3
Brut

Le principe du lissage par fenêtre mobile est toutefois bien plus puissant. H3 permet très facilement (c’est aussi une librairie avec quantité de fonctions utilitaires) de lister les hexagones voisins, avec un pas variable – de 1 à 10 dans cet exemple :

Avec ce rayon de lissage de 10 (soit un peu plus de 20 km), je m’emploie à additionner, en un centre donné, les votants et les votants RNR sur l’ensemble de ce disque. Je prends garde à donner de moins en moins d’importance aux hexagones qui s’éloignent, par une pondération inverse de la distance au centre.

Mon lissage intègre ainsi deux paramètres d’ajustement : le rayon du disque mobile (en fait un grand hexagone mobile), et la fonction de pondération (quelle importance j’accorde aux hexagones les plus éloignés pour calculer le taux ambiant).

Voici deux cartes, avec des rayons de lissage différents : 5 (soit environ 12 km) et 10 (20-25 km).

++
+

C - Comment lisser, en pratique ?

Je conduis les calculs en SQL, avec le moteur DuckDB et son extension H3, dans l’interface DBeaver. DBeaver donne un premier aperçu du résultat des requêtes spatiales, ce qui s’avère très pratique.

Pour la cartographie thématique, Mapshaper, utilisable en ligne, dessine et colorie avec une vélocité remarquable. 

Cette démarche procède d’un principe pédagogique auquel je suis attaché : ouvrir des portes pour le plus grand nombre, privilégier les outils les plus simples, les plus accessibles, les mieux conçus. 

Commençons par récupérer les résultats des européennes 2024, à partir de la base électorale consolidée par l’équipe data.gouv au format parquet :

				
					-- source : https://object.files.data.gouv.fr/data-pipeline-open/prod/elections/candidats_results.parquet

CREATE OR replace TABLE s_com_europ2024 as
WITH t1 AS (
	FROM 'candidats_results.parquet'
	SELECT "Code du département" || "Code de la commune" codgeo, nuance, 
	sum(voix) tvoix,
	sum(tvoix) over(PARTITION BY "Code du département" || "Code de la commune") exprimes,
	WHERE id_election = '2024_euro_t1'
	GROUP BY codgeo, nuance
), t2 AS (
	PIVOT t1 
	ON nuance USING(sum(tvoix))
)
FROM t2 SELECT codgeo,exprimes,LREC+LRN RN,LENS,LFI+LUG+LVEC+LCOM LNFP
ORDER BY codgeo ;


				
			

J’utilise DuckDB dans sa version la plus récente (dev 1.0.1), qui simplifie davantage encore les écritures. 

Deux extensions vont me servir, SPATIAL pour les requêtes géographiques, H3 pour créer et manipuler le maillage hexagonal. 

				
					INSTALL H3 FROM COMMUNITY ;
LOAD H3 ;

-- pour récupérer, si besoin, la version de dev :
-- FORCE INSTALL spatial FROM 'http://nightly-extensions.duckdb.org';
LOAD SPATIAL ;


				
			

À partir du contour de la France métropolitaine, je crée une enveloppe, et je peux la voir immédiatement dans DBeaver.

				
					CREATE OR REPLACE VIEW e_fra AS
FROM st_read('a_frametro.json') 
SELECT st_convexHull(geom).st_buffer(0.1) AS geom ;

				
			
eur2024_hull

Notre première fonction H3, l’une des plus puissantes, est en mesure de mailler ce polygone avec plein de petits hexagones de niveau 7. Ils sont 182 000. DBeaver ne m’en montre qu’un échantillon, mais c’est déjà impressionnant ! 

				
					FROM e_fra
SELECT h3_polygon_wkt_to_cells(geom, 7) -- ids
	    .unnest()
		.h3_cell_to_boundary_wkt()
		.st_geomfromtext() ; -- géométries
				
			
eur2024_hull_h3

h3_polygon_wkt_to_cells() renvoie une valeur qui est en fait une liste d’identifiants d’hexagones. unnest() permet de déplier cette valeur/liste en autant de lignes de la table résultante.

h3_cell_to_boundary_wkt(), autre fonction très utile, génère la géométrie hexagonale d’un identifiant.

On peut ainsi fabriquer un grillage spatial sans écrire soi-même aucun calcul mathématique.

Pour remplir une forme plus complexe que le simple POLYGON précédent, la France par exemple, il faut la décomposer en formes plus élémentaires, et assembler le résultat pour constituer une table homogène.

				
					CREATE OR REPLACE TABLE fra_h3_res7 AS
WITH france_polys AS (
	FROM st_read('a_frametro.json')
	-- décomposition MULTIPOLYGON -> POLYGON
	SELECT st_dump(geom).unnest(recursive := true) AS geom
), h3_ids AS (
	FROM france_polys 
	SELECT list(h3_polygon_wkt_to_cells(geom, 7))
			.flatten().unnest() AS id -- concaténation des ids d'hexagones
) FROM h3_ids SELECT id, 
-- conversion en géométries
h3_cell_to_boundary_wkt(id).st_geomfromtext() AS geom ;


				
			

Voici un aperçu des 115 000 hexagones du niveau 7 qui recouvrent la France métropolitaine.

Passons dans Mapshaper

Les fonctions cartographiques de DBeaver sont pratiques, mais limitées. L’outil Mapshaper affiche sans aucune difficulté l’ensemble de la couche. 

Au préalable, on aura procédé, dans DBeaver, à un export Geojson.

				
					COPY fra_h3_res7 TO 'fra_h3_res7.json' 
WITH (format GDAL, driver GeoJSON) ;


				
			

Il suffit ensuite de faire glisser ce fichier dans l’interface de Mapshaper. La console de cet outil permet d’écrire de puissantes instructions de manipulation, dont je vais profiter.

Je souhaite enrichir cette grille par jointure spatiale avec deux autres couches géographiques. Je vais ainsi relier chaque hexagone aux département, région et commune(s) qui le recouvrent ou l’intersectent.

				
					target fra_h3_res7 \
join a-depmetro calc='reg=first(reg), dep=first(dep)' largest-overlap \
join a-com2022 calc='com2022=first(codgeo), coms2022=collect(codgeo)' largest-overlap \
join a-com2022 calc='coms2022=collect(codgeo)'


				
			

Ces opérations complexes prennent moins de 10 secondes dans mon navigateur. 

J’utilise ce fond de carte communal.

L’identifiant d’un hexagone est un entier de grande taille. Mapshaper l’interprète plutôt comme une string, on y sera attentif par la suite.

Je stocke ma couche hexagonale enrichie sous la forme d’un fichier geoparquet, ce que permet très simplement la version 1.0.1 de DuckDB. Le fichier produit pèse à peine 9 Mo. 

				
					COPY (
	FROM st_read('fra_h3_res7_v2.json')
	SELECT * REPLACE(id::ubigint AS id),
	ORDER BY reg,id
) TO 'fra_h3_res7_v2.parquet' (compression ZSTD) ;


				
			

Cartographie thématique avec Mapshaper

Je ne les avais jamais utilisées, je découvre avec bonheur les fonctions de coloriage de Mapshaper !

La surface des hexagones n’est pas constante dans H3, car ces hexagones résultent de la projection sur la sphère terrestre d’une forme géométrique complexe, un icosaèdre. De plus, leur surface apparente dépendra de la projection cartographique finale.

Pour autant, cette surface projetée varie peu d’un hexagone à l’autre. Voici ce que donne le rapport à la surface moyenne :

				
					classify field=coeff_area colors='#fff5eb,#fee7cf,#fdd4ab,#fdb97e' classes=4 \
style stroke='d.fill'


				
			

Conscient de ces petites variations, je considère tout de même que le lissage à venir s’appliquera de façon globalement homogène – en tous cas bien plus homogène que si j’en étais resté au maillage communal.

J’ai pu agrémenter ma carte de limites départementales et régionales précisément superposables, par fusion de la couche détaillée : Mapshaper excelle dans ces traitements topologiques, et je vais 10 fois plus vite qu’avec un logiciel spécialisé comme QGIS !

				
					target fra_h3_res7_v2 \
dissolve dep,reg

				
			

Projection des données communales du vote sur la grille H3

Je dispose donc d’un excellent référentiel cartographique, avec des hexagones enrichis d’informations communales : elles vont me permettre de faire le lien avec la table des résultats électoraux.

Dans une table intermédiaire, je stocke le nombre d’hexagones couvrant chaque commune.  

				
					CREATE OR replace VIEW n_com_h3_res7 as
WITH t1 AS (
	FROM 'fra_h3_res7_v2.parquet'
	SELECT UNNEST(coms2022) codgeo, id 
) FROM t1 SELECT codgeo, count() AS nb_h3_res7
GROUP BY codgeo 
ORDER BY codgeo ;

FROM n_com_h3_res7 
WHERE codgeo = '31555';  -- 38 hexagones intersectent Toulouse
				
			

Grâce à cela et par jointure, je ventile la table communale du vote à l’hexagone.

				
					CREATE OR REPLACE table s_h3_res7_europ2024 AS
FROM s_com_europ2024 p
-- jointures sur le code commune
JOIN n_com_h3_res7 n using(codgeo)
JOIN (FROM 'fra_h3_res7_v2.parquet'
	SELECT UNNEST(coms2022) codgeo, id) h3 
	ON h3.codgeo = p.codgeo
SELECT id, 
round(sum(RN/n.nb_h3_res7),1) RN, -- ventilation des votants sur chaque hexagone
round(sum(exprimes/n.nb_h3_res7),1) exprimes 
GROUP BY id ORDER BY id ;
				
			

Il ne me reste plus qu’à injecter cette information dans la couche spatiale des hexagones, que j’exporte vers Mapshaper :

				
					COPY (
	FROM 'fra_h3_res7_v2.parquet' m
	JOIN s_h3_res7_europ2024 l USING(id) 
	SELECT RN, exprimes, 
	round(100*RN/exprimes, 1) part_rn, 
	st_geomfromwkb(geom) geom
) TO 'a_h3_7_europ2024_fra_brut.json' WITH (format GDAL, driver GeoJSON) ;
				
			

J’essaie deux variantes de coloration, en quantiles, et avec des seuils explicites (pour faciliter les comparaisons à venir entre carte brute et cartes lissées) :

				
					classify field=part_rn quantile classes=5 colors=Oranges \
style stroke='d.fill'

classify field=part_rn breaks=35,40,45,50 colors=Oranges \
style stroke='d.fill'
				
			

Européennes 2024 – Part des votes RN et Reconquête (%) – par hexagone de niveau 7

Le lissage final

Pour lisser les données par fenêtre spatiale mobile, il me faut faire le lien entre un hexagone donné, et l’ensemble des hexagones voisins, de premier niveau jusqu’au niveau 10.

h3_grid_disk_distances() me donne cette liste d’anneaux successifs en un seul appel. C’est un autre atout majeur du système H3.

				
					CREATE OR replace VIEW corresp_h3_res7_dist10 AS 
WITH t1 AS (
	FROM 'fra_h3_res7_v2.parquet' 
	SELECT id, list_transform(h3_grid_disk_distances(id, 10), 
							  (c,i) -> {ids:c, distance:i})
						.unnest(recursive := true)
) 
FROM t1 
SELECT id, unnest(ids) id2, distance ;
				
			

L’opération de lissage résulte d’un appariement de cette table de correspondance et des données de vote à l’hexagone. Je définis une fonction de pondération inverse de la distance, et je me réserve la possibilité d’ajuster le rayon de lissage.

				
					CREATE OR REPLACE VIEW s_h3_res7_europ2024_liss as
FROM corresp_h3_res7_dist10 c 
JOIN s_h3_res7_europ2024 p ON c.id2 = p.id
SELECT c.id, 
sum( RN     /(1 + pow(distance-1,1.5)) ) RN, -- 1.5 (pondération) ajustable
sum(exprimes/(1 + pow(distance-1,1.5)) ) exprimes
WHERE distance <= 10  -- rayon de lissage ajustable
GROUP BY c.id ;
				
			

Pour rappel, la méthode commence par agréger séparément le numérateur et le dénominateur, le taux « ambiant » est calculé dans un second temps, avant export vers Mapshaper :

				
					COPY (
	FROM 'fra_h3_res7_v2.parquet' 
	JOIN s_h3_res7_europ2024_liss USING(id) 
	SELECT RN, exprimes, 
	round(100*RN/exprimes,1) part_rn, 
	geom
) TO 'a_h3_res7_europ2024_fra_liss_l5_p15.json' 
WITH (format GDAL, driver GeoJSON) ;
				
			
				
					classify field=part_rn breaks=35,40,45,50 colors=Oranges \
style stroke='d.fill'
				
			

Voici le résultat, avec en prime une comparaison avec le vote le Pen lors de l’élection présidentielle de 2022.

Européennes 2024 – part des votes RN et Reconquête (%) et présidentielle 2022 – Part du vote le Pen (%)

2024
2022

Ces deux cartes présentent de grandes similitudes. Même si les seuils ne sont pas comparables (le vote RN était supérieur, en %, en 2002, mais il s’agissait du 2d tour, avec donc seulement 2 candidats en présence).

D - À vous de jouer !

Ci-dessous figure l’accès à ce kit de lissage : la couverture H3 de la France au niveau 7, et la table de correspondance entre chaque hexagone et leurs voisins. Les préparer a demandé un peu de temps, comme on l’a vu ci-dessus.

Leur application à toute base de données communales est toutefois simple et rapide, deux requêtes suffisent, et tournent en moins de 10 secondes : ventilation des valeurs additives sur la grille H3, et lissage par fenêtre mobile. Avec Mapshaper, vous en voyez très rapidement le résultat. Lisser ne demande qu’un éditeur SQL (ou le client léger DuckDB) et le navigateur web.

Pour en savoir plus

2 commentaires sur “Les lignes de force du vote RN en 2024 : une cartographie lissée avec la grille H3”

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *