Creating an hex map of France electricity consumption

The French Ministry for the Ecological and Inclusive Transition (for which I’m currently working) is ongoing a process of opening data related to energy consumption. Each year, we publish data for every neighborhood in France (at the iris statistical level, even adresses in some cases) and to the nature of the final consumer (a household, an industry, a shop…). These data are available here (website in French – direct link to 2018 electricity consumption data).

Making a map to have an overlook at the situation isn’t easy, because the administrative boundaries of France are very diverse, and a direct mapping will reflect this situation. In order to overcome this issue, a solution is to use a different way to represent the country. In this post, we’re going to talk about hex map (as inspired by this website).

What’s a hex map? First, we need to talk about chloropleth maps; despite their unusual names, they’re perfectly common maps where each area is shaded or colored differently according to the values taking by a variable. They’re quite similar to maps such as this one showing which political party won an election on each voting district, but for continuous variable, and required a scale. To determine the color used for each area, we need to compute the average (or any statistical summary) of the values of every individual belonging in this area.

Hex map are entirely composed of hexagons (something perfectly suited for France!); they’re chloropleth maps, so each hexagon is colored depending on the values taking by a variable. The main difference is that the hexagon aren’t usual geographical areas so we need a way to attribute each value in our data set to one of the hexagons before calculating averages, and therefore colors.

In order to do that, we’re going to load some usual R-packages:

library(tidyverse)  
library(viridis)   
library(ggplot2)   
library(stringr)

Our objective will be to make an hex map of residential consumption of electricity in 2018. First, we need to import the data at iris level (doing this, we miss some of the electricity consumption only associated to larger geographical area, but it’s marginal); as the data is coded as strings with some missing values, we start by cleaning the data.

elec <- read.csv2("donnees_elec_iris_2018.csv",stringsAsFactors = F)
elec <- elec[elec$CONSO != "s" & elec$PDL != "s",] #"s" are missing values

# CONSO (electricity consumption) is coded with a french comma separator ; we need to substitute that and convert to numeric CONSO and PDL (number of  energy delivery points) 
elec$CONSO <- str_replace(elec$CONSO,",",".") 
elec$CONSO <- as.numeric(elec$CONSO)
elec$PDL <- as.numeric(elec$PDL)

# Select only residential sector
res <- elec[elec$CODE_GRAND_SECTEUR == "R",]

Each data point is then associated to the coordinates of the center of the neighborhood, using a iris shapefile (available here). The res dataset obtained looks like this:

  CODE_IRIS      CONSO  PDL     x    y
  100020000   843.8162  124 48.25 4.69
  100030000 10374.7166 1987 48.24 3.72
  100040000   679.8085   88 48.59 4.12
  100050000   769.8268  145 48.29 4.49
  100060000  7318.2055 1534 48.53 4.14
  100070000   429.9674   61 48.16 4.73
  100080000   343.1404   62 48.25 4.60
  100090000   262.1539   55 48.05 4.28
  100100000   140.5366   28 48.54 4.61
  100110000   700.1244  113 48.27 4.74

We’re using a ggplot2 environment to create our hex map. The aesthetics used are aes(x,y), the spatial coordinates. We begin by these line of code in order to use a simpler theme (as we’re creating a map, we don’t need any axis) and to specify the positions (longitude and latitude) we want to map.

c <- ggplot(res, aes(x, y))
c + 
xlim(-9, 12) +
ylim(40, 52) +   
theme_void() 

The main argument of the stat_summary_hex function we’re going to use is bins. This parameter allows us to choose how many hexagons will be displayed on the map; the more hexagon, the more small local variations are shown. For the other parameters, we specify aes(z = CONSO) as we want to color the hexagons in relation to the CONSO (Consumption in french) of the data points contained in this area. The fun = “sum” parameter means that the choice of the color of the hexagon depends on the total consumption inside. Lastly, we add a colour=”grey” parameter, which defines the color of every hexagon’s borders, because using white borders on my computer leads to some graphical artefacts (see here).

c <- ggplot(res, aes(x, y))
c +  stat_summary_hex(bins=40,aes(z = CONSO),fun = "sum", colour="grey") +
xlim(-9, 12) +
ylim(40, 52) +   
theme_void() 

We then define a scale (both numeric and in terms of colors) using the scale_fill_viridis function. In order to better see large differences, we use the trans=”log” option which means that transitions between colors are logarithmic and not arithmetic progressions. The breaks points used are 1 GWh, 10 GWh, 100 GWh and 1 TWh.

 c <- ggplot(res, aes(x, y))
c +  stat_summary_hex(bins=40,aes(z = CONSO),fun = "sum", colour="grey") +
xlim(-9, 12) +
ylim(40, 52) +   
theme_void() +
scale_fill_viridis(
 option="A",
 trans = "log", 
 breaks = c(0,1000,10000,100000,1000000,99999999999),
 name="Electricity Consumption", 
 guide = guide_legend(keyheight = unit(2.5, units = "mm"),      keywidth=unit(4, units = "mm"), 
label.position = "bottom", 
title.position = 'top', nrow=1) )  

Using the following code with bins = 80 results in this another map:

c <- ggplot(res, aes(x, y))
c +  stat_summary_hex(bins=80,aes(z = CONSO),fun = "sum", colour="grey") +
xlim(-9, 12) +
ylim(40, 52) +   
theme_void() +
scale_fill_viridis(
 option="A",
 trans = "log", 
 breaks = c(0,1000,10000,100000,1000000,99999999999),
 name="Electricity Consumption", 
 guide = guide_legend(keyheight = unit(2.5, units = "mm"),      keywidth=unit(4, units = "mm"), 
label.position = "bottom", 
title.position = 'top', nrow=1) )  

These map highlight the position of urban centers with high population density. A more useful information is the total electricity consumption per household (or, more accurately in this case, per energy delivery point, whose quantity per iris is PDL in the dataset), defined this way:

res$ElectricityPerHousehold <- res$CONSO/res$PDL

The code used to generate the map is slighty similar; the stat_summary_hex parameter are modified to aes(z = ElectricityPerHousehold) and fun=”mean”, and, scale_fill_viridis parameters are switched to option=”E” (leading to a new color scheme), new breakpoints of 2, 4, 6 and 8 GWh per household, and a new legend name.

 c <- ggplot(res, aes(x, y))
c +  stat_summary_hex(bins=80,aes(z = ElectricityPerHousehold),fun = "mean", colour="grey") +
xlim(-9, 12) +
ylim(40, 52) +   
theme_void() +
scale_fill_viridis(
 option="E",
 trans = "log", 
 breaks = c(0,2,4,6,8,10),
 name="Electricity Consumption per Household", 
 guide = guide_legend(keyheight = unit(2.5, units = "mm"),      keywidth=unit(4, units = "mm"), 
label.position = "bottom", 
title.position = 'top', nrow=1) )  

This map better hightlights places with large electricity consumptions; Paris and its suburbs are associated to lower consumptions per household, which contrasts with an unusually high total consumption, due to high population density. An high consumption per household is usually associated to electric heating and/or large houses, and parisian dwellings are mostly smaller flats.

Featured image: Electricity Converter Power, by ArtisticOperations

Comment expliquer la baisse de participation aux municipales 2020 ?

Dimanche dernier, le 15 mars 2020, la France a organisé le premier tour des élections municipales, après avoir annoncé une fermeture des écoles puis des restaurants et commerces non essentiels. La participation à ce scrutin s’établit à 44,64 %, en chute de 20 points par rapport à 2014, date des précédentes élections municipales (voir une très belle carte du Monde ici, assez illustrative de la situation)

Ce rapide billet ne s’attardera pas sur la question de savoir s’il fallait ou non organiser ces élections (le second tour est, lui, reporté à plus tard) ; nous cherchons ici à identifier quels sont les facteurs explicatifs de la baisse de participation aux municipales, et si ces facteurs peuvent avoir favorisé un ou plusieurs partis politiques.

Un sondage “jour de vote” réalisé par IFOP [modifié : je parlais dans la version initiale par erreur d’un sondage IPSOS ; celui-ci est consultable ici, et qui donne d’autres résultats encore, avec une plus forte participation à droite qu’à gauche sur l’échiquier politique] (consultable ici) montrait une importance du paramètre Covid-19 sur les raisons de ne pas aller voter (plus de 50% des sondés n’ayant pas voté jugeant que c’était une des raisons déterminantes), mais aussi une disparité entre les différentes familles politiques, avec une plus forte abstention chez les électeurs d’EELV (60 %) et une plus faible abstention chez les partisans d’En Marche (37 %).

Une analyse fine des résultats, bureau de vote par bureau, permet d’identifier les bureaux de vote pour lesquels l’évolution de l’abstention a été la plus forte entre 2014 et 2020 (on se limite au même scrutin des municipales), et, une fois ces bureaux de vote identifiés, analyser les résultats politiques obtenus au premier tour de l’élection présidentielle de 2017. Comme toujours, les données sont sur data.gouv.fr (ici pour les municipales 2020), merci à eux !

Le graphique ci-après résume les résultats obtenus :

On constate que les résultats ne sont pas les mêmes que ceux du sondage du jour du vote. Il semblerait que le vote Macron ou Le Pen, au premier tour en 2017, soit un bon indicateur d’une plus forte abstention aux municipales 2020. Cela ne veut cependant pas dire que les électeurs ayant choisi ces deux candidats sont plus sensibles au risques liées au Covid-19 ; peut-être est-ce plutôt lié à une séquence politique qui, pour les municipales 2020, n’était pas favorable à En Marche par exemple, même en l’absence de pandémie.

Méthodologie : les données relatives aux premiers tours des élections municipales de 2014 et 2020 ainsi que celles de la présidentielle 2017 sont agrégées au niveau du bureau de vote (on exclut ici les bureaux de vote ayant disparu, ayant fusionné ou ayant été créés). On calcule ensuite sur les un peu plus de 60 000 bureaux restants un différentiel de participation entre 2014 et 2020, qu’on régresse sur le taux parmi les votants pour chacun des candidats au premier tour de la présidentielle 2017.

Reports de voix à la présidentielle 2017

La question du report des voix entre les deux tours des élections, souvent primordiale pour les politologues et les journalistes politiques, s’est posée de façon particulièrement cruciale pour l’élection présidentielle 2017. En effet, les deux candidats qualifiés étaient issues de nouvelles formations, ou du moins de formations qui n’ont pas l’habitude de participer au second tour de la présidentielle (une fois pour le Front National, et jamais pour En Marche !). Nous allons reprendre la même façon d’aborder cette question que ce que nous avions fait pour l’élection présidentielle de 2012, en décembre dernier.

Les analyses de “report de voix” utilisent des données de sondage mais nous allons reprendre ici l’approche basée sur l’analyse de l’évolution du vote pour chacune des villes entre les deux tours de l’élection. Les données relatives au vote pour chacune des villes sont disponibles ici (premier tour) et ici (second tour).

Nous réalisont alors un modèle de régression linéaire entre les deux tours, pour évaluer quelle partie des votes alloués à chaque candidat au premier tour se reporte sur l’un des deux challengers, ou n’est pas exprimée (abstentions, blancs). Les résultats sont les suivants :

Macron Le Pen
Le Pen < 1 % 112 %
Macron 116 % < 1 %
Fillon 58 % 19 %
Melenchon 48 % 10 %
Dupont-Aignan 39 % 36 %
Hamon 95 % < 1 %
Asselineau 22 % 32%
Arthaud 51% 41%
Poutou 56 % 13 %
Cheminade 44 % 21 %
Lassalle 48 % 23 %

ou sous forme de graphique :

Comme nous l’avions déjà indiqué la dernière fois, il ne s’agit que d’un petit modèle sans grande prétention, et cela ne veut pas dire que 23% des électeurs de Jean Lassalle ont voté pour Martine Le Pen au second tour, mais on peut en déduire quelques remarques :

  • La somme des pourcentages donne une idée des électeurs qui n’ont pas souhaité participer au second tour. On voit que les électeurs de Asselineau puis de Mélenchon sont ceux qui ont le plus souvent voté blanc ou qui se sont abstenus au second tour ;
  • Inversement, pour Macron et Le Pen on observe un score estimé supérieur à 100%, cela signifierait que la mobilisation des électeurs ayant ces deux candidats préférés au premier tour se sont plus mobilisés au second ;
  • Les électeurs insoumis qui ont souhaité exprimer un vote en faveur d’un des deux candidats ont majoritairement choisi Macron ;
  • L’accord électoral entre Marine le Pen et Nicolas Dupont-Aignan n’aurait pas convaincu son électorat, qui se partagerait en parts égales pour les deux candidats ;
  • Le vote Hamon s’est quasiment à 100 % reporté sur le vote Macron ; ce n’est pas le cas de celui Fillon, qui s’est reporté de façon non négligeable pour Marine le Pen, et qui a entraîné plus d’abstention ou de vote blanc.

En comparaison, les reports de voix à la présidentielle 2012 étaient les suivants :

Prénoms au concours d’internat de médecine

Aujourd’hui, un petit article dans la lignée de la sociologie des prénoms, qu’on retrouve fréquemment associée avec les résultats du bac (voir ici par exemple pour un article de Rue89, ou ici pour le site originel). Nous allons nous intéresser aux résultats des ECN, les épreuves classantes nationales des études de médecine qui permettent de choisir les spécialités d’internat. Ils sont disponible sur Legifrance, à ce lien pour ceux de l’année 2016.

