Accueil / Blog / Métier / 2013 / Des cartes avec GeoDjango et Leaflet

Des cartes avec GeoDjango et Leaflet

Par Mathieu Leplatre publié 05/09/2013, édité le 29/01/2014
Un guide pas à pas pour visualiser vos modèles Django avec Leaflet
Des cartes avec GeoDjango et Leaflet

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érologiques 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.

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 !

/blog/metier/weather-stations-qgis.png

( 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, et 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 !

/blog/metier/weather-stations-leaflet.png

Aller plus loin...

Il s'agit d'une introduction, mais cela s'applique à tous les types de géometries (lignes, polygones, ...)

J'ai publié le project 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 oeil 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 toutes façons, 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 ;
  • ...

Cela nous ouvre des pistes à explorer et de quoi alimenter le blog :)

ABONNEZ-VOUS À LA NEWSLETTER !
Voir aussi
Python : Bien configurer son environnement de développement Python : Bien configurer son environnement de développement 07/12/2015

Comment utiliser les bonnes pratiques de développement Python.

Elections.js génère des cartes pour vous Elections.js génère des cartes pour vous 30/03/2015

Le travail sur les cartes pour les élections départementales a débouché sur la création d'un ...

À Makina, la JS fatigue n'existe pas... 08/02/2017

...car la passion l'emporte

Formation Django initiation à Toulouse du 13 au 15 mars Formation Django initiation à Toulouse du 13 au 15 mars 26/01/2017

Entrez de plain-pied dans l'univers de Django aux côtés de développeurs ayant une expérience de ...

Geotrek - 1ère rencontre des utilisateurs 21/12/2016

La communauté Geotrek, regroupant environ 60 personnes, s'est retrouvée le 18 octobre 2016 à ...