# Understanding Layers and Style Parameters in the Prettymaps `plot()` Function

> Master Prettymaps plot function layers and style parameters. Fetch and render OpenStreetMap data with Matplotlib and vsketch for stunning visualizations.

- Repository: [Marcelo de Oliveira Rosa Prates/prettymaps](https://github.com/marceloprates/prettymaps)
- Tags: deep-dive
- Published: 2026-08-20

---

**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`](https://github.com/marceloprates/prettymaps/blob/main/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`](https://github.com/marceloprates/prettymaps/blob/main/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 lamps
- **`line_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/`.

```python
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`](https://github.com/marceloprates/prettymaps/blob/main/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

```python
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

```python
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

```python
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`](https://github.com/marceloprates/prettymaps/blob/main/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 dilation
- **`plot_gdf()`** — Render a single GeoDataFrame with custom styling
- **`gdf_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

- **`layers`** controls **what** gets fetched and how geometries are processed (width, point_size, line_width)
- **`style`** controls **how** each layer appears using Matplotlib or vsketch properties (ec, fc, lw, hatch, alpha)
- **`manage_presets()`** enables reusable layer+style configurations from JSON files
- **`override_args()`** propagates global `circle` and `dilate` settings to every layer automatically
- The rendering pipeline in [`prettymaps/draw.py`](https://github.com/marceloprates/prettymaps/blob/main/prettymaps/draw.py) separates 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.