Makina Blog
Des cartes avec GeoDjango et Leaflet
Un guide pas à pas pour visualiser vos modèles Django avec Leaflet.
Cet article est une brève introduction au Web Mapping avec Django, en utilisant deux applications développées par Makina Corpus : django-leaflet et django-geojson.
Nous allons construire une carte avec les stations météorologiques du monde.
Une station météo
Chaque station a un identifiant, un nom et une position.
En GeoDjango, le modèle donne ça :
# models.py
from django.db import models
from django.contrib.gis.db import models as gismodels
class WeatherStation(gismodels.Model):
wmoid = models.IntegerField(primary_key=True) name = models.CharField(max_length=256)
geom = gismodels.PointField()
objects = gismodels.GeoManager()
def __unicode__(self):
return self.name
Charger des données réelles
L'Organisation Mondiale de la Météorologie publie une liste de toutes les stations météo du monde, au format CSV. Vous pouvez lancer une recherche en filtrant par les critères souhaités ou aucun critère si toute la liste est souhaitée, puis cliquez sur le bouton "Download" pour l'exporter en CSV.
Malheureusement, le format n'est pas très pratique, les latitudes et longitudes en particulier :
StationId StationName Latitude Longitude ...
60351 JIJEL- ACHOUAT 36 48 00N 05 53 00E
...
07630 TOULOUSE BLAGNAC 43 37 16N 01 22 44E
...
Nous allons convertir les coordonnées en degrés minutes secondes vers des degrés décimaux :
def dms2dec(value):
""" Degres Minutes Seconds to Decimal degres """
degres, minutes, seconds = value.split()
seconds, direction = seconds[:-1], seconds[-1]
dec = float(degres) + float(minutes)/60 + float(seconds)/3600
if direction in ('S', 'W'):
return -dec
return dec
Pour ensuite créer une instance de notre modèle pour chaque ligne du fichier CSV :
import csv
from django.contrib.gis.geos import Point
from webmap.models import WeatherStation
csv_file = 'Pub9volA130819x.flatfile.txt'
reader = csv.DictReader(open(csv_file, 'rb'), delimiter="t")
for line in reader:
lng = dms2dec(line.pop('Longitude'))
lat = dms2dec(line.pop('Latitude'))
wmoid = int(line.pop('StationId'))
name = line.pop('StationName').title()
WeatherStation(wmoid=wmoid, name=name, geom=Point(lng, lat)).save()
Ça y est, notre table est remplie (~ 12000 enregistrements) !
Si on l'ouvre avec un outil graphique, comme QGIS, c'est touffu !
Si vous voulez un script qui convertit le CSV des stations vers un simple GeoJSON, vous pouvez utiliser ce morceau de code.
Visualiser sur la carte
Avec django-leaflet, après avoir ajouté leaflet
au setting INSTALLED_APPS
, vous pouvez ajouter des cartes dans les templates :
{% load leaflet_tags %}
<html>
<head>
{% leaflet_js %}
{% leaflet_css %}
</head>
<body>
<h1>Weather Stations</h1>
{% leaflet_map "main" callback="main_map_init" %}
<script type="text/javascript">
function main_map_init (map, options) {
// Use Leaflet API here
}
</script>
</body>
</html>
Une carte vide s'affiche, avec un fond basique OpenStreetMap.
Données vectorielles
Nous souhaitons maintenant placer des marqueurs à l'emplacement de chaque station météo. Pour ça, nous utilisons django-geojson, qui fournit une vue de base très simple :
# urls.py
from djgeojson.views import GeoJSONLayerView
from webmap.models import WeatherStation
urlpatterns = patterns(
url(r'^data.geojson$', GeoJSONLayerView.as_view(model=WeatherStation), name='data'),
)
Les données sont ensuite chargées en Ajax, puis ajoutées en tant que couche sur la carte, et ce dans la fonction d'initialisation que nous avions laissée vide à l'extrait précédent :
function main_map_init (map, options) {
var dataurl = '{% url "data" %}'; // Download GeoJSON via Ajax
$.getJSON(dataurl, function (data) {
// Add GeoJSON layer
L.geoJson(data).addTo(map);
});
}
La carte s'affiche et se remplit avec les stations !
Aller plus loin…
Il s'agit d'une introduction, mais cela s'applique à tous les types de géométries : lignes, polygones, …
J'ai publié le projet complet si vous voulez partir d'un exemple concret.
Mais si vous êtes à l'aise en Django, il n'y aura pas de surprise : jetez un œil aux documentations de Leaflet, django-leaflet and django-geojson pour avoir une idée des possibilités offertes.
Performance
Une carte avec plus de 12 000 objets HTML ne sera pas réactive. Il y a peu de chances ceci dit, que ce soit le cas de votre première application !
Et de toute façon, heureusement, il y a énormément de stratégies différentes pour visualiser une telle quantité de données :
- Utiliser des clusters pour réduire le nombre d'éléments dans la carte : voir résultat ici
- Dessiner des cercles au lieu des marqueurs et passer aux Canvas (voir la documentation de Leaflet)
- Utiliser des geojson tuilés
- Faire le rendu de tuiles avec Tilemill/Mapnik, etc.
Cela nous ouvre des pistes à explorer et de quoi contribuer à des projets cartographiques libres :-)
Formations associées
Actualités en lien
Mini-guide à l’usage des collectivités : l’Open Data, entre nécessité et opportunité
Tout ce que vous avez toujours voulu savoir sur l’Open Data. Petit guide à destination des collectivités pour l’appréhender et se l’approprier.
Carte des vélos de Toulouse avec Leaflet
Les bookmarks, un peu comme les cahiers de recettes…
Créer une heatmap de données raster avec Leaflet
Comment nous avons analysé des images côté client en canvas pour produire une heatmap avec Leaflet