python
¶Dans ce TP, nous allons aborder l'aspect cartographie sous python
avec le package folium
(à installer donc). L'idée sera d'ajouter à un fond de carte des formes de couleurs, en fonction d'une information tierce.
Le package folium
est une interface entre python
et la librairie leaflet
. Elle s'utilise très facilement, comme nous pouvons le voir ci-dessous pour la création d'une carte. Les coordonnées indiquées sont la latitude et la longitude de New-York.
import folium
centre = [40.71427, -74.00597]
newyork = folium.Map(location = centre, zoom_start = 12)
Pour obtenir la carte, il suffit d'appeler l'objet ainsi créé.
newyork
La fonction Marker()
permet d'ajouter une marque sur la carte pour signifier un emplacement précis. Il est possible de spécifier un contenu à afficher (sous la forme d'un pop-up) lorsque l'utilisateur va cliquer sur le marqueur. Celui-ci sera placé à la localisation fournie en premier, au format [latitude, longitude]
. Ce contenu est spécifié dans l'argument popup
(ici, une simple chaîne de caractères, mais cela peut être plus élaboré). Il est aussi possible customiser l'icône du marqueur. Une fois ce marqueur créé, il faut l'ajouter à la carte, via la fonction add_to()
.
folium.Marker(centre, popup = "New-York").add_to(newyork)
newyork
La fonction CircleMarker()
permet elle de créer des cercles, en donnant la localisation du centre et le rayon (via le paramètre radius
). Idem que pour Marker()
, on peut spécifier le contenu de la popup affichée lors d'un clic, et il est nécessaire de l'ajouter à la carte. Il est possible aussi de spécifier la couleur du cercle (via color
) et la couleur de remplissage (via fillColor
).
folium.CircleMarker(centre, popup = "New-York", radius = 10).add_to(newyork)
newyork
Pour pouvoir ajouter ces informations, nous allons importer les contours des 5 quartiers new-yorkais disponibles dans ce fichier. Les données à récupérer sont celles au format GeoJSON
. Vous devez les sauvegarder, idéalement dans le même répertoire que votre notebook.
import json
geo = json.load(open("newyork-borough.geojson"))
geo.keys()
Le format GeoJSON est de plus en plus utilisé pour représenter des données de type géographique. Il suit des spécifications précises, et peut être utilisé directement comme nous le verrons plus loin.
Dans cet objet, transformé en dictionnaire sous python
, il y a deux éléments : le type et les informations (nommées features
)
geo.keys()
geo["type"]
Nous vérifions bien que nous avons les 5 quartiers de New-York dans l'objet features
, qui est une list
.
len(geo["features"])
Dans chaque objet de cette liste, nous disposons aussi de différents objets de type Feature
.
geo["features"][0].keys()
geo["features"][0]["id"]
geo["features"][0]['type']
Dans le champs properties
, il y a différentes informations utiles, dont les coordonnées longitude et latitude du centre.
geo["features"][4]['properties']
Et dans la partie geometry
, nous voyons que c'est un MultiPolygon
qui est représenté, avec toutes les coordonnées des sommets de ce polygone.
geo["features"][0]['geometry']
Avec les informations contenues dans ce fichier, nous allons pouvoir ajouter un marqueur pour chaque quartier, en mettant dans la popup, son nom.
newyork_qu_marker = folium.Map(location = centre, zoom_start = 11)
for qu in geo["features"]:
prop = qu["properties"]
folium.Marker(prop["coordinates"], popup = prop["BoroName"]).add_to(newyork_qu_marker)
newyork_qu_marker
Toujours avec les mêmes informations, nous pouvons disposer des cercles pour chaque arrondissement. Ici, nous décidons de régler la taille des cercles (via radius
) en fonction de la surface des arrondissements. Nous remarquons que nous devons faire cela manuellement (ici, on divise la surface par 1000000 pour avoir des tailles raisonnables).
newyork_qu_circle = folium.Map(location = centre, zoom_start = 11)
for qu in geo["features"]:
prop = qu["properties"]
folium.CircleMarker(prop["coordinates"],
popup = prop["BoroName"],
radius = prop["Shape_Area"] / 1e08,
fill = True).add_to(newyork_qu_circle)
newyork_qu_circle
Enfin, il est possible de faire des cartes choroplètes, dans lesquelles les zones sont coloriées selon une mesure statistique.
Pour cela, nous devons devons utiliser la fonction choropleth()
de la carte créée. Nous passons dans le paramètre geo_data
les données contenues dans le fichier GeoJSON
importées plus haut.
newyork = folium.Map(location = centre, zoom_start = 10)
newyork.choropleth(geo_data = geo)
newyork
Bien évidemment, nous désirons ajouter une couleur. Pour cela, nous avons besoin d'un DataFrame
contenant deux variables :
GeoJSON
Pour le construire, nous allons récupérer le nom du quartier (item BoroName
dans properties
) et la surface (Shape_Area
dans properties
). Voici comment les récupérer.
[qu["properties"]["BoroName"] for qu in geo["features"]]
[qu["properties"]["Shape_Area"] for qu in geo["features"]]
Nous créons donc maintenant le DataFrame
avec ces deux informations.
import pandas
df = pandas.DataFrame({
# "BoroCode" : [qu["properties"]["BoroCode"] - 1 for qu in geo["features"]],
"Quartier": [qu["properties"]["BoroName"] for qu in geo["features"]],
"Surface" : [qu["properties"]["Shape_Area"] / 1e08 for qu in geo["features"]]
})
df
Pour relier ces informations à la carte, toujours dans la fonction choropleth()
, nous devons définir les éléments suivants :
geo_data
: les contours au format GeoJSON
key_on
: l'item dans le GeoJSON
avec lequel nous ferons la jointuredata
: le DataFrame
dans lequel nous avons les informations statistiquescolumns
: les deux colonnes à prendrefill_color
: la palette de couleurs à utiliser (provenant de Color Brewer)Nous obtenons maintenant la carte suivante.
newyork = folium.Map(location = centre, zoom_start = 10)
newyork.choropleth(geo_data = geo, key_on = "feature.properties.BoroName",
data = df, columns = ["Quartier", "Surface"],
fill_color = 'Spectral',
legend_name = "Surface du quartier de New-York")
newyork
Nous allons utiliser une base de données des restaurants new-yorkais disponible dans ce fichier (attention : il fait environ 10 Mo). Nous disposons de deux niveaux d'informations géographiques dans la base des restaurants new-yorkais :
Avec ces deux informations, nous allons donc pouvoir créer des cartes, soit avec des points pour chaque station, soit des formes pour les quartiers. Sur cette base, vous devez faire les demandes suivantes :
Vous trouverez ci-dessous le code pour importer les données dans python.
import bson
donnees = bson.decode_all(open('restaurants.bson', 'rb').read())
donnees[:1]