D3JS - Carte choroplèthe (non linéaire)

Comment réaliser une carte choroplèthe avec une échelle non linéaire
d3js7.x
Sources :

Cet exemple est un complément de la carte choroplète représentant la densité de population en France. Celui-ci permet de visualiser la répartition des prix Nobel depuis sa création. La principale difficulté vient du fait que les Etats-Unis possèdent 350 prix Nobel alors que la plus part des pays en possèdent 0 ou moins d'une dizaine.

Pour éviter d'avoir les Etats-Unis en rouge foncé et tous les autres pays en jaune très clair, nous utilisons une échelle non linéaire basée sur la fonction racine carré. Ainsi nous projetons notre échelle non pas sur 0-350 mais sur 0-19 ce qui permet des différences de couleurs plus visibles.

var quantize = d3.scaleQuantile()
	.domain([0, Math.sqrt(d3.max(csv, e => +e.NobelCount))])
	.range(d3.range(9));

Nous redéfinissons également le scale de la légende en précisant qu'il n'est plus linéaire mais de type racine carré.

var legendScale = d3.scaleSqrt()
	.domain([0, d3.max(csv, e => +e.NobelCount)])
	.range([0, 9 * 20]);

Enfin, la fonction quantize doit être apellé avec la racine carré de la population

quantize(Math.sqrt(+e.NobelCount))

Le reste du code est identique, le fichier geoJSON contient tous les pays du monde et le fichier des prix Nobel est un simple fichier CSV.

La partie CSS

Le code CSS est repris de l'exemple précédent, nous avons simplement changé la classe department en country pour être cohérent et ajouté quelques propritétés pour les pays qui ne possèdent pas de données (avec un fond gris)

.country {
	fill: #999;
	stroke: black;
	stroke-width: 0.5px;
	stroke-linecap: round;
	stroke-linejoin: round;
	vector-effect: non-scaling-stroke;
}
	
.country:hover {
	stroke-width: 1px;
}

D'autres exemples d'échelles

Pour mieux visualiser le problème introduit dans ce tutoriel voici la carte avec une échelle standard.

Il n'est plus possible de faire de distinction entre tous les pays en jaune clair. C'est-à-dire tous les pays qui ont moins de 39 prix Nobel. Ce chiffre correspond à la division du nombre maximum pour un pays, à savoir 350 pour les Etats-Unis, par le nombre de variations (scale) de notre graphique, à savoir 9. Pour conclure voici une dernière représentation en utilisant une échelle logarithmique.

L'échelle n'est pas affichée mais il faut bien avoir en tête qu'elle serait très écrasée. Elle permet de donner plus d'importance aux pays avec peu de prix Nobel. D3 offre encore d'autres types d'échelles qu'il convient de bien étudier pour choisir celle qui sera la plus représentative. Lorsque l'échelle n'est pas linéaire il est important d'associer au graphique une représentation de cette échelle afin de ne pas induire en erreur le lecteur. Dans ce dernier exemple on pourrait penser que l'Allemagne à presque le même nombre de prix Nobel que les Etats-Unis, ce qui n'est pas le cas (105 contre 350).

COMMENTAIRES

Sandy-Pascal Andriant


Bsr,

Je poursuis sur ma lancée.

J'ai créé une carte choroplèthe du département de la Côte-d'Or.

Je voudrais ajouter une liste déroulante des villes(dans une <div> .float : right)

et je voudrais que la fonction csv.forEach(function(e,i) ne soit plus déclenchée par
.on("mouseover", function(d)
mais lorsqu'on choisit une ville de la liste déroulante.
Je précise que la variable "e" fait référence au code INSEE de mon csv et que le "id" de chaque <option> est également associé au même code INSEE.
Suis pas fortiche en JS, désolé.

Merci de vos lumières

Merci

ericfrigot


Bonjour, avec l'accès direct à votre code ça ne sera pas difficile de vous aider. Mais afin de le faire de manière précise j'aimerais comprendre votre besoin. Quand on survole avec la souris les limites d'une commune on affiche le tooltip qui fournit les informations, du coup c'est très fluide. J'ai le sentiment qu'en faisant ce que vous demandez on régresse un peu, pourquoi devoir sélectionner la ville dans une liste ? Et dans ce cas là ce n'est plus un tooltip qu'il faut afficher mais un texte dans un DIV positionner à droite de la carte par exemple. Par ailleurs est-ce que vous pouvez me dire ou vous voulez placer la liste déroulante dans la page ? Eric

Sandy-Pascal Andriant


Bjr,

pourquoi devoir sélectionner la ville dans une liste


Actuellement, la carte est totalement "anonyme" : si on ne sait pas d'avance où se situe la ville recherchée, on peut passer des heures avant de la trouver.

Dans la future architecture, la carte sera incluse dans un <div> avec css "float: left" et la liste des communes dans un <div> "float:right".

Voir nouvelle page

Merci
Sandy-Pascal

Sandy-Pascal Andriant


Le résultat recherché ressemblerait aux fonctionnalités de cette page :

https://www.cgvaucluse.org/...
Une carte interactive ET une liste des communes qui dynamise la carte de la même manière que le clic sur une commune.

Je suppose que je dois utiliser un addEventListener mais c'est bien trop complexe pour mon peu de connaissances en JS.
Merci

Sandy-Pascal Andriant


Bonjour,

Je ne trouve pas le bout de code qui permet de colorer en gris les zones dont les données sont manquantes.
Merci pour ces tutos par ailleurs excellents.

Sandy-Pascal Andriant


Ah super,

Par ailleurs, j'arrive très bien à créer une carte en local mais malgré les modifications nécessaires pour le lien vers les fichiers, je n'arrive pas à la mettre en ligne. Écran blanc

Comme si le fichier d3.v5.js n'était pas accessible. :(

Sandy-Pascal Andriant


Oups,

J'avais oublié le chemin relatif de d3.v5.min.js

Vraiment très cool.
J'adore cette API !

ericfrigot


Bonjour, content que ça fonctionne de votre côté.
Pour information nous venons tout juste de passer tous nos tutoriaux en version D3 V6. Je pense que ça fonctionne même avec la version 7.
Si vous le pouvez utiliser plutôt ces dernières versions, il y a juste des changements à faire au niveau des évènements de la souris.

Sandy-Pascal Andriant


Merci pour l'info,

J'ai essayé mais effectivement, il va falloir que je modifie les évènements de la souris.
Contrats de Mariage de la Côte-d'Or (21)
Je renouvelle mes compliments pour cet API qui produit des cartes très "professionnelles" pour l'amateur que je suis.

ericfrigot


Bonjour et merci pour le compliment, ça fait toujours plaisir.
En fait au fur et à mesure des tutos je ne mentionne plus forcément la partie CSS, c'est une erreur.
Pour le gris il faut utiliser ce CSS :
.country {
fill: #999;
stroke: black;
stroke-width: 0.5px;
stroke-linecap: round;
stroke-linejoin: round;
vector-effect: non-scaling-stroke;
}

Je l'ajouterais dans une partie dédiée ce soir. Bonne continuation, Eric

Christophe


Bonjour, et tout d'abord merci beaucoup pour vos tutos très précis et très clairs !
J'ai mis en place une map comme celle-ci et je me pose maintenance la question suivante : "comment la rendre responsive ?"
En effet les dimensions du svg sont actuellement fixées au départ... merci d'avance pour vos éclaircissements sur le sujet.

ericfrigot


Bonjour,
Je vous réponds un peu tardivement. Pouvez-vous me dire à quel point vous voulez que votre map soit responsive ? Je m'explique, si vous voulez afficher la map sur une largeur d'écran qui peut varier (1980px pour un PC fixe ou mettons 800px pour un smartphone) vous pouvez initialiser votre map comme c'est fait dans le code source de cette page avec ces deux variables : const width = document.getElementById("container").offsetWidth * 0.95, height = 600;
Ainsi vous tenez compte de la largeur de l'écran. Si maintenant vous voulez que la map soit complètement responsive, il faut ajouter un événement pour que lorsque la taille de l'écran varie la map se redessine automatiquement. Avec cette dernière solution vous pouvez rapidement rencontrer quelques difficultés, le choix de votre font-size peut être trop grand au bout d'un moment, l'échelle peut également prendre trop de place en hauteur. Pour gérer cela correctement il faut aller beaucoup plus loin et tout rendre dynamique. Par exemple dire que si ma hauteur est H alors ma légende doit entrer dans (H - 5%) pour laisser une marge puis en déduire la taille de chaque bloc de la légende en fonction de la valeur de cette hauteur et du nombre de bloc que l'on doit afficher. Je pourrais vous répondre de manière plus structurée si vous indiquez ce que vous voulez faire.
Eric