Understanding Layers and Style Parameters in the Prettymaps `plot()` Function
The Prettymaps plot() function uses two dictionaries—layers to define what OpenStreetMap features are fetched and style to control how each feature is rendered with Matplotlib or vsketch parameters.
The marceloprates/prettymaps library transforms geographic queries into artistic, publication-ready maps through a declarative rendering pipeline. Central to this pipeline is the plot() function in prettymaps/draw.py, which orchestrates data fetching, geometry conversion, and final rendering. Understanding how its layers and style parameters interact unlocks the full customization potential of the library.
How the layers Dictionary Works
The layers parameter is defined at lines 107-110 in prettymaps/draw.py. Each key represents an OSM feature type, and each value is a sub-dictionary of fetch-time parameters.
Common Layer Parameters
Common parameters include:
width— Controls street-width dilation for network layers (streets, railway, waterway)point_size— Size for point geometries like trees or street lampsline_width— Width for raw line geometries
These parameters are consumed during geometry conversion in gdf_to_shapely() (lines 260-289), which delegates to graph_to_shapely() for network layers or geometries_to_shapely() for point/line/polygon layers.
How the style Dictionary Works
The style parameter mirrors the layers keys and contains rendering arguments, defined at lines 111-114. Styling values are passed directly to Matplotlib's PolygonPatch (lines 311-382) or vsketch (lines 403-425) depending on the mode parameter.
Matplotlib Style Properties
| Property | Description | Example |
|---|---|---|
ec |
Edge color | "#222222" |
fc |
Face color (fill) | "#dddddd" |
lw |
Line width | 2.0 |
hatch |
Hatch pattern | "///" |
alpha |
Opacity | 0.7 |
If a layer appears in layers but has no style entry, default styling is applied—including random colors when a palette is supplied.
The Rendering Pipeline: Step by Step
The plot() function processes layers and style through several distinct phases:
1. Preset Merging with manage_presets()
At lines 108-116, manage_presets() merges a preset file with your supplied dictionaries. This enables reusable configurations stored in prettymaps/presets/.
pm.plot("Paris, France", preset="minimal") # Loads presets/minimal.json
2. Global Argument Override with override_args()
At lines 145-168, override_args() injects circle and dilate into each layer's parameter dictionary when not already present. This applies uniform clipping or dilation without manual per-layer edits.
3. Data Fetching with get_gdfs()
At lines 214-218, get_gdfs() (implemented in prettymaps/fetch.py) collects OSM GeoDataFrames for every layer key.
4. Layer Drawing with draw_layers()
At lines 224-250, draw_layers() iterates over fetched data, calling plot_gdf() for any layer present in layers or style.
Practical Code Examples
Basic Custom Colors
import prettymaps as pm
layers = {
"streets": {"width": 2.0},
"waterway": {"width": 1.5},
}
style = {
"streets": {"ec": "#222222", "fc": "#dddddd"},
"waterway": {"ec": "#2e86ab", "fc": "#b0e0e6"},
}
pm.plot("Cambridge, MA", layers=layers, style=style)
The layers dict supplies numeric width values for geometry dilation; style supplies Matplotlib-compatible edge and face colors.
Circular Mask with Global Overrides
layers = {"streets": {}}
style = {"streets": {"ec": "#111", "fc": "#fff"}}
pm.plot(
"Berlin, Germany",
layers=layers,
style=style,
circle=True, # Clipped to circle
dilate=0.2, # 20% radius expansion
radius=5000, # Meters
)
Here circle and dilate are automatically propagated to each layer by override_args() before fetching begins.
Preset Extension with Custom GPX Track
layers = {"gpx": {}} # Special layer for GPS tracks
style = {"gpx": {"ec": "#eb4034", "lw": 4}} # Overrides GPX_STYLE default
pm.plot(
query="trail.gpx",
layers=layers,
style=style,
preset="default",
save_preset="my_trip"
)
GPX handling uses helpers from prettymaps/gpx.py: read_track(), track_center(), and track_radius(). The track is injected after main OSM fetching at lines 220-226.
Advanced: Bypassing plot() for Custom Pipelines
Because plot() is a thin orchestrator, you can call lower-level functions directly:
graph_to_shapely()— Convert OSMnx graph to shapely with width dilationplot_gdf()— Render a single GeoDataFrame with custom stylinggdf_to_shapely()— Geometry conversion with per-layer parameters
This enables pre-processing, filtering, or multi-pass rendering workflows not supported by the high-level API.
Summary
layerscontrols what gets fetched and how geometries are processed (width, point_size, line_width)stylecontrols how each layer appears using Matplotlib or vsketch properties (ec, fc, lw, hatch, alpha)manage_presets()enables reusable layer+style configurations from JSON filesoverride_args()propagates globalcircleanddilatesettings to every layer automatically- The rendering pipeline in
prettymaps/draw.pyseparates data fetching (lines 214-218), geometry conversion (lines 260-289), and final drawing (lines 311-382 for Matplotlib, lines 403-425 for vsketch) - For custom workflows, call
graph_to_shapely(),plot_gdf(), and other helpers directly
Frequently Asked Questions
What happens if I define a layer in layers but not in style?
The layer is fetched and drawn with default styling. If a color palette is provided, random colors are assigned automatically. Omitting a layer from style does not prevent rendering—it simply falls back to internal defaults.
Can I use the same style dictionary for multiple layers?
Yes, but each layer requires its own key in the style dictionary. To apply identical styling, copy the dictionary or use dictionary unpacking: style={"streets": base_style, "railway": base_style}.
How does the circle parameter interact with individual layer widths?
The circle parameter triggers a circular clip mask applied after geometry conversion. The width parameter in layers controls street dilation during the graph_to_shapely() conversion phase— these operations are independent and compose naturally.
What's the difference between width in layers and lw in style?
width (in layers) controls geometric dilation at fetch time—how many meters wide a street is rendered as a polygon. lw or linewidth (in style) controls the visual stroke width in the final image—purely a display property that does not affect geometry.
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 →