Skip to content

prettymaps Tutorial

A minimal Python library to draw customized maps from OpenStreetMap created using the osmnx, matplotlib, shapely and vsketch packages.

Heerhugowaard sample

This tutorial is generated from notebooks/tutorial.py, a marimo notebook. To run it interactively:

uv run --with marimo marimo edit notebooks/tutorial.py

Or with the locally installed copy:

.venv/bin/marimo edit notebooks/tutorial.py

Installation

Install locally

pip install prettymaps

Install on Google Colaboratory

!pip install -e "git+https://github.com/marceloprates/prettymaps#egg=prettymaps"

Then restart the runtime (Runtime -> Restart Runtime) before importing prettymaps.

Run front-end

After prettymaps is installed, you can run the front-end (streamlit) application from the prettymaps repository using:

streamlit run app.py

Plotting

Plotting with prettymaps is very simple. Run:

prettymaps.plot(your_query)

your_query can be:

  1. An address (Example: "Porto Alegre"),
  2. Latitude / Longitude coordinates (Example: (-30.0324999, -51.2303767)),
  3. A custom boundary in GeoDataFrame format.

Default preset

import prettymaps

plot = prettymaps.plot('Stad van de Zon, Heerhugowaard, Netherlands')

Heerhugowaard, default preset

Presets

You can also choose from different "presets" (parameter combinations saved in JSON files). See below an example using the "minimal" preset:

plot = prettymaps.plot(
    'Stad van de Zon, Heerhugowaard, Netherlands',
    preset='minimal',
)

Heerhugowaard, minimal preset

Run prettymaps.presets() to list all available presets. To inspect a specific preset, run prettymaps.preset('default').

Customizing parameters

Instead of using the default configuration you can customize several parameters. The most important are:

  • layers — A dictionary of OpenStreetMap layers to fetch.
  • Keys: layer names (arbitrary)
  • Values: dicts representing OpenStreetMap queries
  • style — Matplotlib style parameters
  • Keys: layer names (the same as before)
  • Values: dicts representing Matplotlib style parameters
plot = prettymaps.plot(
    your_query,
    layers,
    style,
    preset,
    save_preset,
    update_preset,
    circle,
    radius,
    dilate,
)

plot is a Python dataclass containing:

@dataclass
class Plot:
    geodataframes: Dict[str, gp.GeoDataFrame]
    fig: matplotlib.figure.Figure
    ax: matplotlib.axes.Axes

Here's an example of running prettymaps.plot() with customized parameters (Macau):

plot = prettymaps.plot(
    'Praça Ferreira do Amaral, Macau',
    circle=True,
    radius=1100,
    layers={
        "green": {
            "tags": {
                "landuse": "grass",
                "natural": ["island", "wood"],
                "leisure": "park",
            }
        },
        "forest": {"tags": {"landuse": "forest"}},
        "water": {"tags": {"natural": ["water", "bay"]}},
        "parking": {
            "tags": {
                "amenity": "parking",
                "highway": "pedestrian",
                "man_made": "pier",
            }
        },
        "streets": {
            "width": {
                "motorway": 5, "trunk": 5, "primary": 4.5,
                "secondary": 4, "tertiary": 3.5, "residential": 3,
            }
        },
        "building": {"tags": {"building": True}},
    },
    style={
        "background": {"fc": "#F2F4CB", "ec": "#dadbc1", "hatch": "ooo..."},
        "perimeter": {"fc": "#F2F4CB", "ec": "#dadbc1", "lw": 0, "hatch": "ooo..."},
        "green": {"fc": "#D0F1BF", "ec": "#2F3737", "lw": 1},
        "forest": {"fc": "#64B96A", "ec": "#2F3737", "lw": 1},
        "water": {
            "fc": "#a1e3ff", "ec": "#2F3737",
            "hatch": "ooo...", "hatch_c": "#85c9e6", "lw": 1,
        },
        "parking": {"fc": "#F2F4CB", "ec": "#2F3737", "lw": 1},
        "streets": {"fc": "#2F3737", "ec": "#475657", "alpha": 1, "lw": 0},
        "building": {
            "palette": ["#FFC857", "#E9724C", "#C5283D"],
            "ec": "#2F3737", "lw": 0.5,
        },
    },
)

Macau, custom parameters

Plot an entire region

To plot an entire region (not just a rectangular or circular area), set radius=False:

plot = prettymaps.plot('Bom Fim, Porto Alegre, Brasil', radius=False)

Bom Fim, Porto Alegre

Access GeoDataFrames directly

