R calendar heatmap: densité de données temporelles

Toujours à la pointe de l’actualité1, je vous propose pour ce Vendredi Saint de nous intéresser à la visualisation de décès. Même si j’arrive bien après la guerre (ou plutôt ses commémorations) cela concerne plus particulièrement les morts pour la France de la Première Guerre mondiale.

En réalité je vous propose surtout une technique de représentation d’évènements temporels : une carte de densité temporelle (ou calendar heatmap). L’usage de cette représentation devient de plus en plus courante depuis son usage sur la forge de développement de logiciels GitHub. Elle permet de se faire une idée assez rapide de la distribution des évènements. Jugez par vous même:

Densité temporelle des morts pour la France nancéiens

Je ne vais pas m’attarder sur l’interprétation historique de ces données qui dépasse mes compétences d’amateur. On peut cependant noter comment ce petit jeu de 3688 natifs de Nancy, et décédés sur différents champs de bataille ou après des soins plus ou moins long, correspond très bien aux différentes phases de la guerre (les batailles identifiées par des caractères sur le graphique). Chaque début d’offensive apparaît nettement … avec un pic de décès.
Alors que le jour le plus meurtrier de la première guerre serait le 22 août 1914, avec ses 27000 soldats français tués, le graphique fait un apparaître un maximum de 232 morts deux jours plus tôt : le 20 août 1914. Ils sont certainement liés à la défaite spécifique de Morhange. On voit alors également apparaître la victoire sanglante de la trouée de Charmes des 24 et 25 août et les atermoiements allemands entre le 21 et 24 août. Ces légères variations seraient spécifiquement lorraines.
Il faut également noter l’étrange premier mort pour la France du 14 avril 1914. Il s’agit d’une possible erreur de saisie qu’il faudrait vérifier et corriger.
Ce type de représentation graphique permet alors de vérifier rapidement les données collectées et d’identifier des points d’attention particulier.

En réalité, j’utilise ce type de représentation pour mon travail mais avec des données d’un domaine très différent que je ne diffuse pas publiquement. À mon sens, il est préférable que ces techniques et outils soient accessibles pour que chacun puisse en faire usage plutôt que les conserver sur mes disques durs ou dans le cercle restreint de mes collègues.

Choix des données

Il s’agissait dans un premier temps de trouver des données intéressantes à examiner. Si les nombres de morts globaux ou par bataille de la Première Guerre sont largement connus, je m’interrogeais sur la densité de ces décès. J’aurais bien collecté les données concernant Metz mais il existe seulement 169 natifs de Metz morts pour la France. La majorité est plutôt composée de mort pour l’empire Allemand. Comme mon niveau d’allemand ne me permet de trouver ces données, je me suis tourné vers une grande ville proche de Metz: Nancy.

Le très bon site MémorialGenWeb donne accès, depuis 2000, aux bases de données de Morts pour la France de soldats ou civils. J’ai utilisé alors les données d’un des Livres d’Or créés en 1919 par le ministère des pensions.
J’aurais pu les contacter pour obtenir ces données mais je trouvais plus amusant (et plus générique) de les collecter directement sur le site.

Collecte des données

La plupart des langages de programmation modernes sont aujourd’hui capable de télécharger et analyser une page HTML. Comme j’apprécie particulièrement la souplesse du langage Perl, je vous propose alors un script pour «scraper» ces données.
Deux petites astuces spécifiques à ce site sont utilisées. Pour commencer, MémorialGenWeb protège les données contre l’accès par des robots de collecte qui ne respecteraient pas les indications standard de non-traitement. Cette protection se base sur une confirmation d’accès depuis un navigateur. Il faut alors récupérer le cookie de session PHPSESSID depuis son navigateur et modifier le script pour enregistrer votre valeur personnelle.
La seconde astuce est algorithmique : la donnée qui nous intéresse se trouve dans une cellule de style .corptable. Il s’agit de la cellule suivant la cellule de type .corptableR. Il faut alors détecter et vérifier que la cellule .corptableR concerne bien 1914-1918, puis utiliser un indicateur qui collecte la valeur suivante.

Page HTML

Traitement et affichage du graphique

Pour la visualisation de données, j’utilise la logiciel de statistiques R.
R est également un langage et aurait pu également «scraper» les page HTML.

Un simple fichier texte permet d’adapter facilement les données à afficher.

require(tidyverse)

title <- "Première Guerre Mondiale: densité des morts pour la France nancéiens"

# Données étendues en surcharge
e <- read_csv("batailles.csv")
# Données de type "Date,Quantité"
d <- read_csv("scrapmemorialgenweb-nancy.csv")

# Valeurs à afficher en sous-titre ou légende
date <- d$Date
val <- d$Quantité
max <- head(d[rev(order(d$Quantité)),],1)
start <- as.Date(head(date,1), format = "%Y-%m-%d")
end <- as.Date(head(rev(date),1), format = "%Y-%m-%d")

stitle <- sprintf("%s - %s : %d morts au Livre d'Or du ministère des pensions
Bataille des (f)rontières, (m)arne, (a)rtois, (c)hampagne, (.)verdun, (s)omme, (C)hemin des Dames",
   format(start, format = "%d %b %Y"),
   format(end, format = "%d %b %Y"), sum(val) )

leg <- sprintf("Quantités (log10) - Max %s  %d morts",
   format(max$Date, format = "%d %b %Y"), max$Quantité)

# Script de traitement
source("calendarHeatmap.R")

# Génération de l'image
calendarHeatmap(date, val, title = title,
    subtitle = stitle, legendtitle = leg,
    e$Date, e$Bataille)

# Enregistrement de l'image
ggsave("morts.png", width = 13, height = 10, dpi = 90)

Vous pouvez télécharger calendarHeatmap.R.
Il s’agit d’une adaptation personnelle du code de Dominik Koch. J’y ai ajouté la version française et la possibilité d’étendre l’affichage avec des caractères particuliers à des dates données. Ici il s’agit d’indicateurs visuels des grandes batailles.
Attention lors de l’usage de ce script, par défaut l’affichage des quantités suit une règle logarithmique. Si les variations de données sont linéaires, il suffit de commenter le ligne identifiée par le commentaire XXX

Données

Solutions alternatives

Pour vous permettre de créer vos propres représentations

avec R

avec javascript

  1. C’est bien entendue une plaisanterie, ce blog continuera d’être alimenté à la vitesse de mon temps libre et de mes centres d’intérêts particuliers