How to Combine Multiple Maps Using python `multiplot` Function in prettymaps
Use prettymaps.multiplot() to render several geographic regions on a single Matplotlib canvas by passing Subplot objects that each encapsulate a query and its own styling parameters.
The prettymaps open-source library (marceloprates/prettymaps) generates artistic maps from OpenStreetMap data. While plot() produces single-map visualizations, the multiplot() function enables composite layouts—ideal for city comparisons, regional surveys, or thematic collections. This guide explains the internal mechanics and practical implementation based on the actual source code.
Understanding the Multiplot Architecture
The Three Public Entry Points
In prettymaps/__init__.py, the library exposes three key functions:
plot()– Renders a single map to a given axismultiplot()– Orchestrates multiple maps on a shared figureSubplot– A lightweight data container for per-map configuration
The multiplot() implementation resides in prettymaps/draw.py (lines 1270–1320), where it coordinates figure creation, subplot iteration, and final rendering.
How multiplot() Processes Multiple Maps
The function executes a four-stage pipeline, as implemented in the source:
-
Figure initialization – Creates a Matplotlib figure via
plt.figure()and a single master axis withplt.subplot(111) -
Backend selection – Checks for
plotter=Trueinkwargsto toggle between standard Matplotlib rendering and the experimental Plotter API -
Subplot loop – Iterates over each
Subplotinstance, calling the internalplot()function with merged parameters:
plot(
subplot.query,
ax=ax,
multiplot=True,
**override_params(...),
show=False,
)
This loop appears at draw.py lines 1280–1305. The multiplot=True flag suppresses duplicate attribution handling, while override_params() resolves conflicts between global and per-subplot settings.
- Finalization – Hides axis borders with
ax.axis("off")and optionally displays the figure
Creating Subplot Containers
The Subplot Data Class
Defined at draw.py lines 70–84, Subplot is a minimal container storing:
| Attribute | Purpose |
|---|---|
query |
Geographic region string or OSM tag query |
kwargs |
Dictionary of overrides for that specific map |
Instantiation requires no dependencies beyond the class itself:
from prettymaps import Subplot, multiplot
s1 = Subplot(query="New York, USA", kwargs={"load_preset": "default"})
s2 = Subplot(query="Paris, France", kwargs={"load_preset": "minimal"})
multiplot(s1, s2, figsize=(12, 8))
Parameter Override Logic
The override_params() function (invoked within multiplot) implements careful precedence:
- Per-subplot
kwargstake priority over globalmultiplot()arguments - The
load_presetflag receives special protection to prevent accidental override - Style dictionaries, layer configurations, and drawing parameters all merge cleanly
This design allows each map to maintain distinct visual characteristics while sharing the same figure context.
Practical Code Examples
Two-City Comparison
Create a minimalist side-by-side of major cities:
from prettymaps import Subplot, multiplot
ny = Subplot("New York, USA", kwargs={"load_preset": "default"})
tokyo = Subplot("Tokyo, Japan", kwargs={"load_preset": "minimal"})
multiplot(ny, tokyo, figsize=(12, 6))
Custom Styles Per Subplot
Apply individual color schemes and layer configurations:
from prettymaps import Subplot, multiplot
s1 = Subplot(
query="Berlin, Germany",
kwargs={
"load_preset": "default",
"style": {"land": "#e0e0e0", "background": "#ffffff"},
"layers": {"buildings": {"fill": "#ffcc00", "alpha": 0.8}},
},
)
s2 = Subplot(
query="Copenhagen, Denmark",
kwargs={
"load_preset": "minimal",
"style": {"land": "#f5f5f5"},
"layers": {"water": {"fill": "#4a90d9", "alpha": 0.6}},
},
)
multiplot(s1, s2, figsize=(14, 7), credit={"text": "European capitals comparison"})
Three-Map Layout with Varied Complexity
Mix detailed and minimal renderings:
from prettymaps import Subplot, multiplot
s1 = Subplot(
"Sydney, Australia",
kwargs={
"load_preset": "default",
"style": {"land": "#e8f5e9"},
"layers": {
"water": {"fill": "#b3e5fc"},
"buildings": {"fill": "#a1887f"}
},
},
)
s2 = Subplot(
"Rio de Janeiro, Brazil",
kwargs={
"load_preset": "default",
"style": {"land": "#fff3e0"},
"layers": {"vegetation": {"fill": "#c8e6c9"}},
},
)
s3 = Subplot(
"Reykjavik, Iceland",
kwargs={"load_preset": "minimal", "style": {"land": "#eceff1"}},
)
multiplot(s1, s2, s3, figsize=(15, 5), credit={"text": "Global coastal cities"})
Using the Plotter Backend
Enable interactive rendering for web-based workflows:
from prettymaps import Subplot, multiplot
s1 = Subplot("Amsterdam, Netherlands", kwargs={"load_preset": "default"})
s2 = Subplot("Venice, Italy", kwargs={"load_preset": "default"})
multiplot(s1, s2, figsize=(10, 5), plotter=True)
Key Source Files and Their Roles
| File | Function | Relevant Lines |
|---|---|---|
prettymaps/draw.py |
Core implementation of multiplot(), Subplot class, and parameter merging |
70–84 (Subplot), 1280–1305 (multiplot loop) |
prettymaps/__init__.py |
Public API exports | Full module |
prettymaps/presets/*.json |
Styling presets referenced via load_preset |
Preset directory |
tests/test.py |
Validation suite including multiplot smoke tests | Test implementations |
Configuration Options Reference
Global multiplot() Parameters
| Parameter | Type | Effect |
|---|---|---|
figsize |
tuple (width, height) | Dimensions in inches for the Matplotlib figure |
credit |
dict or None | Attribution text configuration; applied once to entire canvas |
plotter |
bool | Switches to experimental Plotter API when True |
Per-Subplot Valid kwargs
Any argument accepted by plot() can be passed through Subplot.kwargs:
load_preset– Name of JSON preset filestyle– Dictionary of color overrideslayers– Layer-specific rendering rulesdpi– Resolution for raster outputbuffer– Geographic expansion around query region
Why the Design Works
Stateless core rendering – The plot() function accepts an external ax parameter and does not maintain global state, enabling safe repeated invocation.
Controlled attribution – The multiplot=True internal flag prevents duplicate copyright notices that would otherwise appear on every sub-render.
Flexible parameter inheritance – The override_params() merge strategy preserves intentional per-subplot customization without exposing complexity to users.
Summary
- Import
Subplotandmultiplotfromprettymapsto compose multiple maps - Each
Subplotrequires a geographicqueryand accepts customkwargsfor styling multiplot()creates a shared Matplotlib figure, iterates through subplots, and applies parameter overrides automatically- Use
load_preset,style, andlayerskeys to differentiate individual maps - Pass
plotter=Truefor interactive Plotter-backend rendering - Control global layout with
figsizeand unified attribution viacredit
Frequently Asked Questions
What's the difference between plot() and multiplot()?
plot() renders a single map to a specified axis and handles its own figure management. multiplot() creates a figure, accepts multiple Subplot objects, and orchestrates their rendering with proper attribution handling and parameter merging. Use plot() for standalone maps; use multiplot() for composites.
Can I mix different presets in one multiplot?
Yes. Each Subplot carries its own kwargs dictionary, including independent load_preset values. The override_params() function in draw.py protects preset loading during parameter merging, ensuring your per-subplot choices persist.
How do I control the layout arrangement of multiple maps?
multiplot() currently uses a single axis (plt.subplot(111)) and overlays maps at different positions. For custom grid arrangements, call plot() directly with manually created axes using plt.subplots() or GridSpec, then omit multiplot() entirely. The multiplot() function prioritizes convenience over granular layout control.
Why might attribution text appear duplicated, and how do I prevent it?
The multiplot=True internal flag suppresses per-subplot credit rendering. This flag is set automatically when multiplot() calls plot(). If using plot() directly for manual composition, pass credit=None to all but the final subplot to avoid duplication.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →