24. Carte de densité#

L’enjeu de cet exercice est de parvenir à réaliser une carte de France affichant les densités de population enregistré durant les derniers recensements. Pour cela, nous avons récupéré le fichier insee_rp_hist_1968.csv qui contient les colonnes suivantes :

  • codgeo est l’indentifiant unique d’une ville ;

  • libgeo est le libélé d’une ville ;

  • an est l’année du recensement ;

  • dens_pop est la densité de population.

Pour afficher ces information sur une carte, il nous manque les coordonnées de chaque ville. Par chance, nous avons déjà le fichier communes_2021.csv qui complète ces informations. Il contient les colonnes suivantes.

  • Geocode est l’identifiant unique d’une ville ;

  • nom est le libélé d’une ville ;

  • latitude et longitude sont les coordonnées ;

  • population est la population en 2021.

Voici comment nous allons procédé.

  1. Nous lirons les informations contenues dans le fichier communes_2021.csv et les stocker dans un dictionnaire.

  2. Nous lirons celles du fichier insee_rp_hist_1968.csv et nous les stockerons dans un autre dictiionnaire.

  3. Nous fusionnerons les informations des deux dictionnaires.

  4. Enfin nous créerons une heatmap avec folium.

24.1. Lecture du fichier des communes#

Exercice : Écrivez une fonction read_city_file qui prend en paramètre le chemin vers le fichier csv communes_2021.csv et renvoie un dictionnaire de la forme suivante. Il associe à un geode donnée, les informations concernant la ville, à savoir : son nom et ses coordonnées. Notons que les coordonnées sont converties en nombre à virgule.

