Makina Blog

Le blog Makina-corpus

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

Formations SIG / Cartographie

Formation Leaflet

À distance (FOAD) Du 1er au 2 juillet 2024

Voir la formation

Formations Django

Formation Django initiation

Toulouse Du 26 au 28 juin 2024

Voir la formation

Actualités en lien

Image
SOTM-24
16/05/2024

La carto­gra­phie libre à l’hon­neur : Makina Corpus spon­sor State of the Map Fr 2024

Makina Corpus soutient State of the Map France à Lyon du 28 au 30 juin, l’évé­ne­ment qui rassemble les passion­nés de carto­gra­phie et la commu­nauté OpenS­treet­Map.

Voir l'article
Image
SIG_velo
10/03/2015

Carte des vélos de Toulouse avec Leaflet

Les bookmarks, un peu comme les cahiers de recettes…

Voir l'article
04/03/2015

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

Voir l'article

Inscription à la newsletter

Nous vous avons convaincus