In [1]:
import pandas as pd
import numpy as np
import datetime as dt

Un peu de cartographie¶

On va regarder comment dessiner une carte géographique avec de l'information par dessus.

Note : si les cartes ne sont pas visibles à l'ouverture de la feuille, veuillez recalculer toutes les cellules avec Cell -> Run all.

Les données : le prix de l'essence¶

On récupère les prix du jour de l'essence dans les stations de France sur https://www.prix-carburants.gouv.fr/ (voir le programme prix_carburants.py qui fait le travail).

In [2]:
from data import prix_carburants
df = prix_carburants.get_gaz_price()
print("Nombre de données : ", len(df))
df.head()
Nombre de données :  33496
Out[2]:
adresse cp ville latitude longitude essence prix maj
0 596 AVENUE DE TREVOUX 01000 SAINT-DENIS-LèS-BOURG 46.201 5.198 Gazole 1.799 2024-02-22 00:46:00
1 596 AVENUE DE TREVOUX 01000 SAINT-DENIS-LèS-BOURG 46.201 5.198 SP95 1.884 2024-02-22 00:46:00
2 596 AVENUE DE TREVOUX 01000 SAINT-DENIS-LèS-BOURG 46.201 5.198 E85 0.849 2024-02-22 00:46:00
3 596 AVENUE DE TREVOUX 01000 SAINT-DENIS-LèS-BOURG 46.201 5.198 E10 1.848 2024-02-22 00:46:00
4 596 AVENUE DE TREVOUX 01000 SAINT-DENIS-LèS-BOURG 46.201 5.198 SP98 1.952 2024-02-22 00:46:00

Certaines données ne semble pas avoir été mises à jour, aussi je filtre :

In [3]:
df =df[df.maj > np.datetime64('today') - np.timedelta64(30)] # keep 30 last days of price updated
len(df)
Out[3]:
31643

Récupérons les 10 meilleurs prix et les 10 pires pour l'essence sans plomb 95 européenne (E10). Attention certaines stations ne mettent pas à jour leur prix ce qui fait qu'on peut avoir des prix d'il y a un an, donc totalement faux !

In [4]:
e10 = df[df.essence.isin(['E10', 'SP95'])].sort_values('prix')
print('Nombre de stations prises en compte : %d' % len(e10))
worst = e10[-10:]
best = e10[:10]
best
Nombre de stations prises en compte : 10597
Out[4]:
adresse cp ville latitude longitude essence prix maj
9189 ROUTE DE ST GILLES 30132 CAISSARGUES 43.784000 4.393000 SP95 1.193 2024-02-04 19:26:16
5035 1 RUE D'ALIGRE 17230 MARANS 46.311311 -0.991826 E10 1.715 2024-02-23 09:00:00
8819 137 Avenue Maréchal Foch 29400 Landivisiau 48.514888 -4.053751 E10 1.725 2024-02-24 05:57:00
8823 Boulevard de la République 29400 LANDIVISIAU 48.503959 -4.073226 E10 1.726 2024-02-23 08:27:15
15171 24 , ROUTE DE COUERON 44360 SAINT-ÉTIENNE-DE-MONTLUC 47.270000 -1.776000 E10 1.734 2024-02-23 08:29:41
15178 LIEU DIT TOURNEBRIDE 44360 Saint-Étienne-de-Montluc 47.278000 -1.721000 E10 1.734 2024-02-23 07:45:20
30689 rd pt de l'Europe parc Océanis 85800 Saint-Gilles-Croix-de-Vie 46.694000 -1.914000 E10 1.735 2024-02-25 01:17:00
30540 87 Avenue François Mitterand 85340 Olonne-sur-Mer 46.513501 -1.777663 E10 1.735 2024-02-25 01:17:00
30487 Avenue du Terre Fort Face Hyper U 85270 SAINT-HILAIRE-DE-RIEZ 46.713000 -1.961000 E10 1.735 2024-02-24 09:34:11
30533 73 Rue du 8 Mai 1945 85340 Olonne Sur Mer 46.543000 -1.772000 E10 1.735 2024-02-24 09:54:30

Parfois il y a des prix d'essence incroyablement bas, genre erreur. On pourrait filtrer par valeur aussi.

Folium¶

Folium est une des bibliothèques bien adaptée pour faire de la cartographie. Elle s'appuie sur la bibliothèque Javascript Leaflet laquelle utilise les cartes de

  • OpenStreetMap par défaut (libre)
  • Staten s'appuie sur OpenStreetMao mais produit un rendu différent
  • Boxmap (compte gratuit limité possible)