You can access a layer's GeoDataFrame directly:

plot = prettymaps.plot('Centro Histórico, Porto Alegre', show=False)
plot.geodataframes['building']

Search by name

Search a building by name and display it:

plot.geodataframes['building'][
    plot.geodataframes['building'].name
    == 'Catedral Metropolitana Nossa Senhora Mãe de Deus'
].geometry[0]

Mosaic of building footprints

import numpy as np
import osmnx as ox
from matplotlib import pyplot as plt

plot = prettymaps.plot('Porto Alegre', show=False)
buildings = plot.geodataframes['building']
buildings = ox.projection.project_gdf(buildings)
buildings = [b for b in buildings.geometry if b.area > 0]

n = 6
fig, axes = plt.subplots(n, n, figsize=(7, 6))
fig.patch.set_facecolor('#5cc0eb')
fig.suptitle('Buildings of Porto Alegre', size=25, color='#fff')
for ax, building in zip(np.concatenate(axes), buildings):
    ax.plot(*building.exterior.xy, c='#ffffff')
    ax.autoscale(); ax.axis('off'); ax.axis('equal')

Buildings of Porto Alegre mosaic

Customizing the matplotlib axes

Access plot.ax or plot.fig to add new elements to the matplotlib plot:

plot = prettymaps.plot(
    (41.39491, 2.17557),
    preset='barcelona',
    show=False,
)

plot.fig.patch.set_facecolor('#F2F4CB')
plot.ax.set_title('Barcelona', font='serif', size=50)

Plotter mode

Use plotter mode to export a pen plotter-compatible SVG (thanks to abey79's amazing vsketch library):

plot = prettymaps.plot(
    (41.39491, 2.17557),
    mode='plotter',
    layers=dict(perimeter={}),
    preset='barcelona-plotter',
    scale_x=0.6,
    scale_y=-0.6,
)

Barcelona plotter

Other examples

plot = prettymaps.plot(
    'Barra da Tijuca',
    dilate=0,
    figsize=(22, 10),
    preset='tijuca',
    adjust_aspect_ratio=False,
)

Barra da Tijuca, tijuca preset

Create a preset

Use prettymaps.create_preset() to create a preset:

prettymaps.create_preset(
    "my-preset",
    layers={
        "building": {
            "tags": {"building": True, "leisure": ["track", "pitch"]},
        },
        "streets": {
            "width": {
                "trunk": 6, "primary": 6, "secondary": 5,
                "tertiary": 4, "residential": 3.5,
                "pedestrian": 3, "footway": 3, "path": 3,
            }
        },
    },
    style={
        "perimeter": {"fill": False, "lw": 0, "zorder": 0},
        "streets": {"fc": "#F1E6D0", "ec": "#2F3737", "lw": 1.5, "zorder": 3},
        "building": {"palette": ["#fff"], "ec": "#2F3737", "lw": 1, "zorder": 4},
    },
)

prettymaps.preset('my-preset')

Multiplot

Use prettymaps.multiplot and prettymaps.Subplot to draw multiple regions on the same canvas:

plot = prettymaps.multiplot(
    prettymaps.Subplot(
        'Cidade Baixa, Porto Alegre',
        style={'building': {'palette': ['#49392C', '#E1F2FE', '#98D2EB']}},
    ),
    prettymaps.Subplot(
        'Bom Fim, Porto Alegre',
        style={'building': {'palette': ['#BA2D0B', '#D5F2E3', '#73BA9B', '#F79D5C']}},
    ),
    prettymaps.Subplot(
        'Farroupilha, Porto Alegre',
        layers={'building': {'tags': {'building': True}}},
        style={'building': {'palette': ['#EEE4E1', '#E7D8C9', '#E6BEAE']}},
    ),
    preset='cb-bf-f',
    figsize=(12, 12),
)

Porto Alegre multiplot

Add hillshade

plot = prettymaps.plot(
    'Honolulu',
    radius=5500,
    figsize='a4',
    layers={
        'hillshade': {
            'azdeg': 315,
            'altdeg': 45,
            'vert_exag': 1,
            'dx': 1,
            'dy': 1,
            'alpha': 0.75,
        },
    },
)

Honolulu hillshade

Add keypoints

plot = prettymaps.plot(
    'Garopaba',
    radius=5000,
    figsize='a4',
    layers={'building': False},
    keypoints={
        'tags': {'natural': ['beach']},
        'specific': {
            'pedra branca': {'tags': {'natural': ['peak']}},
        },
    },
)

Garopaba keypoints