Nous allons réaliser un nuage de points sur ces prénoms : en ordonnée, on retrouve la fréquence des noms parmi la liste des 8000 et quelques admis(es), et abscisse, le rang moyen obtenu par les porteurs de ce prénom. On se limite aux prénoms les plus fréquents (plus de 10 inscrits). Voici les résultats obtenus (cliquer pour une version zoomée) :

On peut comparer cette image avec celle des résultats du bac 2015 :

On retrouve certes les mêmes noms parmi les plus fréquents (Marie, Camille, Thomas…) mais la structure dans les prénoms ne semble pas être la même ! Cela peut s’expliquer par un échantillon bien plus faible, et par des effets de sélection à d’autres niveaux dans les études de médecine.

EDIT 07/03 : Pour répondre au commentaire de Baptiste Coulmont, voici le graphe avec les rangs passés au logarithme. On voit effectivement que ce n’est pas exactement les mêmes résultats ; en particulier, il y a plus de noms de garçons qui ressortent dans les bonnes places.

[Dataviz] Odonymie et couleur politique

Les noms de rue peuvent être parfois un sujet politique sensible, comme l’a montré une actualité récente. L’odonymie (ou étude des noms des voies de communication) a déjà donné lieu à quelques dataviz sympathiques, comme par exemple sur le blog datamix, le site PatronyMap ou sur Slate. Disposant d’une base de données de noms de rues en France Métropolitaine, nous avons cherché à notre tour à illustrer le lien entre odonymes et politique par une petite dataviz.

Accéder à la dataviz
Cliquez pour accéder à la dataviz

On dispose de la liste des noms de rues pour 1470 grandes villes, que l’on classe en deux catégories “Droite” et “Gauche” suivant la couleur politique de leur mairie en 2012 (738 communes à gauche et 732 à droite). On entraîne ensuite un modèle de classification naïve bayésienne sur le TF-IDF constitué par cette liste d’odonymes, que l’on optimise classiquement par validation croisée sur sa qualité prédictive. Etant donnée une liste de noms de voies, le classificateur choisi permet d’identifier correctement la couleur politique de la ville dans environ 70% des cas. Ce chiffre plus élevé que ce à quoi nous nous attendions montre que l’influence de la politique sur les noms de rues (ou tout du moins la corrélation entre les deux) est réelle. Enfin, prédire correctement la couleur politique d’une ville à partir d’un ou ou plusieurs noms de rues n’est que peu intéressant en soi : le modèle entraîné vaut surtout pour son pouvoir explicatif (modèle de régression). C’est pourquoi on utilise les probabilités calculées par le classificateur pour construire une “typicité d’un nom de ville de droite/gauche”, qui est indiquée par la jauge dans notre dataviz.

En faisant tourner le modèle sur notre base de données, les valeurs des probabilités (typicités) obtenues vont de 0.25 à 0.75 (en prenant la convention “0 = gauche” et “1 = droite”), avec plus de 99% des valeurs entre 0.3 et 0.7. Notre jauge est recalibrée en conséquence avec un minimum à 0.3 et un maximum à 0.7, de manière à pouvoir observer correctement les valeurs.

En faisant quelques tests, on s’aperçoit d’une typicité bien plus marquée à gauche qu’à droite (le recall de notre modèle est d’ailleurs supérieur à 90% pour les villes de gauche). A première vue, les odonymes les plus typiques de la droite semblent très “traditionnels” (par exemple Rue de l’industrie ou Rue des Fleurs) alors que les odonymes les plus typiques de la gauche mettent plutôt en avant des personnalités (rue Jean Jaurès, rue Salvador Allende, etc.). Partant de ce constat, on aurait très envie de pouvoir tester si le fait de renommer une rue est plus le fait de la gauche que de la droite, mais on ne dispose pas de données sur les renommages qui permettraient de le faire. Peut-être une prochaine fois ?

Certaines disparités régionales transparaissent également (testez par exemple rue des Alpes vs. rue des Pyrénées ou rue Eric Tabarly vs. rue des Cigognes), et curieusement le type de voie est parfois très influent (“quai” penche à gauche alors que “traverse” penche à droite). Les noms issus du communisme quant à eux penchent certes à gauche, mais peut-être pas autant que l’on aurait pu imaginer (avenue de l’Union Soviétique, avenue Karl Marx). Il faut se souvenir que notre modèle prend en compte la couleur politique de 2016, et que l’orientation politique de certaines villes ont pu changer depuis le moment où ces rues ont été baptisées. Enfin, gardez à l’esprit que cette dataviz n’est que l’illustration d’un modèle et qu’a fortiori rien de ce qui peut être indiqué n’a de valeur sociologique ou politique. N’hésitez pas à mener vos propres tests, et à nous envoyer/tweeter vos trouvailles les plus intéressantes !