Journal Où il est question de D3, des communes de France et des performances SVG des moteurs de rendu

60
21
mai
2013

Mes-dame-sieur-s, mesdemoise-lle-au-s-x, mestransgenres, bonmatin-jour-soir-nuit (j'espère n'avoir oublié personne, nulle part),
 

J'ai récemment eu l'occasion de m'éloigner de ma Vendée natale et de ma Loire-Atlantique d'adoption pour explorer le vaste monde autour de moi : je suis parti en expédition d'une part dans le sud lointain, la Charente-Maritime, et d'autre part dans le grand nord en m'aventurant dans le Morbihan. J'ai bien sûr eu l'occasion de passer par de nombreuses communes pittoresques et sauvages, entre autres Meursac, Rouffiac, Pérignac, Nivillac, Sévérac et Carnac. Repensant à ma famille lointaine, exilée dans des villages aux noms barbares tels que Florac, Figeac ou Compreignac, j'ai cru remarquer qu'un certain motif se répétait.

L'avez-vous remarqué vous aussi ? Pour ceux qui n'auraient pas eu la perspicacité, la vivacité d'esprit requise pour détecter ce motif d'après mes exemples, il semblerait que les communes de certaines provinces de France aient une certaine propension à se terminer par les lettres "ac".

 

Je m'attelai donc à la tâche de vérifier cette hypothèse, et pour ce faire choisis d'utiliser D3, que j'avais déjà eu l'occasion d'utiliser à plusieurs reprises, par exemple pour afficher des statistiques de tribune. D3 est une bibliothèque Javascript facilitant la manipulation de données et l'interfaçage avec le DOM (des éléments SVG dans mon cas).

 

Armé donc de D3 et d'un fichier CSV listant toutes les communes de France métropolitaine, leurs noms et leurs coordonnées, je décidai naïvement dans un premier temps d'afficher chaque commune sur une carte, comme un point. Las ! aucun de mes navigateurs ne semblait capable de gérer trente-six mille points SVG sans se suicider, ou sans que mon noyau ne décide unilatéralement de sacrifier un processus innocent choisi aléatoirement, probablement dans le vain espoir d'adoucir le courroux du navigateur. Désarçonné mais pas vaincu, je pensai d'abord à l'utilisation de choroplèthes pour grouper les communes par canton, voire arrondissement mais reculai devant le poids des données nécessaires (neuf mégaoctets pour les cantons, trois pour les communes). J'optai donc pour le groupement des communes en hexagones qui, s'il a l'inconvénient de ne pas montrer aisément la densité des communes (certains hexagones ne couvrent qu'une commune, d'autres des dizaines), est facile à mettre en place avec d3 et le plugin présenté par le lien susmentionné. Je me figurai aussi que dessiner quelques milliers d'hexagones devait être pour mon processeur plus facile que dessiner quatre mille cantons avec leurs frontières biscornues.
 

J'avais raison, et après ces quelques revers, l'implémentation de mon idée fût relativement simple et rapide, et en voici le résultat sans plus attendre :
http://ssz.fr/fr -ac
 

Le plus difficile étant fait, j'ajoutai quelques fleuves et rivières majeures pour servir de points de repère, la possibilité choisir le motif à appliquer aux noms des communes, et deux autres champs pour comparer plusieurs motifs à la fois… mais j'avais oublié un test important : Firefox.
Jusqu'à ce point, j'avais uniquement testé ma création avec Chromium et Opera et avais négligé Firefox, dont les performances sont décidément largement inférieures aux autres moteurs de rendu en ce qui concerne le SVG, comme vous pouvez probablement vous-même le constater (vous l'avez peut-être même déjà constaté en cliquant sur les premiers liens de ce journal, qui affichent en SVG les frontières des départements).

Ces problèmes de performance semblent uniquement liés au rendu du SVG et non au Javascript de votre serviteur : celui-ci n'est exécuté qu'au chargement de la page pour créer le pavage hexagonal, et à la modification d'un pattern pour mettre à jour les couleurs des hexagones, mais Firefox semble être à genoux lorsqu'on lui passe simplement la souris sur les hexagones, peut-être en partie à cause de leur transparence ? Quoi qu'il en soit, je ne peux semble-t-il pas y remédier autrement qu'en diminuant la précision de l'affichage, ce qui rend malheureusement la carte moins intéressante.

 

Après ces considérations techniques, je me suis posé la question du choix des couleurs. Chaque hexagone représente un nombre très variable de communes : Port-Joinville ou Ouessant sont représentées par un seul hexagone, mais en région parisienne chacun peut couvrir plus d'une dizaine de communes (notez que cela dépend de la taille disponible pour l'affichage : les hexagones font toujours cinq pixels de côté, mais la carte est ajustée pour faire à peu près la même hauteur que la fenêtre du navigateur dans lequel elle est affichée). Dans ce cas, comment afficher un hexagone dont une seule des communes vérifie le motif ? J'ai décidé d'utiliser un dégradé lorsque moins de 15% des communes de l'hexagone correspond, et d'utiliser la couleur pleine au-dessus de 15%, puis de faire la moyenne des couleurs lorsque plusieurs patterns correspondent, mais si vous avez des idées qui vous semblent meilleures, je vous prie de me les suggérer dans les commentaires.

 

Et pour en arriver à la carte elle-même, le motif des communes se terminant par -ac est finalement assez remarquable. En accédant directement à http://ssz.fr/fr un motif est affiché au hasard parmi une liste de motifs intéressants, par exemple :
* ac$ / y$ / hei?m$
* ^saint / court$ / w
* sur-seine / sur-loire / sur-meuse

Sur la même foulée, j'ai fait une carte similaire pour les îles britanniques, mais la recherche de motifs intéressant s'est avérée plus ardue :
http://ssz.fr/uk

  • # svg

    Posté par . Évalué à 5. Dernière modification le 21/05/13 à 16:54.

    j'avais déjà observé ce manque de perf quand j'avais tenté l'expérience de mettre du svg en background image (cf http://www.broken-links.com/2010/06/14/using-svg-in-backgrounds-with-png-fallback/ )

    il y a quelques rapports de bug sur le bugzilla en rapport https://bugzilla.mozilla.org/show_bug.cgi?id=698996

    https://bugzilla.mozilla.org/show_bug.cgi?id=554004

  • # Malloc Linux

    Posté par . Évalué à 4.

    aucun de mes navigateurs ne semblait capable de gérer trente-six mille points SVG sans se suicider, ou sans que mon noyau ne décide unilatéralement de sacrifier un processus innocent choisi aléatoirement, p

    J’ai toujours trouvé ce choix par défaut ahurissant. Ce qui ne m’empêche pas de l’utiliser en l’état. Mais tu peux le modifier en changeant la valeur de /proc/sys/vm/overcommit_memory. Au moins, tu pourras faire des tests sans avoir d’applications qui meurent.

    • [^] # Re: Malloc Linux

      Posté par . Évalué à -3.

      Comme ça, si on process part en sucette, au lieu de laisser le noyau tuer le process, ta machine va prograssivement ramer en remplissant la swap, et puis ça sera le reboot assuré. Vraiment un bon plan :)

      • [^] # Re: Malloc Linux

        Posté par . Évalué à 8.

        Pas du tout.

        Par défaut l'allocation mémoire de Linux est optimiste et permet d'allouer plus que la mémoire (RAM + swap) disponible. On suppose que les applis n'utiliseront peut être pas réellement la mémoire ou pas en même temps. Le noyau crash un process selon une heuristique quand la mémoire est vraiment utilisée.

        En désactivant l'overcommit tu enlèves l'allocation optimiste. Tu fais retourner null à malloc (sbrk en fait) quand tu arrives à la limite. Le processus passe par la au mauvais momoent doit gérer ce cas (et dans 90% plus ou moins se suicider car il ne peut rien faire d'autre).

        Dans les deux cas:

        • Tu vas remplir le swap avant que quoi ce soit se passe
        • L'application qui se fait butter (ou à qui on demande de se suicider) n'est pas forcément la bonne.
    • [^] # Re: Malloc Linux

      Posté par . Évalué à 5.

      Au moins, tu pourras faire des tests sans avoir d’applications qui meurent.

      Tu supposes deux choses pas forcément vraies:

      • Que l'appli qui va se prendre null en retour de malloc est la bonne
      • Que la malheureuse appli à qui ca arrive peut et sait gérer ce cas
      • [^] # Re: Malloc Linux

        Posté par . Évalué à 4.

        Tu supposes deux choses pas forcément vraies:

        Certes.

        Que l'appli qui va se prendre null en retour de malloc est la bonne

        Oui, enfin quand une application est en train de construire une représentation mémoire d’un svg dans l’espoir de l’afficher, on peut supposer qu’elle utilise une bonne part du CPU et qu’elle réalise la majorité des mallocs à ce moment là (>>90% àmha) donc une bonne chance que ça marche.

        Que la malheureuse appli à qui ca arrive peut et sait gérer ce cas

        Enfin, c’est la base… si un développeur ne sait pas gérer un malloc qui échoue, il devrait apprendre.
        Les cas où on ne peut rien faire lorsqu’une allocation échoue, ne sont pas si nombreux. Il y a le problème des frameworks… je ne sais pas comment Qt réagit par exemple.

        Néanmoins, je t’accorde que une autre application peut se tuer car c’est elle qui a prie le refus de malloc, et donc libérer sa mémoire, et donc donner un peu plus de temps à celle qui bouffe tout !

        • [^] # Re: Malloc Linux

          Posté par . Évalué à 4. Dernière modification le 21/05/13 à 18:32.

          Oui, enfin quand une application est en train de construire une représentation mémoire d’un svg dans l’espoir de l’afficher, on peut supposer qu’elle utilise une bonne part du CPU et qu’elle réalise la majorité des mallocs à ce moment là

          Donc il n'y à aucune raison que l'OOM killer ne soit pas capable de définir une heuristique qui retrouve ce processus. Pour avoir un peu suivi les discutions sur l'OOM killer il y a quelques années, c'est visiblement pas si simple (le coup de shooter le processus qui à fait le plus d'alloc dans les dernières secondes a été testé, tout comme le plus gros et des dizaines de variantes).

          Enfin, c’est la base… si un développeur ne sait pas gérer un malloc qui échoue, il devrait apprendre.

          Il y a une différence entre la théorie et la pratique dans des vraies applis complexes. Et souvent la complexité ajoutée par gérer spécifiquement ce cas, fait que ca ne vaut pas le coup par rapport à un suicide simple. Ce type d'erreur peut facilement cascader et empêcher de faire toute chose utile ou même de notifier l'utilisateur que tu ne peux pas faire ce qu'il demande. À quoi bon tout saloper pour le même résultat au final ? Au pire tu vas même introduire des inconsistances à cause de ton code de rattrapage.

          Et la on ne parle que du C. Dans la plupart des langages modernes tout le monde se balance de ce cas. J'ai jamais vu catcher des ErrorMemory, OutOfMemoryException ou je ne sais même pas quoi en js sauf dans des cas bien particuliers. Et vu que les libs ne le font pas non plus, tu pourrais wrapper chaque appel de méthode aussi.

          Après ce n'est pas vrai pour tout. Il y a des cas où c'est faisable et à faire. Mais si tu tests avec les applis de ton desktop j'ai une petite idée du résultat.

        • [^] # Re: Malloc Linux

          Posté par (page perso) . Évalué à 3.

          si un développeur ne sait pas gérer un malloc qui échoue, il devrait apprendre.

          La meilleur chose à faire quand un malloc échoue est un crash. Gérrer tous les malloc dans un programme compliqué est un travail important. En plus, il faut s'assurer à bien tester tous ces cas. Et en plus à cause de l'over commit, en général les malloc n'échoue jamais. Donc il est préférable d'ignorer les cas ou malloc échoue.

          je ne sais pas comment Qt réagit par exemple.

          avec un crash.

          • [^] # Re: Malloc Linux

            Posté par . Évalué à 0.

            La meilleur chose à faire quand un malloc échoue est un crash.

            Heu, non. Au pire, tu devrais pouvoir prévenir l’utilisateur qu’il y a eu un problème de ressource… soit avec un message (messageBox, printf/cout) soit avec un code de retour donné.

            Gérrer tous les malloc dans un programme compliqué est un travail important.

            Oui, personne n’a dit que programmer était facile.

            En plus, il faut s'assurer à bien tester tous ces cas.

            Oui et non. Ça dépend de ton programme et de l’usage que tu souhaites faire de cette mémoire. Tu pourrais parfaitement attendre une quelques secondes avant de retenter… choisir un algo plus lent mais moins gourmand…

            Et en plus à cause de l'over commit, en général les malloc n'échoue jamais. Donc il est préférable d'ignorer les cas ou malloc échoue.

            Ceci n’est vrai que avec Linux par défaut. À ma connaissance, et j’ai peut-être tort, les BSD n’ont pas ce comportement. Donc, pour réaliser des programmes portables, il vaut mieux les tester en choisissant pour chacun une sanction.

            • [^] # Re: Malloc Linux

              Posté par (page perso) . Évalué à 3. Dernière modification le 22/05/13 à 11:48.

              Vas-y montre nous des applications desktop open source C ou C++ qui font quelque chose de plus sophistiqué que exit() précedé optionnellement d'une tentative d'affichage d'un petit message à l'utilisateur avant la mort du soft, je suis bien curieux de voir comment ils gèrent ça.

              Et je te donne 50 points de bonus si en plus tu en es l'auteur !

              • [^] # Re: Malloc Linux

                Posté par . Évalué à 2.

                C’est le cas d’Enlightenment, qui affiche une boîte de dialogue demandant si on souhaite le redémarrer (et donc ne pas perdre ses applications en cours) ou quitter.

                • [^] # Re: Malloc Linux

                  Posté par . Évalué à 6.

                  Mais ladite boite de dialogue ne nécessite-t-elle pas de faire des malloc, pour pouvoir être générée et affichée ? On ne tourne pas en rond, là ?

            • [^] # Re: Malloc Linux

              Posté par . Évalué à 4.

              soit avec un message (messageBox, printf/cout) soit avec un code de retour donné.

              Qui va demander une allocation mémoire… Oups. Qui va partir en deadlock… Oups.

              Oui et non. Ça dépend de ton programme et de l’usage que tu souhaites faire de cette mémoire. Tu pourrais parfaitement attendre une quelques secondes avant de retenter… choisir un algo plus lent mais moins gourmand…

              Tu es conscient que ca veut dire de faire un try catch (ou une ERRNOerie) avec un fallback utile autour de chaque appel de méthode qui peut faire une allocation mémoire ? Quand tu es au niveau lib C sur un filtre UNIX c'est trivial. Maintenant explique moi:

              • comment tu gères ca correctement sur un navigateur web.
              • en quoi le résultat est systématiquement mieux que le suicide pour l'utilisateur
              • en quoi ton soft est meilleur (il vient de prendre 200% de ligne de code avec des chemins d'exécution à la con à tester).

              Comme d'hab il faut faire attention à ne pas généraliser. Mais plus tu vas dan les GUI, les applis haut niveau, et les trucs compliqués plus la gestion de ce type d'erreur perd de son intêret par rapport aux couts engendrés et à ce que ca apporte. Ca peut être beaucoup plus payant de prévoir des blocs fonctionnels autonomes qui se suicident et repartent tout seul quand quelque chose va mal. La cohérence est facile à tester et prise en compte dans le design et tu mets pas du code qui sert à rien partout.

              • [^] # Re: Malloc Linux

                Posté par . Évalué à 2.

                soit avec un message (messageBox, printf/cout) soit avec un code de retour donné.

                Qui va demander une allocation mémoire… Oups. Qui va partir en deadlock… Oups.

                Un fprintf sur stderr n'alloue pas de mémoire (il va bouffer la pile)… pour la message Box, je suis d'accord sauf si elle a été préparée avant et qu’il suffit de lui demander de s’afficher.
                Mais bon, même un message sur stderr qui dit : « mémoire insuffisante » est plus claire que un segmentation fault.

                comment tu gères ca correctement sur un navigateur web.

                Je ne sais pas, mais tu pourrais décider d’annuler le rendu de la page, de libérer la mémoire et d’afficher un message du genre : « Mémoire insuffisante pour afficher cette page » et si ceci échoue, alors un message d'erreur et un exit avec un code particulier permettant de savoir que c’est un problème mémoire.

                en quoi le résultat est systématiquement mieux que le suicide pour l'utilisateur

                L’utilisateur sait pourquoi, il peut donc tuer son process gimp avec une image en 10000x10000, ou autre. Sinon, pour l’utilisateur c’est juste un programme pourri qui vautre.

                en quoi ton soft est meilleur (il vient de prendre 200% de ligne de code avec des chemins d'exécution à la con à tester).

                J’ai appris à l’école et au boulot à tester systématiquement les codes de retour des fonctions. J’évite de le faire sur le printf, car généralement, je me fout du nombre de caractères imprimés. Mais dans la plupart des cas, le retour permet de prendre la sanction appropriée pouvant être le suicide dans certains cas.

                Pour les GUI, je suis d’accord qu’ont ne puissent pas toujours éviter. Mais il ne faut pas oublier de se poser la question.

                • [^] # Re: Malloc Linux

                  Posté par (page perso) . Évalué à 2.

                  Un fprintf sur stderr n'alloue pas de mémoire

                  nope, *printf peut appeller malloc , (meme sprintf).

                  • [^] # Re: Malloc Linux

                    Posté par . Évalué à 2.

                    Au temps pour moi, je pensais qu’il n’utilisait que calloc (pas le temps de vérifier). Qui de toute façon pourrait échouer à étendre la pile… ;-)

  • # Canvas

    Posté par . Évalué à 1.

    C'est peut-être hors sujet, mais est-ce que tu as essayé de dessiner ça en utilisant les "canvas" ? Pour Leaflet, qui est utilisé par OpenStreetMap pour afficher des cartes et dessiner par dessus, il y a un switch pour forcer l'utilisation des canvas, c'est plus rapide dans certain cas.

    Certes c'est pas du vectoriel donc ça doit être moins facile à manipuler et à modifier dynamiquement…

    from __future__ import division

    • [^] # Re: Canvas

      Posté par (page perso) . Évalué à 1.

      C'est tout à fait dans le sujet, et j'ai le projet d'adapter le code pour faire du canvas à la place, au moins pour voir comment le faire (ça manquera probablement de tooltips et du subtil changement de couleur des hexagones au survol).

    • [^] # Re: Canvas

      Posté par (page perso) . Évalué à 5.

      Alors voilà à quoi je suis arrivé avec du canvas :
      http://ssz.fr/canvas/#y$/ij/w$
      à comparer avec :
      http://ssz.fr/eu/#y$/ij/w$

      Attention, là c'est une bonne partie de l'Europe, ça fait 15 Mo de données (heureusement compressés en 2 Mo lors du transfert), j'ai peut-être été un peu gourmand :)

      Sinon, visuellement c'est identique, avec les tooltips au hover en moins (ça pourrait se gérer, mais ça devient un peu trop compliqué juste pour une preuve de concept). C'est plus réactif à la fois sous Firefox et Chromium (une fois le chargement et traitement initial des données effectué) mais la différence reste minime, je trouve.

  • # Petit détail

    Posté par . Évalué à 3.

    D'abord, merci pour cet outils amusant et ce retour pertinent. Un petit détail : si on laisse un champ vide avant un autre, la code couleur à côté de la carte est faux. Exemple : http://ssz.fr/fr/#//seuil affiche bien les hexagone en rose, mais à côté de la carte, on voit "seuil" en jaune.
    Merci encore pour le partage.

  • # Carte de France choroplèthe interactive

    Posté par (page perso) . Évalué à 4.

    J'avais pondu ça il y a quelques temps : http://kerneis.github.io/france-choropleth/

    Pour ceux qui veulent avoir une idée de ce que ramer veut dire ;-) (L'interface utilisateur est complètement foireuse, c'était juste pour jouer avec une idée de David Madore : http://www.madore.org/~david/weblog/2012-04.html#d.2012-04-26.2033).

  • # Bravo

    Posté par (page perso) . Évalué à 10.

    Bravo, franchement bravo.

    Au lieu de profiter des 30 dernières minutes à me reposer du sommeil du juste, je viens les passer à tester des variantes de nommage de communes françaises en svg.

    Ce n'est pas comme ça que l'on va redresser productivement la France.

    La France de vous remercie pas mon petit monsieur.

  • # Les autres noms remarquables

    Posté par . Évalué à 4.

  • # acum

    Posté par . Évalué à 3.

    sur l'origine du suffixe et quelques cartes intéressantes

    https://fr.wikipedia.org/wiki/Suffixe_-acum

  • # Avec mes remerciement les plus sincère

    Posté par . Évalué à 3.

    Et pour deux raison.

    1) Ma femme qui travaillait dans un office de tourisme à eu un jours la question "que signifie le ieu qu'on trouve dans les villes du coin ?" (jameyzieu, cremieu, tignieu, meyzieu, charvieux…) et donc grâce à la carte, je peux constater que c'est effectivement bien localiser cers chez nous.

    2) Toujours en lien avec l'anecdote si dessus, con comme je suis, je n'avais jamais pensé à chercher sur la page "suffixe -acum" pour avoir le suffixe -ieu… je suis pas excessivement malin. Du coup, merci pour ce journal qui a permit à un commentaire de pointer sur cette page qui m'a permis d'apprendre la signification de la vie, l'univers et… merde, non, la signification du "ieu"

    Sur ce, une longue journée m'attend demain.

    Faites de beaux rêves.

    • [^] # Re: Avec mes remerciement les plus sincère

      Posté par . Évalué à 4.

      Ma femme qui travaillait dans un office de tourisme à eu un jours la question "que signifie le ieu qu'on trouve dans les villes du coin ?" (jameyzieu, cremieu, tignieu, meyzieu, charvieux…) et donc grâce à la carte, je peux constater que c'est effectivement bien localiser cers chez nous.

      Arf, ma première recherche à aussi été sur le motif "ieu$". Je rajoute Charancieu, Fitilieu, Chamagnieu, Romagnieu, Montagnieu, Virieu, Dolomieu, Vignieu, Sermérieu,…

      C'est bô le Nord Isère et tous ses noms poétiques…

Suivre le flux des commentaires

Note : les commentaires appartiennent à ceux qui les ont postés. Nous n'en sommes pas responsables.