prettymaps: drawing printable maps from OpenStreetMap with Python
Draw pretty maps from OpenStreetMap data! Built with osmnx +matplotlib + shapely
At a glance
- What is it?
- prettymaps is a small Python library that pulls OpenStreetMap features through osmnx and renders them with matplotlib and shapely. It is good for poster-style maps of a named place, and it is not a GIS.
- Who is it for?
- Adopt prettymaps if you want a styled, poster-like map of a place you can name, and you are comfortable with matplotlib and shapely objects. Do not adopt it if you need routing, spatial analysis, or a tile server; it draws figures, it does not answer spatial queries.
- Can I use it commercially?
- Yes, with strict conditions. AGPL-3.0 is a network copyleft licence: if people use a modified version over a network, for example as a hosted service, you must offer them its source code under the same licence.
- Is it still maintained?
- Yes. The repository last received commits 62 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 30, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The problem prettymaps solves: a place name in, a styled figure out
Most mapping libraries make you assemble the pipeline yourself. You fetch vector data, project it, decide which features are water and which are buildings, set a colour for each, and then fight matplotlib's axes. prettymaps collapses that into one call. The README's quick start is a single line: `plot = prettymaps.plot('Stad van de Zon, Heerhugowaard, Netherlands')`. The library geocodes the string, fetches OpenStreetMap features for the area, and returns a rendered figure.
The audience is narrow and specific. It is for people who want a picture of a city, not a map service. The repository topics list cartography, generative-art and matplotlib alongside maps and openstreetmap, and the sample images are poster compositions rather than navigation aids. If your output is going on a wall, into a print, or into a plotter drawing, the defaults are aimed at you. If your output is going into a routing engine or a spatial join, they are not.
One design decision tells you a lot about intent. The README says the printed message on the figures crediting the repository and OpenStreetMap is mandatory by their license, and the library keeps that credit in the figure. That is a choice made for a tool whose output is meant to be looked at.
How prettymaps works: osmnx for data, shapely for geometry, matplotlib for the figure
The stack is stated plainly in the README: osmnx, matplotlib, shapely, and vsketch. osmnx is the piece that talks to OpenStreetMap and returns GeoDataFrames. shapely handles the geometry operations, which is where the boundary shape comes in. matplotlib renders the final figure. vsketch is listed as a dependency and the README points to a Barcelona plotter example, so the pen-plotter path exists, but the README does not document the vsketch workflow in the same detail as the matplotlib one.
The data flow is visible in the return value. `plot` is a dataclass with `geodataframes` (per-layer GeoDataFrames), `fig`, and `ax`. That means the library does not hide the intermediate state from you. You get the raw per-layer frames back, so you can post-process them with shapely or geopandas before or after rendering. The `fig` and `ax` handles mean you can keep working on the matplotlib side, adding annotations, changing the figure size, or saving at a different DPI.
Layers are the unit of control. The `layers` parameter is a dict of OpenStreetMap layers to fetch, and each entry carries `tags`, which is the Overpass-style query for that layer. The style is a parallel dict keyed by the same layer names, holding matplotlib style parameters. Because both are plain dicts, you can add a layer the library does not ship with, as long as you know the tags. This is the part that rewards reading the tutorial: the defaults are a starting point, not a specification.
Installing prettymaps and drawing your first custom map
The README gives two install paths. Locally, it is a plain pip install. Note that setup.py declares `python_requires=">=3.12"`, while the README badge says Python 3.11+, so check your interpreter before you start.
pip install prettymapsOn Google Colaboratory the README uses an editable install from the repository instead, and then tells you to restart the runtime before importing. Skipping the restart is the usual reason an import fails right after installing.
!pip install -e "git+https://github.com/marceloprates/prettymaps#egg=prettymaps"The repository also ships a Streamlit front-end. From a clone of the repository, `streamlit run app.py` starts it, which is the fastest way to see what the layer and style dictionaries do before writing them by hand.
For a first real use, the README's customization example is the one to copy. It draws a circular crop of Macau with two layers, water and buildings, and gives each its own style. The `circle=True` and `radius=1100` arguments replace the default boundary with a circle of that radius, and `dilate` is the related parameter for expanding the boundary.
import prettymaps
plot = prettymaps.plot(
'Praça Ferreira do Amaral, Macau',
circle=True,
radius=1100,
layers={
"water": {"tags": {"natural": ["water", "bay"]}},
"building": {"tags": {"building": True}},
},
style={
"water": {"fc": "#a1e3ff", "ec": "#2F3737"},
"building": {"palette": ["#FFC857", "#E9724C", "#C5283D"]},
},
)What you should see is a circular map with flat blue water and buildings filled from the three-colour palette. The `fc` and `ec` keys are fill and edge colour; `palette` is a list the library draws from. Presets are JSON files shipped with the package (`package_data={"prettymaps": ["presets/*.json"]}` in setup.py) and are selected with the `preset` parameter, for example `'default'`, `'minimal'`, `'macao'`, or `'tijuca'`.
Where prettymaps stops: no routing, no analysis, and a credit line you keep
prettymaps is a rendering layer over osmnx, and the README never claims otherwise. There is no routing, no isochrone, no spatial join API, and no tile server. If you need to know which buildings fall inside a catchment area, you would take the `geodataframes` the plot returns and do that work yourself with geopandas. At that point prettymaps has saved you the fetch and the styling, not the analysis.
The credit line is a real constraint, not a footnote. The README states the printed message crediting the repository and OpenStreetMap is mandatory by their license, and it asks you to keep it. If your use case requires a clean figure with no attribution text, this library is the wrong tool and you should fetch the data yourself. The same section of the README is explicit that the author does not authorize using the project to sell NFTs, and notes that the AeternaCivitas and geoartnft projects used the work without crediting it. That is a stated wish rather than a licence term, and the README says so.
There is also a dependency-weight cost. `requirements.txt` pulls in rasterio, rioxarray, opencv-python-headless, scikit-image, scikit-learn, elevation, streamlit and marimo on top of the core four. The hillshade and keypoints examples explain some of that, but if you only want flat vector maps, you are installing a large tree. The README does not document a slim install extra.
prettymaps versus building the same figure on osmnx directly
The honest alternative is osmnx plus matplotlib, without prettymaps. osmnx is already a dependency here; it does the geocoding, the Overpass fetch, and the GeoDataFrame construction, and it has its own plotting functions. If you go that route you control the projection, the layer queries and the styling from the first line, and you avoid the extra dependencies that prettymaps adds for hillshade and plotting support.
The difference is where the defaults live. With osmnx alone, every aesthetic decision is yours to make, and the result is whatever you build. With prettymaps, the presets and the layer/style dicts encode a set of decisions that already look like a poster: the palette handling, the boundary dilation, the circular crop, the per-layer fill and edge colours. The README's own examples are the evidence, with named presets for Macau, Tijuca and Bom Fim. That is a different kind of value. You are adopting a look, not a data layer.
A second alternative is the Streamlit app, which is part of this repository rather than a competitor. It runs the same library behind a UI, so it is a way to evaluate the presets without writing Python. The README links a hosted instance at prettymaps.streamlit.app. Treat it as a preview of the library's range, not as a separate product.
Maintenance, licence and the cost of upgrading
The last push to the repository was on 2026-07-30, and the most recent release listed is v1.4.2 on 2025-03-03. The repository is not archived. That combination is worth reading carefully: the code is being touched, but the release tags are not moving at the same pace, so a fix you see on `main` may not be in the version pip gives you.
The licence is AGPL-3.0, and setup.py is inconsistent with that, declaring `license="MIT License"`. The README and the LICENSE file are the authoritative pair, and the README describes the terms: you can make commercial use, distribute and modify the project, but must disclose the source code with the licence and copyright notice. The practical consequence is that AGPL-3.0 reaches network use, so if you wrap prettymaps in a hosted service, the disclosure obligation is the thing to think about before you build. This is a description of what the project says, not legal advice.
Upgrade cost is dominated by the dependency floor, not by the library's own API. `requirements.txt` pins minimums rather than exact versions: osmnx>=2.0.5, shapely>=2.0.0, matplotlib>=3.9.0, numpy>=1.26.4, streamlit>=1.60.0, marimo>=0.23.0. Because they are floors, a fresh install months from now can resolve to a very different set of versions than the ones the presets were tuned against. If you care about reproducible output, pin the full tree in your own environment rather than relying on requirements.txt. The README does not document a supported version matrix beyond the Python floor.
Editorial conclusion
Adopt prettymaps if you want a styled, poster-like map of a place you can name, and you are comfortable with matplotlib and shapely objects. Do not adopt it if you need routing, spatial analysis, or a tile server; it draws figures, it does not answer spatial queries. Before you commit, check three things: that your Python is 3.12 or newer, that the printed credit line survives whatever you do with the figure, and that the AGPL-3.0 obligations fit how you plan to distribute the output or the code.
Frequently asked questions
How do I install prettymaps?
The README gives a plain pip install for local use: pip install prettymaps. On Google Colaboratory it uses an editable install from the repository and then asks you to restart the runtime before importing.
What Python version does prettymaps need?
setup.py declares python_requires=">=3.12", while the README badge says Python 3.11+. The two disagree, so check the interpreter you plan to use.
What can I customize in a prettymaps plot?
The README names layers (a dict of OpenStreetMap layers to fetch), style (matplotlib style parameters per layer), preset (a JSON preset such as 'default', 'minimal', 'macao' or 'tijuca'), and the boundary controls circle, radius and dilate.
Does prettymaps return the underlying map data?
Yes. The README states that plot is a dataclass with geodataframes, holding per-layer GeoDataFrames, along with fig and ax.
What licence is prettymaps under?
The README and LICENSE state AGPL-3.0, which allows commercial use, distribution and modification as long as you disclose the source code with the licence and copyright notice. setup.py says "MIT License", which conflicts with those files.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/marceloprates-prettymaps)