{'64001': {'nom': 'Aast',
  'latitude': 43.291192630916704,
  'longitude': -0.08172502738117142},
 '55001': {'nom': 'Abainville',
  'latitude': 48.53272044504441,
  'longitude': 5.51487324547426},
 '60001': {'nom': 'Abancourt',
  'latitude': 49.965002813144096,
  'longitude': 2.488730102972196},
  ...
def read_city_file(f):
    pass

24.2. Lecture du fichier de densité#

Lisons maintenant les données contenues dans le fichier insee_rp_hist_1968.csv. Nous souhaitons les stocker dans un dictionnaire ayant la forme suivante. Il associe à un geode donnée, les informations concernant les recesement. Donc pour une géocode donnée, le dictionaire contient autant d’année que de recensement. Chaque année est associé à la densité de population mesuré. Notons que les densités sont converties en nombre à virgule. Attention, il existe des erreur dans le fichier des densités. Certaines densités sont vides.

{'1001': {'1968': '21,76',
  '1975': '23,07',
  '1982': '29,91',
  '1990': '36,3',
  '1999': '45,64',
  '2008': '49,59',
  '2013': '48,09',
  '2018': '48,34'},
 '1002': {'1968': '9,62',
  '1975': '11,58',
  '1982': '14,86',
  '1990': '17,38',
  '1999': '18,36',
  '2008': '21,2',
  '2013': '25,79',
  '2018': '27,65'},
  ...

Exercice : Écrivez une fonction read_density_file qui prend en paramètre le chemin vers le fichier csv insee_rp_hist_1968.csv et renvoie le dictionnaire comme ci-dessus.

def read_density_file(f):
    pass

24.3. Fusion des données#

Nous allons créer un nouveau dictionnaire qui fusionnera les informations contenues dans les deux dictionnaires de coordonnées et de densités. Nous n’intègrerons une ville dans le nouveau dictionnaire que si elle est présente à la fois dans le dictionnaire de coordonées et dans celui de densités.

Voici ce que vous devirez obtenir comme résultat.

{'64001': {'nom': 'Aast',
  'latitude': 43.291192630916704,
  'longitude': -0.08172502738117142,
  '1968': '42,74',
  '1975': '24,21',
  '1982': '29,47',
  '1990': '34,32',
  '1999': '40',
  '2008': '38,11',
  '2013': '37,47',
  '2018': '38,95'},
 '55001': {'nom': 'Abainville',
  'latitude': 48.53272044504441,
  'longitude': 5.51487324547426,
  '1968': '26,99',
  '1975': '23,92',
  '1982': '25,53',
  '1990': '22,31',
  '1999': '23,26',
  '2008': '23,48',
  '2013': '21,73',
  '2018': '21,65'},
  ...

Exercice : Écrivez une fonction fusion qui prend en paramètre un dictionnaire de coordonées et un dictionnaire de densité et renvoie un nouveau dictionnaire comme ci-dessus.

def fusion(coordinates, densities):
    pass

Si vous affichez la taille des dictionnaires respectifs, vous devriez obtenir les valeurs suivantes. Elles nous indiquent en particulier que le fichier de densité contenait plus de villes que celui des coordonnées.

data = fusion(cities, densities)
print(len(coordinates))
print(len(densities))
print(len(data))
32683
34965
32683

24.4. Heatmap#

Pour créer une heatmap, nous avons besoin d’un ensemble de valeurs de la forme suivante : [lat, lng, weight]. Le poids, weight doit être une valeur comprise entre 0 (exclu) et 1 (inclu). Pour plus d’informations, vous pouvez consulter la documentation de la fonction heatmap.

La première étape est donc de trouver quelle est la densité maximum dans nos données pour ensuite pouvoir normaliser les valeurs.

Exercice : Écrire une fonction find_maximum qui parcours les données et renvoie la densité maximum pour toutes villes et toutes années.

def find_maximum(data):
    pass

Vous devriez trouver 27309.96.

Pour afficher la densité d’une année en particulier, il faut créer une liste de valeurs de la forme suivante.

[(43.291192630916704, -0.08172502738117142, 0.0001280237198559534),
 (48.53272044504441, 5.51487324547426, 0.00010983646932824074),
 (49.965002813144096, 2.488730102972196, 0.00016185140750861465),
 (48.89237421486775, 6.26546345064283, 0.00012064757099993821),
 (49.19723198916412, 5.548973627354689, 8.61421943695134e-05),
 ...

La liste contient de tuple. Chaque tuple est composé de la latitude, la longitude et la densité, normalisé (donc entre 0, exclu et 1, inclu). La fonction suivante semble donnée des résultats intéressants. L’idée est d’avoir une fonction qui n’est pas linéaire pour marqué un peu plus les valeurs extrèmes.

def normalize(i, max_density):
    return (i**(1/3)/max_density**(1/3))

Exercice : Écrivez une fonction extract qui prend en paramètre des données et une année et renvoie une liste de tuples dont la valeur de densité est normalisée.

def extract(data, year, max_density):
    pass

On pourra ainsi facilement récupérer les données pour année voulue. data1968 = extract(data, "1968").

Nous pouvons maintenant utiliser folium pour l’affichage d’une heatmap. Voici un exemple de code qui devrait vous permettre de générer la carte ci-dessous. En zoomant, vous verrez que l’on observe quelques abérations, en particulier dans Paris. C’est normal car l’échentillonage n’est pas idéal. Nous avons une unique donnée pour chaque ville, ca ne permet pas une bonne répartition spaciale des informations. Il serais préférable disposer des ces informations au niveau des IRIS.

import folium
import folium.plugins

years = ["1968", "1975", "1982", "1990", "1999", "2008", "2013", "2018"]
max_density = find_maximum(data)
data1968 = extract(data, "1968", max_density)

m = folium.Map([46.4, 2.6], tiles="stamentoner", zoom_start=6)
gradient={0.2: 'blue', 0.4: 'lime', 0.5: 'yellow', 0.95: 'orange', 1: 'red'}

hm1968 = folium.plugins.HeatMap(data1968,
                gradient=gradient, 
                min_opacity=0.01, 
                max_opacity=0.95, 
                radius=15,
                use_local_extrema=False)

hm1968.add_to(m)
m
Make this Notebook Trusted to load map: File -> Trust Notebook

Maintenant, nous pouvons même afficher deux années différentes et comparer les résultats.

m = folium.plugins.DualMap(location=(47.6, 3.7), zoom_start=6)
data2018 = extract(data, "2018", max_density)


hm1968 = folium.plugins.HeatMap(data1968,gradient=gradient, 
                min_opacity=0.01, 
                max_opacity=0.95, 
                radius=15,
                use_local_extrema=False)

hm2018 = folium.plugins.HeatMap(data2018, gradient=gradient, 
                min_opacity=0.01, 
                max_opacity=0.95, 
                radius=15,
                use_local_extrema=False)

hm1968.add_to(m.m1)
hm2018.add_to(m.m2)
m
Make this Notebook Trusted to load map: File -> Trust Notebook