Il est possible d'utiliser les cartes de Google si on a un compte qui le permet avec FoliumGEE.

Fond de carte¶

Les principaux fonds de carte sont OpenStreetMap (par défaut), Stamen Terrain, Staten Toner, Statemen Watercolor, Mapbox Bright et Mapbox Control.

In [5]:
import folium

Marqueurs¶

On commence par placer des marqueurs avec folium.Marker et un joli cercle vert :

In [6]:
france = folium.Map(location=[46.8,2], zoom_start=6)

for lat,lon,val in zip(best.latitude, best.longitude, best.prix):
    folium.Marker((lat,lon), popup="%.2f €/l" % val).add_to(france)        # default marker
for lat,lon,val in zip(worst.latitude, worst.longitude, worst.prix):
    folium.Marker((lat,lon), 
                  icon=folium.Icon(color='red', icon='exclamation-sign'),  # custumized marker
                  popup="%.2f €/l" % val
                 ).add_to(france)
vb = best.iloc[0] # very best
folium.CircleMarker((vb.latitude,vb.longitude), radius=20, 
                    popup='Best !', color='green').add_to(france)
france
Out[6]:
Make this Notebook Trusted to load map: File -> Trust Notebook

Bien sûr on peut zoomer et déplacer la carte. On note que certaines coordonnées latitude/longitude sont approximatives...

Icônes¶

Pour les icônes possibles voir https://github.com/lvoogdt/Leaflet.awesome-markers

Objets géographiques¶

GeoJSON est un format ouvert pour définir des objets géographique. Folium permet d'afficher directement ces objets folium.GeoJson et folium.TopoJson (comme on a utilisé folium.Marker).

Mais on peut aussi colorier les objets ajoutés en fonction de données dans un tableau. Ainsi sur France Geojson on peut récupérer les entités administratives de la France ce qui va nous permettre de faire une carte coloriée avec le prix moyen de l'essence par département.

Pour cela il faut un DataFrame qui ait une valeur par département et donc aussi l'identifiant du département. Dans le fichier récupéré sur France Geojson, on note que le code des départements est une chaîne de 2 caractères. Il faut donc avoir la même chaine dans notre tableau.

In [7]:
df['département'] = df.cp.apply(lambda x:x[:2])
prix_dep = df[(df.essence == 'E10') & (df.maj + dt.timedelta(days=30) > dt.datetime.now())] \
             [['département','prix']].groupby('département', as_index=False).mean()
display(prix_dep.sort_values('prix').head(2))
display(prix_dep.sort_values('prix').tail(2))
département prix
27 29 1.787747
83 85 1.794893
département prix
90 92 1.934878
73 75 1.979611
In [8]:
france = folium.Map(location=[46.5,2], zoom_start=5)

colors = folium.Choropleth(geo_data = 'data/departements-version-simplifiee.geojson',
                           data = prix_dep,
                           columns = ['département', 'prix'],
                           key_on = 'feature.properties.code',
                           fill_color = 'YlOrRd',
                           fill_opacity = 0.6,
                           line_opacity = 0.2,
                           legend_name = "Prix de l\\'essence E10"
                          )
colors.add_to(france)
folium.LayerControl().add_to(france)
france
Out[8]:
Make this Notebook Trusted to load map: File -> Trust Notebook

La Corse pose un problème de notation (20 pour l'essence, 2A et 2B pour la carte).

Folium propose un résumé rapide qui reprend tout ces points.

Plotly¶

Plotly propose aussi d'afficher des cartes. Elle s'appuie sur Mapbox.

In [9]:
import plotly.express as px
import json

departements = json.load(open('data/departements-version-simplifiee.geojson'))

fig = px.choropleth_mapbox(prix_dep, geojson=departements, 
                           locations='département', featureidkey = 'properties.code', # join keys
                           color='prix', color_continuous_scale="Viridis",
                           mapbox_style="carto-positron",
                           zoom=4.6, center = {"lat": 47, "lon": 2},
                           opacity=0.5,
                           labels={'prix':'Prix E10'}
                          )
fig.update_layout(margin={"r":0,"t":0,"l":0,"b":0})
fig

Voici la liste des fonctionnalités offertes par Plotly :

No description has been provided for this image

In [ ]: