# How to Integrate GPX/KML Tracks with prettymaps Using the `gpx` Argument

> Easily integrate GPX/KML tracks into prettymaps. Learn how to use the gpx argument to overlay tracks or frame maps automatically for stunning visualizations.

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

---

**You can overlay GPX or KML tracks on prettymaps visualizations by passing a file path or list of paths to the `gpx` argument, or use a track file as the map query itself for automatic framing.**

The `marceloprates/prettymaps` library provides native support for integrating GPS track data into aesthetic OSM-based maps. This feature, implemented across [`prettymaps/gpx.py`](https://github.com/marceloprates/prettymaps/blob/main/prettymaps/gpx.py) and [`prettymaps/draw.py`](https://github.com/marceloprates/prettymaps/blob/main/prettymaps/draw.py), lets you visualize running routes, cycling tracks, or hiking paths alongside other map layers without preprocessing external tools.

## How prettymaps Parses GPX and KML Files

The parsing pipeline in [`prettymaps/gpx.py`](https://github.com/marceloprates/prettymaps/blob/main/prettymaps/gpx.py) handles both GPX (1.0/1.1) and KML formats through XML namespace-agnostic parsing.

### Core Parsing Functions

The private helper `_localname` strips XML namespaces, enabling robust parsing regardless of schema version. Three main functions extract geometries:

- **`_lines_from_gpx`** – Walks `<trkseg>` and `<rte>` elements, extracting `(lon, lat)` coordinate pairs into `LineString` objects
- **`_lines_from_kml`** – Parses `<coordinates>` strings from `<LineString>` elements, handling the `lon,lat[,alt]` format
- **`read_track`** – Public entry point that accepts a single path, list, or tuple and returns a unified `MultiLineString`

```python

# Simplified flow from prettymaps/gpx.py

if isinstance(source, (list, tuple)):
    # Recursively read each file and concatenate geometries

else:
    root = ET.parse(source).getroot()
    if _localname(root.tag) == "kml":
        lines = _lines_from_kml(root)
    elif _localname(root.tag) == "gpx":
        lines = _lines_from_gpx(root)
    else:
        lines = _lines_from_gpx(root) or _lines_from_kml(root)

```

### Geographic Utilities

Two helper functions prepare tracks for map integration:

- **`track_center`** – Computes the geographic centroid of the track geometry
- **`track_radius`** – Calculates a suitable map radius from the bounding box (minimum 250 meters)

These enable **auto-framing**: when you pass a GPX/KML file as the main query, prettymaps automatically centers and zooms to fit the track.

## How the `gpx` Argument Works in `plot()`

The integration logic resides in [`prettymaps/draw.py`](https://github.com/marceloprates/prettymaps/blob/main/prettymaps/draw.py). When you call `prettymaps.plot()`, the function processes GPX tracks through five steps:

### 1. Detect the GPX/KML Source

```python
gpx_source = gpx if gpx is not None else (query if is_track_file(query) else None)

```

The `gpx` argument takes precedence. If omitted but `query` is a recognizable track file (`.gpx`, `.kml`, `.kmz`), that becomes the source.

### 2. Read and Validate

```python
track_geom = read_track(gpx_source)

```

Returns `None` if parsing fails, otherwise a `MultiLineString`.

### 3. Auto-Frame When Query Is a Track

If `query` is a track file and `radius` is not explicitly set:

- `track_center` becomes the new query (a `(lat, lon)` tuple)
- `track_radius` determines the zoom level

### 4. Inject as a Map Layer

```python
if track_geom is not None:
    gdfs["gpx"] = gp.GeoDataFrame(geometry=[track_geom], crs="EPSG:4326")
    layers.setdefault("gpx", {})
    style.setdefault("gpx", {**GPX_STYLE, **(gpx_style or {})})

```

The track enters the same pipeline as OSM-data layers—subject to translation, scaling, and rotation.

### 5. Render with `draw_layers`

The default style (`GPX_STYLE`) applies unless overridden.

## Customizing GPX/KML Track Appearance

The default visual style is defined in [`prettymaps/draw.py`](https://github.com/marceloprates/prettymaps/blob/main/prettymaps/draw.py):

```python
GPX_STYLE = {"ec": "#EB4034", "lw": 3, "zorder": 6}

```

| Property | Value | Meaning |
|----------|-------|---------|
| `ec` | `"#EB4034"` | Edge color (red) |
| `lw` | `3` | Line width in points |
| `zorder` | `6` | Draw on top of most layers |

Override with the `gpx_style` argument. Keys merge with `GPX_STYLE`, so unspecified values keep defaults:

```python
prettymaps.plot(
    query="Porto Alegre",
    gpx="samples/track.gpx",
    gpx_style={"ec": "#00AAFF", "lw": 4}  # Blue, thicker line

)

```

## Practical Code Examples for Integrating GPX/KML Tracks

### Use a Track File as the Query (Auto-Framing)

```python
import prettymaps

# prettymaps auto-detects the format, centers the map, and sets radius

prettymaps.plot("samples/track.gpx")

```

### Overlay a Track on a Named Location

```python
prettymaps.plot(
    query="Porto Alegre",
    gpx="samples/track.gpx",
    gpx_style={"ec": "#00AAFF", "lw": 4},
    show=False,
    save_as="porto_map.png"
)

```

### Multiple Track Files

```python
prettymaps.plot(
    query="Berlin",
    gpx=["track1.gpx", "track2.kml"],  # Mixed formats supported

    show=True
)

```

### Access Track Geometry for Post-Processing

```python
result = prettymaps.plot("track.gpx", show=False)
gpx_geom = result.geodataframes["gpx"].geometry.iloc[0]  # Shapely MultiLineString

```

## Source File Reference

| File | Purpose | Key Exports |
|------|---------|-------------|
| [`prettymaps/gpx.py`](https://github.com/marceloprates/prettymaps/blob/main/prettymaps/gpx.py) | Track parsing and geometry utilities | `read_track`, `track_center`, `track_radius` |
| [`prettymaps/draw.py`](https://github.com/marceloprates/prettymaps/blob/main/prettymaps/draw.py) | Plot orchestration and styling | `plot`, `GPX_STYLE` |
| [`tests/test_gpx.py`](https://github.com/marceloprates/prettymaps/blob/main/tests/test_gpx.py) | Validation suite | Examples of auto-framing and overlay behavior |

## Summary

- **Pass a GPX/KML path to `gpx`** to overlay tracks on any map query
- **Use a track file as `query`** for automatic centering and zoom
- **Multiple files** are supported via list or tuple input
- **Style customization** merges with `GPX_STYLE` through the `gpx_style` argument
- **Track geometry** is available in the returned result's `geodataframes["gpx"]` for further analysis

## Frequently Asked Questions

### Can prettymaps handle KML files the same way as GPX?

Yes. The `read_track` function in [`prettymaps/gpx.py`](https://github.com/marceloprates/prettymaps/blob/main/prettymaps/gpx.py) auto-detects format by checking the root XML tag. KML files with `<LineString>` elements parse correctly, and you can mix GPX and KML files in the same `gpx` list argument.

### What happens if my track file has no valid geometry?

`read_track` returns `None`, and `prettymaps.plot()` skips GPX layer injection without raising an error. The map renders normally with other layers. Check `result.geodataframes` for the presence of a `"gpx"` key to confirm successful parsing.

### How do I make the track line thicker or change its color?

Pass a dictionary to `gpx_style` with Matplotlib-compatible properties. The default `{"ec": "#EB4034", "lw": 3}` uses edge color and line width; any keys you provide override these defaults while preserving unspecified values.

### Can I use a GPX track to define the map boundaries without showing the line?

Not directly through the public API. The track layer always renders if successfully parsed. To hide it, you would need to set `lw: 0` and `fc: "none"` in `gpx_style`, or modify the `gdfs["gpx"]` entry after calling `plot()` with `show=False`.