Aller au contenu

À la découverte de prettymaps#

📆 Date de publication initiale : 5 décembre 2023

Introduction#

logo ArtSIG

À l'occasion des cours que je donne à l'École Urbaine de Sciences Po Paris, j'aime à proposer aux étudiants/es d'autres outils que le seul logiciel SIG. C'est ainsi qu'aux côtés de Khartis et kepler.gl notamment, je leur ai présenté la pépité dénichée par Nicolas Rochard dans la revue de presse du 18 mars 2022 : prettymaps.

prettymaps - Heerhugowaard

Cette bibliothèque Python est un générateur de cartes statiques stylisées à partir d'une simple adresse, en utilisant les données OpenStreetMap et les bibliothèques osmnx, GeoPandas et Matplotlib. Elle est l'oeuvre de Marcelo de Oliveira Rosa Prates, un Brésilien docteur en Computer Science et Machine Learning qui :

  • 💓 aime partager son travail et jouer avec les intelligences artificielles pour créer des visualisations intéressantes qu'il expose sur son portfolio
  • 💔 n'aime pas les NFT ou toute autre technologie purement vénale sans considération pour l'environnement. Merci de respecter ses valeurs.

Il y a déjà de nombreuses ressources et posts (notamment sur LinkedIn) sur prettymaps mais je n'ai rien trouvé en français ni rien qui ne détaille vraiment le fonctionnement. Alors c'est parti !

Commenter cet article


Prérequis logiciels#

  • Python 3.9+, correctement configuré dans le PATH. Pour Windows, voir cet article.
  • une connexion internet
  • un terminal. Sur Windows, privilégier Windows Terminal

Installation#

logo Python

Dans ses premières versions, le projet était difficilement installable à cause d'un packaging foireux (dépendances non déclarées ou non épinglées, police d'écriture manquante...). Depuis, Marcelo a clairement corrigé le tir. Le plus simple est d'utiliser le gestionnaire de paquets Python (pip) depuis un terminal, de préférence dans un environnement virtuel en lançant la commande adaptée à votre système.

pip install prettymapsInstalling collected packages: prettymaps
Successfully installed prettymaps-1.0.0

Exemple sur Ubuntu LTS (22.04 à date) :

python3 -m pip install --upgrade prettymaps

Dans une fenêtre PowerShell :

py -3 -m pip install --upgrade prettymaps

Si un message d'avertissement s'affiche, allez lire cet article 😉 !


Prise en main de prettymaps#

Une simple adresse suffit#

icône cadeau carto

C'est l'un des éléments qui a rendu prettymaps aussi populaire : la simplicité d'utilisation. On sent que l'auteur a fait des efforts pour nous rendre la vie facile, du moins au début :

  • une adresse suffit ; à noter qu'on peut aussi passer une paire de coordonnées bien sûr ou encore un objet GeoDataFrame.boundary,
  • la bibliothèque propose une série de préréglages (preset) pour les paramètres de symbologie.

On peut donc entamer notre script de la manière suivante :

tuto_prettymaps.py
# import des bibliothèques utilisées dans le script
import prettymaps

# adresse
adresse = "13 rue de l'Université, Paris, France"

# génération de la carte et sauvegarde sous forme d'image
plot: prettymaps.draw.Plot = prettymaps.plot(
    query=adresse,
    save_as="sciencespo_paris.png"
)

Il suffit ensuite d'exécuter le script :

python tuto_prettymaps.py

Et voici le fichier sciencespo_paris.png :

prettymaps - Sciences Po Paris

Jouer avec les préréglages intégrés#

Si le rendu par défaut est déjà sympa, la richesse de prettymaps se trouve dans sa capacité à personnaliser les styles des différents objets issus d'OpenStreetMap. L'auteur a intégré dans la bibliothèque des préréglages de styles (preset) que l'on peut obtenir avec une simple commande :

>>> import prettymaps
>>> presets = prettymaps.presets()
>>> print(presets['preset'].to_string(index=False))
        barcelona
barcelona-plotter
          cb-bf-f
          default
    heerhugowaard
            macao
          minimal
           tijuca

On peut donc améliorer notre script pour itérer sur les différents styles disponibles et au passage ajouter un peu de sucre de façon à gérer les éventuelles erreurs et à générer un nom de fichier dynamiquement :

tuto_prettymaps.py
# -- Globals
presets = (
    "barcelona",
    "barcelona-plotter",
    "cb-bf-f",
    "default",
    "heerhugowaard",
    "macao",
    "minimal",
    "tijuca",
)

for p in presets:
    print(f"Carte de '{adresse}' avec le préréglage '{p}'")
    try:
        plot: prettymaps.draw.Plot = prettymaps.plot(
            query=adresse,
            preset=p,
            save_as=f"{''.join(e for e in adresse if e.isalnum())}_{p}.png",
        )
    except Exception as err:
        logging.error(
            f"La génération de la carte de '{adresse}' avec le préréglage '{p}' a échoué."
            f" Trace : {err}"
        )
        continue

On exécute de nouveau le script et voilà les 7 résultats (le style barcelona-plotter génère une erreur chez moi) :

prettymaps - Ville mystère preset barcelona prettymaps - Ville mystère preset cb-bf-f prettymaps - Ville mystère preset default prettymaps - Ville mystère preset heerhugowaard prettymaps - Ville mystère preset macao prettymaps - Ville mystère preset minimal prettymaps - Ville mystère preset tijuca

GeoGuessr

Saurez-vous identifier l'adresse que j'ai donnée pour générer les images ci-dessus ?
Réponse en commentaire. Vous avez environ 1 an pour donner la réponse 😉.

Let's script again : jouer avec les paramètres#

logo OpenStreetMap Python

Maintenant qu'on a bien joué avec les préréglages intégrés, creusons un peu plus loin car prettymaps permet de paramétrer plutôt finement la façon dont les objets OpenStreetMap sont stylisés ainsi que comment la figure (au sens de Matplotlib) est construite :

  • layers permet de spécifier les objets à récupérer depuis OpenStreetMap, en fait les requêtes à l'API Overpass,
  • style permet de régler le mode de représentation des objets dans Maplotlib : la couleur de fond (fc), de bordure (ec), la largeur de celle-ci (lw), le motif (hatch), etc.

Prenons un lieu qui se prête bien à l'exercice : Saint-Malo. Plus exactement le bassin Jacques Cartier car il y a de la vieille ville, de l'eau, de la plage, des bâtiments, des routes... bref, de la diversité !

🎄 Vu que Noël approche, essayons d'utiliser les couleurs associées : vert pomme, vert sapin, jaune dorée, orange rouge, rouge et blanc. Pour faciliter la lisibilité du script, stockons les paramètres de style dans un fichier JSON à part, que je replie ici pour vous éviter de scroller de trop.

Fichier de style personnalisé Noël
preset_christmas.json
{
    "layers": {
        "perimeter": {},
        "streets": {
            "width": {
                "motorway": 5,
                "trunk": 5,
                "primary": 4.5,
                "secondary": 4,
                "tertiary": 3.5,
                "cycleway": 3.5,
                "residential": 3,
                "service": 2,
                "unclassified": 2,
                "pedestrian": 2,
                "footway": 1
            }
        },
        "building": {
            "tags": {
                "building": true,
                "landuse": "construction"
            }
        },
        "water": {
            "tags": {
                "natural": [
                    "water",
                    "bay"
                ]
            }
        },
        "forest": {
            "tags": {
                "landuse": "forest"
            }
        },
        "green": {
            "tags": {
                "landuse": [
                    "grass",
                    "orchard"
                ],
                "natural": [
                    "island",
                    "wood"
                ],
                "leisure": "park"
            }
        },
        "beach": {
            "tags": {
                "natural": "beach"
            }
        },
        "parking": {
            "tags": {
                "amenity": "parking",
                "highway": "pedestrian",
                "man_made": "pier"
            }
        }
    },
    "style": {
        "perimeter": {
            "fill": true,
            "lw": 0,
            "hatch": "o....",
            "zorder": 0
        },
        "background": {
            "fc": "#FFFFFF",
            "hatch": "....*",
            "hatch_c": "#C0C0C0",
            "lw": 1,
            "zorder": -1
        },
        "green": {
            "fc": "#008000",
            "ec": "#2F3737",
            "lw": 1,
            "zorder": 1
        },
        "forest": {
            "fc": "#06470C",
            "ec": "#2F3737",
            "lw": 1,
            "zorder": 2
        },
        "water": {
            "fc": "#4C9A2A",
            "ec": "#2F3737",
            "lw": 1,
            "zorder": 3
        },
        "beach": {
            "fc": "#FFD700",
            "ec": "#2F3737",
            "lw": 1,
            "zorder": 3
        },
        "parking": {
            "fc": "#FFFFFF",
            "ec": "#2F3737",
            "lw": 1,
            "zorder": 3
        },
        "streets": {
            "fc": "#FF0000",
            "ec": "#800000",
            "alpha": 1,
            "lw": 0,
            "zorder": 4
        },
        "building": {
            "palette": [
                "#FF0000",
                "#ea4630",
                "#f8b229"
            ],
            "ec": "#2F3737",
            "lw": 0.5,
            "zorder": 5
        }
    },
    "circle": true,
    "radius": 1000,
    "dilate": 100
}

On ajoute alors le chargement du fichier JSON à notre script :

tuto_prettymaps.py
import json
from pathlib import Path

import prettymaps

# charge les préréglages depuis un JSON
preset_christmas_file = Path(__file__).parent.joinpath("preset_christmas.json")
with preset_christmas_file.open(mode="r", encoding="UTF-8") as file:
    christmas_preset = json.load(file)

# enregistre le préréglage
prettymaps.create_preset("christmas", **christmas_preset)

# adresse (on peut aussi passer une paire de coordonnées)
adresse = "Saint-Malo, France"

# génération de la carte
plot: prettymaps.draw.Plot = prettymaps.plot(
    query=adresse,
    preset="christmas",
)

Bon, c'est pas forcément une grande réussite ce projet de style de Noël mais disons que c'est une première ébauche 😅.

prettymaps - Saint-Malo - Style personnalisé Noël


prettymapp : l'alternative web optimisée#

icône souris clic gauche

Bon, ok, j'aurais pu vous en parler plus tôt, mais si j'avais commencé par là, vous n'auriez pas mis les mains dans le cambouis, ni ressenti ce soulagement à l'idée de pouvoir cliquer sur une interface web pour faire les réglages de style 😄.

L'énorme succès de prettymaps a inspiré de nombreux dérivés, certains comme le méprisable Aeterna Civitas allant à l'encontre du souhait de l'auteur, le poussant à ne plus publier ses outils en open source... Et d'autres, plus heureux, comme prettymapp (oui sans s mais avec 2 p), le projet de Christoph Rieke qui facilite l'utilisation en proposant une interface graphique pour les principaux paramètres, le tout dans une application web dont l'instance de démo est publique :

🖼 Utiliser prettymapp

prettymapp - démo

Utiliser prettymapp en Python#

À l'instar de son projet parent, prettymapp est d'abord un package Python qu'il est donc possible d'utiliser dans un script pour personnaliser son usage au besoin. Voici un rapide exemple :

tuto_prettymapp.py
# import des bibliothèques utilisées dans le script
from prettymapp.geo import get_aoi
from prettymapp.osm import get_osm_geometries
from prettymapp.plotting import Plot
from prettymapp.settings import STYLES

# variables
adresse = 50.98682, 2.12736
style_name = "PEACH"

# récupère le polygone (rectangle ou rond) dans un rayon en mètres autour des coordonnées transmises
aoi = get_aoi(coordinates=adresse, radius=600, rectangular=False)

# récupérer les objets OSM pour les stocker dans un GeoDataFrame (un objet GeoPandas)
df = get_osm_geometries(aoi=aoi)

# génération de la carte
fig = Plot(
    df=df,
    aoi_bounds=aoi.bounds,
    draw_settings=STYLES[style_name.title()],
    name_on=True,
    name="Fort de Gravelines",
    text_x=-35,
    text_y=40,
    text_rotation=-25,
).plot_all()

# sauvegarde du fichier de sortie
fig.savefig(
    "Fort-de-Gravelines_France_prettymapp.png",
    metadata={"Author": "Geotribu", "Software": "prettymapp"},
)

Voilà le rendu :

prettymapp - Fort de Gravelines

Bien sûr, il est aussi possible de personnaliser le style des objets et de la carte. Le plus simple étant probablement d'utiliser l'interface web pour faire les premiers réglages avant de l'exporter pour l'affiner.


Conclusion#

Voilà une présentation finalement assez rapide de prettymaps et de prettymapp, son principal dérivé, qui, je l'espère, vous aura donné envie de l'utiliser si ça n'est pas déjà fait.

Si jamais vous vous lancez, partagez donc vos styles ici en commentaire, sur le reddit ou sur Mapstodon 😉.

Ah j'oubliais. J'ai fait pas mal d'essais avec les 2 bibliothèques que j'ai stockés en vrac dans un projet GitHub :

Consulter le projet GitHub des exemples


Auteur·ice#

Julien MOURA#

Portrait Julien Moura

Géographe "sigiste" de formation, j'ai travaillé sur différentes thématiques et types de structures : gestion des déchets en milieu urbain à Madagascar, foncier d'intérêt général auprès de l'EPF de La Réunion, organisation et la résilience urbaine face aux risques naturels à Lima pour l'IRD, gouvernance et ouverture des données à Isogeo.

Je travaille désormais à Oslandia.
Féru des dynamiques de contributions, je participe activement à Geotribu depuis fin 2011.

Licence Beerware #

Ce contenu est sous licence Beerware (Révision 42).
Les médias d'illustration sont potentiellement soumis à d'autres conditions d'utilisation.

Réutiliser, citer l'article

Tant que vous conservez cette licence :

  • vous pouvez faire ce que vous voulez de ce contenu
  • si vous rencontrez l'auteur/e un jour et que vous pensez que ce contenu vaut le coup, vous pouvez lui payer un coup en retour

Citer cet article :

"prettymaps, des jolies cartes sans SIG" publié par Julien MOURA sur Geotribu - Source : https://geotribu.fr/articles/2023/2023-12-05_prettymaps-jolies-cartes-avec-openstreetmap-python-pandas-matplotlib/

Commentaires

Afin de favoriser les échanges constructifs, merci de préférer le pseudonymat à l'anonymat. Pour rappel, l'adresse mail n'est pas exposée publiquement et sert principalement aux notifications de réponse. Les commentaires sont automatiquement republiés sur nos réseaux sociaux pour favoriser la discussion. Consulter la page sur la confidentialité et les données personnelles.
Une version minimale de la syntaxe markdown est acceptée pour la mise en forme des commentaires.
Propulsé par Isso.

Ce contenu est sous licence Beerware Pictogramme BeerWare